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-10-26 02:05:54 +02:00
|
|
|
* <p>
|
2014-10-15 12:23:32 +02:00
|
|
|
* This class writes <strong>NBT</strong>, or <strong>Named Binary Tag</strong>
|
2014-10-26 02:05:54 +02:00
|
|
|
* <code>Tag</code> objects to an underlying <code>OutputStream</code>.
|
|
|
|
* </p>
|
2014-11-08 20:27:09 +01:00
|
|
|
* <p/>
|
2014-10-26 02:05:54 +02:00
|
|
|
* <p>
|
|
|
|
* The NBT format was created by Markus Persson, and the specification may be
|
2014-10-15 12:23:32 +02:00
|
|
|
* found at <a href="http://www.minecraft.net/docs/NBT.txt">
|
2014-10-26 02:05:54 +02:00
|
|
|
* http://www.minecraft.net/docs/NBT.txt</a>.
|
|
|
|
* </p>
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-10-26 02:05:54 +02: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;
|
|
|
|
|
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Creates a new <code>NBTOutputStream</code>, which will write data to the
|
2014-10-15 12:23:32 +02:00
|
|
|
* specified underlying output stream.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +01:00
|
|
|
* @param os
|
|
|
|
* The output stream.
|
|
|
|
* @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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes a tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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);
|
2014-10-15 12:23:32 +02:00
|
|
|
|
2014-11-05 04:42:08 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes tag payload.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Byte</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Byte_Array</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Compound</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_List</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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();
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-11-05 04:42:08 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_String</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Double</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Float</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Long</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Int</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Short</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-10-15 12:23:32 +02:00
|
|
|
/**
|
2014-10-26 02:05:54 +02:00
|
|
|
* Writes a <code>TAG_Empty</code> tag.
|
2014-11-05 04:42:08 +01:00
|
|
|
*
|
2014-12-16 06:03:20 +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 */
|
|
|
|
}
|
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
|
|
|
}
|
2014-10-15 11:43:20 +02: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
|
|
|
}
|
2014-10-15 11:43:20 +02:00
|
|
|
|
2014-11-05 04:42:08 +01:00
|
|
|
}
|