PlotSquared/src/main/java/com/intellectualcrafters/jnbt/NBTOutputStream.java

282 lines
9.4 KiB
Java
Raw Normal View History

2014-11-08 20:27:09 +01:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 /
////////////////////////////////////////////////////////////////////////////////////////////////////
2014-10-15 11:43:20 +02:00
package com.intellectualcrafters.jnbt;
import java.io.Closeable;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
/**
2014-12-18 03:15:11 +01:00
* <p> This class writes <strong>NBT</strong>, or <strong>Named Binary Tag</strong> <code>Tag</code> objects to an
2015-03-13 08:05:06 +01:00
* underlying <code>OutputStream</code>. </p> <p> The NBT format was created by Markus Persson, and the
2015-03-13 08:26:08 +01:00
* specification may be found at
* @linktourl http://www.minecraft.net/docs/NBT.txt
* </p>
2014-11-05 04:42:08 +01:00
*
* @author Graham Edgecombe
2014-10-15 11:43:20 +02:00
*/
public final class NBTOutputStream implements Closeable {
2014-10-15 12:23:32 +02:00
/**
* The output stream.
*/
private final DataOutputStream os;
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
2014-12-18 03:15:11 +01:00
* Creates a new <code>NBTOutputStream</code>, which will write data to the specified underlying output stream.
*
* @param os The output stream.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
public NBTOutputStream(final OutputStream os) throws IOException {
2014-10-15 12:23:32 +02:00
this.os = new DataOutputStream(os);
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag to write.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
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);
2014-10-15 12:23:32 +02:00
if (type == NBTConstants.TYPE_END) {
throw new IOException("Named TAG_End not permitted.");
}
writeTagPayload(tag);
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes tag payload.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeTagPayload(final Tag tag) throws IOException {
final int type = NBTUtils.getTypeCode(tag.getClass());
2014-10-15 12:23:32 +02:00
switch (type) {
2014-11-05 04:42:08 +01:00
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 + ".");
2014-10-15 12:23:32 +02:00
}
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Byte</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeByteTagPayload(final ByteTag tag) throws IOException {
this.os.writeByte(tag.getValue());
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Byte_Array</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeByteArrayTagPayload(final ByteArrayTag tag) throws IOException {
final byte[] bytes = tag.getValue();
this.os.writeInt(bytes.length);
this.os.write(bytes);
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Compound</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeCompoundTagPayload(final CompoundTag tag) throws IOException {
for (final Tag childTag : tag.getValue().values()) {
2014-10-15 12:23:32 +02:00
writeTag(childTag);
}
2014-11-05 04:42:08 +01:00
this.os.writeByte((byte) 0); // end tag - better way?
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_List</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeListTagPayload(final ListTag tag) throws IOException {
final Class<? extends Tag> clazz = tag.getType();
final List<Tag> tags = tag.getValue();
final int size = tags.size();
this.os.writeByte(NBTUtils.getTypeCode(clazz));
this.os.writeInt(size);
2014-12-16 06:03:20 +01:00
for (final Tag tag1 : tags) {
2014-11-21 23:45:46 +01:00
writeTagPayload(tag1);
2014-10-15 12:23:32 +02:00
}
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_String</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
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);
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Double</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeDoubleTagPayload(final DoubleTag tag) throws IOException {
this.os.writeDouble(tag.getValue());
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Float</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeFloatTagPayload(final FloatTag tag) throws IOException {
this.os.writeFloat(tag.getValue());
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Long</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeLongTagPayload(final LongTag tag) throws IOException {
this.os.writeLong(tag.getValue());
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Int</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeIntTagPayload(final IntTag tag) throws IOException {
this.os.writeInt(tag.getValue());
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Short</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeShortTagPayload(final ShortTag tag) throws IOException {
this.os.writeShort(tag.getValue());
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-10-15 12:23:32 +02:00
/**
* Writes a <code>TAG_Empty</code> tag.
2014-11-05 04:42:08 +01:00
*
2014-12-18 03:15:11 +01:00
* @param tag The tag.
*
* @throws IOException if an I/O error occurs.
2014-10-15 12:23:32 +02:00
*/
2014-11-05 04:42:08 +01:00
private void writeEndTagPayload(final EndTag tag) {
2014-10-15 12:23:32 +02:00
/* empty */
}
2015-02-23 02:32:27 +01:00
2014-11-05 04:42:08 +01:00
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);
}
2014-10-15 12:23:32 +02:00
}
2015-02-23 02:32:27 +01:00
2014-11-05 04:42:08 +01:00
@Override
2014-10-15 12:23:32 +02:00
public void close() throws IOException {
2014-11-05 04:42:08 +01:00
this.os.close();
2014-10-15 12:23:32 +02:00
}
/**
* Flush output
* @throws IOException
*/
public void flush() throws IOException {
this.os.flush();
}
2014-11-05 04:42:08 +01:00
}