Skip to content

Commit 41e49da

Browse files
Outfluencermd-5
authored andcommitted
#3803: Add NBT module
1 parent bec3293 commit 41e49da

39 files changed

+1514
-154
lines changed

nbt/LICENSE

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2025, SpigotMC Pty. Ltd.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
3. Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived from
17+
this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

nbt/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
BungeeCord-NBT
2+
=================
3+
4+
Minimal implementation of NBT for use in BungeeCord

nbt/nb-configuration.xml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project-shared-configuration>
3+
<!--
4+
This file contains additional configuration written by modules in the NetBeans IDE.
5+
The configuration is intended to be shared among all the users of project and
6+
therefore it is assumed to be part of version control checkout.
7+
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
8+
-->
9+
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
10+
<!--
11+
Properties that influence various parts of the IDE, especially code formatting and the like.
12+
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
13+
That way multiple projects can share the same settings (useful for formatting rules for example).
14+
Any value defined here will override the pom.xml file value but is only applicable to the current project.
15+
-->
16+
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
17+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
18+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
19+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
20+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
21+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
22+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
23+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
24+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
25+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
26+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
27+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
28+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
29+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
30+
</properties>
31+
</project-shared-configuration>

nbt/pom.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>net.md-5</groupId>
8+
<artifactId>bungeecord-parent</artifactId>
9+
<version>1.21-R0.3-SNAPSHOT</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
<groupId>net.md-5</groupId>
14+
<artifactId>bungeecord-nbt</artifactId>
15+
<version>1.21-R0.3-SNAPSHOT</version>
16+
<packaging>jar</packaging>
17+
18+
<name>BungeeCord-NBT</name>
19+
<description>Minimal implementation of NBT for use in BungeeCord</description>
20+
<licenses>
21+
<license>
22+
<name>BSD-3-Clause</name>
23+
<url>https://github.com/SpigotMC/BungeeCord/blob/master/dialog/LICENSE</url>
24+
<distribution>repo</distribution>
25+
</license>
26+
</licenses>
27+
</project>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package net.md_5.bungee.nbt;
2+
3+
import com.google.common.base.Preconditions;
4+
import java.io.DataInput;
5+
import java.io.DataOutput;
6+
import java.io.IOException;
7+
import lombok.AllArgsConstructor;
8+
import lombok.Data;
9+
import lombok.NoArgsConstructor;
10+
import net.md_5.bungee.nbt.limit.NBTLimiter;
11+
import net.md_5.bungee.nbt.type.CompoundTag;
12+
13+
@Data
14+
@NoArgsConstructor
15+
@AllArgsConstructor
16+
public class NamedTag implements Tag
17+
{
18+
19+
private String name;
20+
private TypedTag tag;
21+
22+
/**
23+
* Reads the data of the {@link DataInput} and parses it into this
24+
* {@link NamedTag}.
25+
*
26+
* @param input input to read from
27+
* @param limiter limitation of the read data
28+
*/
29+
@Override
30+
public void read(DataInput input, NBTLimiter limiter) throws IOException
31+
{
32+
byte type = input.readByte();
33+
name = CompoundTag.readString( input, limiter );
34+
tag = Tag.readById( type, input, limiter );
35+
}
36+
37+
/**
38+
* Write this {@link NamedTag} into a {@link DataOutput}.
39+
*
40+
* @param output the output to write to
41+
*/
42+
@Override
43+
public void write(DataOutput output) throws IOException
44+
{
45+
Preconditions.checkNotNull( name, "name cannot be null" );
46+
Preconditions.checkNotNull( tag, "tag cannot be null" );
47+
48+
output.writeByte( tag.getId() );
49+
CompoundTag.writeString( name, output );
50+
tag.write( output );
51+
}
52+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package net.md_5.bungee.nbt;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.DataInput;
6+
import java.io.DataInputStream;
7+
import java.io.DataOutput;
8+
import java.io.DataOutputStream;
9+
import java.io.IOException;
10+
import java.util.function.Supplier;
11+
import net.md_5.bungee.nbt.exception.NBTFormatException;
12+
import net.md_5.bungee.nbt.limit.NBTLimiter;
13+
import net.md_5.bungee.nbt.type.ByteArrayTag;
14+
import net.md_5.bungee.nbt.type.ByteTag;
15+
import net.md_5.bungee.nbt.type.CompoundTag;
16+
import net.md_5.bungee.nbt.type.DoubleTag;
17+
import net.md_5.bungee.nbt.type.EndTag;
18+
import net.md_5.bungee.nbt.type.FloatTag;
19+
import net.md_5.bungee.nbt.type.IntArrayTag;
20+
import net.md_5.bungee.nbt.type.IntTag;
21+
import net.md_5.bungee.nbt.type.ListTag;
22+
import net.md_5.bungee.nbt.type.LongArrayTag;
23+
import net.md_5.bungee.nbt.type.LongTag;
24+
import net.md_5.bungee.nbt.type.ShortTag;
25+
import net.md_5.bungee.nbt.type.StringTag;
26+
27+
public interface Tag
28+
{
29+
30+
int OBJECT_HEADER = 8;
31+
int ARRAY_HEADER = 12;
32+
int STRING_SIZE = 28;
33+
int OBJECT_REFERENCE = 4;
34+
35+
Supplier<? extends TypedTag>[] CONSTRUCTORS = new Supplier[]
36+
{
37+
EndTag::new,
38+
ByteTag::new,
39+
ShortTag::new,
40+
IntTag::new,
41+
LongTag::new,
42+
FloatTag::new,
43+
DoubleTag::new,
44+
ByteArrayTag::new,
45+
StringTag::new,
46+
ListTag::new,
47+
CompoundTag::new,
48+
IntArrayTag::new,
49+
LongArrayTag::new
50+
};
51+
52+
byte END = 0;
53+
byte BYTE = 1;
54+
byte SHORT = 2;
55+
byte INT = 3;
56+
byte LONG = 4;
57+
byte FLOAT = 5;
58+
byte DOUBLE = 6;
59+
byte BYTE_ARRAY = 7;
60+
byte STRING = 8;
61+
byte LIST = 9;
62+
byte COMPOUND = 10;
63+
byte INT_ARRAY = 11;
64+
byte LONG_ARRAY = 12;
65+
66+
/**
67+
* Reads the data into this tag.
68+
*
69+
* @param input the input to read from
70+
* @param limiter the limiter for this read operation
71+
* @throws IOException if an exception occurs during io operations
72+
*/
73+
void read(DataInput input, NBTLimiter limiter) throws IOException;
74+
75+
/**
76+
* Writes this tag into a {@link DataOutput}.
77+
*
78+
* @param output the output to write to
79+
* @throws IOException if an exception occurs during io operations
80+
*/
81+
void write(DataOutput output) throws IOException;
82+
83+
/**
84+
* Reads the data of the {@link DataInput} and parses it into a {@link Tag}.
85+
*
86+
* @param id the nbt type
87+
* @param input input to read from
88+
* @param limiter limitation of the read data
89+
* @return the initialized {@link Tag}
90+
* @throws IOException if an exception occurs during io operations
91+
*/
92+
static TypedTag readById(byte id, DataInput input, NBTLimiter limiter) throws IOException
93+
{
94+
if ( id < END || id > LONG_ARRAY )
95+
{
96+
throw new NBTFormatException( "Invalid tag id: " + id );
97+
}
98+
99+
TypedTag tag = CONSTRUCTORS[id].get();
100+
tag.read( input, limiter );
101+
return tag;
102+
}
103+
104+
static NamedTag readNamedTag(DataInput input, NBTLimiter limiter) throws IOException
105+
{
106+
NamedTag namedTag = new NamedTag();
107+
namedTag.read( input, limiter );
108+
return namedTag;
109+
}
110+
111+
static byte[] toByteArray(TypedTag tag) throws IOException
112+
{
113+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
114+
DataOutputStream dataOutputStream = new DataOutputStream( byteArrayOutputStream );
115+
dataOutputStream.writeByte( tag.getId() );
116+
tag.write( dataOutputStream );
117+
return byteArrayOutputStream.toByteArray();
118+
}
119+
120+
static TypedTag fromByteArray(byte[] data) throws IOException
121+
{
122+
return fromByteArray( data, NBTLimiter.unlimitedSize() );
123+
}
124+
125+
static TypedTag fromByteArray(byte[] data, NBTLimiter limiter) throws IOException
126+
{
127+
DataInputStream stream = new DataInputStream( new ByteArrayInputStream( data ) );
128+
byte type = stream.readByte();
129+
return readById( type, stream, limiter );
130+
}
131+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.md_5.bungee.nbt;
2+
3+
public interface TypedTag extends Tag
4+
{
5+
6+
/**
7+
* Gets the id of this tag's type.
8+
*
9+
* @return the id related to this tag's type
10+
*/
11+
byte getId();
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package net.md_5.bungee.nbt.exception;
2+
3+
public class NBTException extends RuntimeException
4+
{
5+
6+
public NBTException(String message)
7+
{
8+
super( message );
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package net.md_5.bungee.nbt.exception;
2+
3+
public class NBTFormatException extends NBTException
4+
{
5+
6+
public NBTFormatException(String message)
7+
{
8+
super( message );
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package net.md_5.bungee.nbt.exception;
2+
3+
public class NBTLimitException extends NBTException
4+
{
5+
6+
public NBTLimitException(String message)
7+
{
8+
super( message );
9+
}
10+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package net.md_5.bungee.nbt.limit;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import net.md_5.bungee.nbt.exception.NBTLimitException;
5+
6+
@RequiredArgsConstructor
7+
public class NBTLimiter
8+
{
9+
10+
private static final int MAX_STACK_DEPTH = 512;
11+
//
12+
private final long maxBytes;
13+
private final int maxDepth;
14+
15+
public static NBTLimiter unlimitedSize()
16+
{
17+
return new NBTLimiter( Long.MAX_VALUE, MAX_STACK_DEPTH );
18+
}
19+
20+
public NBTLimiter(long maxBytes)
21+
{
22+
this( maxBytes, MAX_STACK_DEPTH );
23+
}
24+
25+
private long usedBytes;
26+
private int depth;
27+
28+
public void countBytes(long amount)
29+
{
30+
if ( amount < 0 )
31+
{
32+
throw new NBTLimitException( "NBT limiter tried to count negative byte amount" );
33+
}
34+
35+
if ( ( usedBytes = Math.addExact( usedBytes, amount ) ) > maxBytes )
36+
{
37+
throw new NBTLimitException( "NBT tag is to big, bytes > " + maxBytes );
38+
}
39+
}
40+
41+
public void countBytes(long amount, long factor)
42+
{
43+
if ( amount < 0 || factor < 0 )
44+
{
45+
throw new NBTLimitException( "NBT limiter tried to count negative byte amount" );
46+
}
47+
48+
countBytes( Math.multiplyExact( amount, factor ) );
49+
}
50+
51+
public void push()
52+
{
53+
if ( ( depth = Math.addExact( depth, 1 ) ) > maxDepth )
54+
{
55+
throw new NBTLimitException( "NBT tag is to complex, depth > " + maxDepth );
56+
}
57+
}
58+
59+
public void pop()
60+
{
61+
if ( --depth < 0 )
62+
{
63+
throw new NBTLimitException( "NBT limiter tried to pop depth 0" );
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)