2017-03-02 01:09:25 +01:00
|
|
|
package com.github.steveice10.opennbt.tag.builtin;
|
2014-03-02 01:46:32 +01:00
|
|
|
|
2021-03-14 15:40:10 +01:00
|
|
|
import com.github.steveice10.opennbt.tag.TagCreateException;
|
|
|
|
import com.github.steveice10.opennbt.tag.TagRegistry;
|
2022-08-14 22:16:32 +02:00
|
|
|
import com.github.steveice10.opennbt.tag.limiter.TagLimiter;
|
2021-03-14 15:40:10 +01:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2014-03-02 01:46:32 +01:00
|
|
|
|
2016-12-16 03:15:04 +01:00
|
|
|
import java.io.DataInput;
|
|
|
|
import java.io.DataOutput;
|
2014-03-26 04:16:23 +01:00
|
|
|
import java.io.EOFException;
|
2014-03-02 01:46:32 +01:00
|
|
|
import java.io.IOException;
|
2017-09-01 21:52:20 +02:00
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.Map;
|
2014-03-02 01:46:32 +01:00
|
|
|
import java.util.Map.Entry;
|
2017-09-01 21:52:20 +02:00
|
|
|
import java.util.Set;
|
2014-03-02 01:46:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A compound tag containing other tags.
|
|
|
|
*/
|
2021-03-14 15:40:10 +01:00
|
|
|
public class CompoundTag extends Tag implements Iterable<Entry<String, Tag>> {
|
|
|
|
public static final int ID = 10;
|
2017-09-01 21:52:20 +02:00
|
|
|
private Map<String, Tag> value;
|
|
|
|
|
|
|
|
/**
|
2021-03-14 15:40:10 +01:00
|
|
|
* Creates a tag.
|
|
|
|
*/
|
|
|
|
public CompoundTag() {
|
|
|
|
this(new LinkedHashMap<>());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
*
|
2021-03-14 15:40:10 +01:00
|
|
|
* @param value The value of the tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
*/
|
2021-03-14 15:40:10 +01:00
|
|
|
public CompoundTag(Map<String, Tag> value) {
|
|
|
|
this.value = new LinkedHashMap<>(value);
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-14 15:40:10 +01:00
|
|
|
* Creates a tag without wrapping the map.
|
2017-09-01 21:52:20 +02:00
|
|
|
*
|
|
|
|
* @param value The value of the tag.
|
|
|
|
*/
|
2021-03-14 15:40:10 +01:00
|
|
|
public CompoundTag(LinkedHashMap<String, Tag> value) {
|
2023-03-03 13:51:13 +01:00
|
|
|
if (value == null) {
|
|
|
|
throw new NullPointerException("value cannot be null");
|
|
|
|
}
|
2021-03-14 15:40:10 +01:00
|
|
|
this.value = value;
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Map<String, Tag> getValue() {
|
2021-03-14 15:40:10 +01:00
|
|
|
return this.value;
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the value of this tag.
|
|
|
|
*
|
|
|
|
* @param value New value of this tag.
|
|
|
|
*/
|
|
|
|
public void setValue(Map<String, Tag> value) {
|
2023-03-03 13:51:13 +01:00
|
|
|
if (value == null) {
|
|
|
|
throw new NullPointerException("value cannot be null");
|
|
|
|
}
|
2021-03-14 15:40:10 +01:00
|
|
|
this.value = new LinkedHashMap<>(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the value of this tag without wrapping the map.
|
|
|
|
*
|
|
|
|
* @param value New value of this tag.
|
|
|
|
*/
|
|
|
|
public void setValue(LinkedHashMap<String, Tag> value) {
|
2023-03-03 13:51:13 +01:00
|
|
|
if (value == null) {
|
|
|
|
throw new NullPointerException("value cannot be null");
|
|
|
|
}
|
2021-03-14 15:40:10 +01:00
|
|
|
this.value = value;
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the compound tag is empty.
|
|
|
|
*
|
|
|
|
* @return Whether the compound tag is empty.
|
|
|
|
*/
|
|
|
|
public boolean isEmpty() {
|
|
|
|
return this.value.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-14 15:40:10 +01:00
|
|
|
* Checks whether the compound tag contains a tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
*
|
|
|
|
* @param tagName Name of the tag to check for.
|
2021-03-14 15:40:10 +01:00
|
|
|
* @return Whether the compound tag contains a tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
*/
|
|
|
|
public boolean contains(String tagName) {
|
|
|
|
return this.value.containsKey(tagName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-14 15:40:10 +01:00
|
|
|
* Gets the tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
*
|
|
|
|
* @param <T> Type of tag to get.
|
|
|
|
* @param tagName Name of the tag.
|
2021-03-14 15:40:10 +01:00
|
|
|
* @return The tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
*/
|
2021-03-14 15:40:10 +01:00
|
|
|
@Nullable
|
2017-09-01 21:52:20 +02:00
|
|
|
public <T extends Tag> T get(String tagName) {
|
|
|
|
return (T) this.value.get(tagName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Puts the tag into this compound tag.
|
|
|
|
*
|
2021-03-14 15:40:10 +01:00
|
|
|
* @param <T> Type of tag to put.
|
|
|
|
* @param tagName Name of the tag.
|
|
|
|
* @param tag Tag to put into this compound tag.
|
2017-09-01 21:52:20 +02:00
|
|
|
* @return The previous tag associated with its name, or null if there wasn't one.
|
|
|
|
*/
|
2021-03-14 15:40:10 +01:00
|
|
|
@Nullable
|
|
|
|
public <T extends Tag> T put(String tagName, T tag) {
|
|
|
|
return (T) this.value.put(tagName, tag);
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes a tag from this compound tag.
|
|
|
|
*
|
|
|
|
* @param <T> Type of tag to remove.
|
|
|
|
* @param tagName Name of the tag to remove.
|
|
|
|
* @return The removed tag.
|
|
|
|
*/
|
2021-03-14 15:40:10 +01:00
|
|
|
@Nullable
|
2017-09-01 21:52:20 +02:00
|
|
|
public <T extends Tag> T remove(String tagName) {
|
|
|
|
return (T) this.value.remove(tagName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a set of keys in this compound tag.
|
|
|
|
*
|
|
|
|
* @return The compound tag's key set.
|
|
|
|
*/
|
|
|
|
public Set<String> keySet() {
|
|
|
|
return this.value.keySet();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a collection of tags in this compound tag.
|
|
|
|
*
|
|
|
|
* @return This compound tag's tags.
|
|
|
|
*/
|
|
|
|
public Collection<Tag> values() {
|
|
|
|
return this.value.values();
|
|
|
|
}
|
|
|
|
|
2021-03-14 15:40:10 +01:00
|
|
|
/**
|
|
|
|
* Gets the entry set of this compound tag.
|
|
|
|
*
|
|
|
|
* @return The compound tag's entry set.
|
|
|
|
*/
|
|
|
|
public Set<Entry<String, Tag>> entrySet() {
|
|
|
|
return this.value.entrySet();
|
|
|
|
}
|
|
|
|
|
2017-09-01 21:52:20 +02:00
|
|
|
/**
|
|
|
|
* Gets the number of tags in this compound tag.
|
|
|
|
*
|
|
|
|
* @return This compound tag's size.
|
|
|
|
*/
|
|
|
|
public int size() {
|
|
|
|
return this.value.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clears all tags from this compound tag.
|
|
|
|
*/
|
|
|
|
public void clear() {
|
|
|
|
this.value.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-03-14 15:40:10 +01:00
|
|
|
public Iterator<Entry<String, Tag>> iterator() {
|
|
|
|
return this.value.entrySet().iterator();
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-08-14 22:16:32 +02:00
|
|
|
public void read(DataInput in, TagLimiter tagLimiter, int nestingLevel) throws IOException {
|
2017-09-01 21:52:20 +02:00
|
|
|
try {
|
2022-08-14 22:16:32 +02:00
|
|
|
tagLimiter.checkLevel(nestingLevel);
|
|
|
|
int newNestingLevel = nestingLevel + 1;
|
2021-03-14 15:40:10 +01:00
|
|
|
int id;
|
|
|
|
while (true) {
|
2022-08-14 22:16:32 +02:00
|
|
|
tagLimiter.countByte();
|
2021-03-14 15:40:10 +01:00
|
|
|
id = in.readByte();
|
|
|
|
if (id == 0) {
|
|
|
|
// End tag
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
String name = in.readUTF();
|
2022-08-14 22:16:32 +02:00
|
|
|
tagLimiter.countBytes(2 * name.length());
|
|
|
|
|
2021-03-14 15:40:10 +01:00
|
|
|
Tag tag = TagRegistry.createInstance(id);
|
2022-08-14 22:16:32 +02:00
|
|
|
tag.read(in, tagLimiter, newNestingLevel);
|
2021-03-14 15:40:10 +01:00
|
|
|
this.value.put(name, tag);
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
2021-03-14 15:40:10 +01:00
|
|
|
} catch(TagCreateException e) {
|
|
|
|
throw new IOException("Failed to create tag.", e);
|
2022-05-16 13:15:04 +02:00
|
|
|
} catch(EOFException ignored) {
|
2021-03-14 15:40:10 +01:00
|
|
|
throw new IOException("Closing tag was not found!");
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void write(DataOutput out) throws IOException {
|
2021-03-14 15:40:10 +01:00
|
|
|
for(Entry<String, Tag> entry : this.value.entrySet()) {
|
|
|
|
Tag tag = entry.getValue();
|
|
|
|
out.writeByte(tag.getTagId());
|
|
|
|
out.writeUTF(entry.getKey());
|
|
|
|
tag.write(out);
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
|
|
|
|
2021-03-14 15:40:10 +01:00
|
|
|
// End
|
2017-09-01 21:52:20 +02:00
|
|
|
out.writeByte(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-03-14 15:40:10 +01:00
|
|
|
public boolean equals(final Object o) {
|
|
|
|
if (this == o) return true;
|
|
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
|
|
CompoundTag tags = (CompoundTag) o;
|
|
|
|
return this.value.equals(tags.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return value.hashCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public final CompoundTag clone() {
|
|
|
|
LinkedHashMap<String, Tag> newMap = new LinkedHashMap<>();
|
2017-09-01 21:52:20 +02:00
|
|
|
for(Entry<String, Tag> entry : this.value.entrySet()) {
|
|
|
|
newMap.put(entry.getKey(), entry.getValue().clone());
|
|
|
|
}
|
|
|
|
|
2021-03-14 15:40:10 +01:00
|
|
|
return new CompoundTag(newMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getTagId() {
|
|
|
|
return ID;
|
2017-09-01 21:52:20 +02:00
|
|
|
}
|
2014-03-02 01:46:32 +01:00
|
|
|
}
|