├── .github └── workflows │ ├── deploy.yml │ └── maven.yml ├── .gitignore ├── Jenkinsfile ├── LICENSE.txt ├── README.md ├── pom.xml └── src └── main └── java └── com └── github └── steveice10 └── opennbt ├── NBTIO.java ├── SNBTIO.java ├── conversion ├── ConversionException.java ├── ConverterRegisterException.java ├── ConverterRegistry.java ├── TagConverter.java └── builtin │ ├── ByteArrayTagConverter.java │ ├── ByteTagConverter.java │ ├── CompoundTagConverter.java │ ├── DoubleTagConverter.java │ ├── FloatTagConverter.java │ ├── IntArrayTagConverter.java │ ├── IntTagConverter.java │ ├── ListTagConverter.java │ ├── LongArrayTagConverter.java │ ├── LongTagConverter.java │ ├── ShortTagConverter.java │ ├── StringTagConverter.java │ └── custom │ ├── DoubleArrayTagConverter.java │ ├── FloatArrayTagConverter.java │ └── ShortArrayTagConverter.java └── tag ├── TagCreateException.java ├── TagRegisterException.java ├── TagRegistry.java └── builtin ├── ByteArrayTag.java ├── ByteTag.java ├── CompoundTag.java ├── DoubleTag.java ├── FloatTag.java ├── IntArrayTag.java ├── IntTag.java ├── ListTag.java ├── LongArrayTag.java ├── LongTag.java ├── ShortTag.java ├── StringTag.java ├── Tag.java └── custom ├── DoubleArrayTag.java ├── FloatArrayTag.java └── ShortArrayTag.java /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac 16 | 17 | - name: Set up JDK 1.8 18 | uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 19 | with: 20 | java-version: 8 21 | distribution: temurin 22 | 23 | - uses: s4u/maven-settings-action@v2.8.0 24 | with: 25 | servers: '[{"id": "opencollab-release-repo", "username": "${env.MAVEN_USERNAME}", "password": "${env.MAVEN_PASSWORD}"},{"id": "opencollab-snapshot-repo", "username": "${env.MAVEN_USERNAME}", "password": "${env.MAVEN_PASSWORD}"}]' 26 | 27 | - name: Deploy with Maven 28 | run: mvn deploy -B -P deploy 29 | env: 30 | MAVEN_USERNAME: ${{ vars.DEPLOY_USER }} 31 | MAVEN_PASSWORD: ${{ secrets.DEPLOY_PASS }} 32 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac 13 | 14 | - name: Set up JDK 1.8 15 | uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 16 | with: 17 | java-version: 8 18 | distribution: temurin 19 | 20 | - name: Build with Maven 21 | run: mvn package --file pom.xml 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | lib 3 | target 4 | testing 5 | 6 | .settings 7 | .classpath 8 | .project 9 | .directory 10 | 11 | *.iml 12 | .idea 13 | 14 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | tools { 4 | maven 'Maven 3' 5 | jdk 'Java 8' 6 | } 7 | options { 8 | buildDiscarder(logRotator(artifactNumToKeepStr: '20')) 9 | } 10 | stages { 11 | stage ('Build') { 12 | steps { 13 | sh 'mvn clean package' 14 | } 15 | post { 16 | success { 17 | archiveArtifacts artifacts: 'target/*.jar', excludes: 'target/*-sources.jar', fingerprint: true 18 | } 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013-2021 Steveice10 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Now archived 2 | 3 | For alternative NBT libraries in Java, please see [ViaNBT](https://github.com/ViaVersion/ViaNBT) (derived from an earlier version of OpenNBT) or [CloudburstMC's NBT implementation](https://github.com/CloudburstMC/NBT) (what MCProtocolLib now uses). Both have active maintenance as of the time of this repository's archival. 4 | 5 | # OpenNBT 6 | OpenNBT is a library for reading and writing NBT files and stringified NBT, with some extra custom tags added to allow the storage of more data types. 7 | 8 | ## Building the Source 9 | OpenNBT uses Maven to manage dependencies. Simply run 'mvn clean install' in the source's directory. 10 | 11 | ## Support and development 12 | 13 | Please join us at https://discord.gg/geysermc under #mcprotocollib for discussion and support for this project. 14 | 15 | ## License 16 | OpenNBT is licensed under the **[MIT license](http://www.opensource.org/licenses/mit-license.html)**. 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.github.steveice10 7 | opennbt 8 | 1.6 9 | jar 10 | 11 | OpenNBT 12 | A library for reading and writing NBT files, written in Java. 13 | http://github.com/Steveice10/OpenNBT/ 14 | 15 | 16 | scm:git:git@github.com:Steveice10/OpenNBT.git 17 | scm:git:git@github.com:Steveice10/OpenNBT.git 18 | http://github.com/Steveice10/OpenNBT/ 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | MIT 29 | http://www.opensource.org/licenses/mit-license.html 30 | repo 31 | 32 | 33 | 34 | 35 | 36 | steveice10 37 | Steveice10 38 | Steveice10@gmail.com 39 | 40 | 41 | GeyserMC 42 | GeyserMC 43 | https://geysermc.org/ 44 | GeyserMC 45 | https://github.com/GeyserMC 46 | 47 | 48 | 49 | 50 | GitHub 51 | https://github.com/Steveice10/OpenNBT/issues 52 | 53 | 54 | 55 | clean install 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-clean-plugin 60 | 3.0.0 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-resources-plugin 65 | 3.0.2 66 | 67 | 68 | org.apache.maven.plugins 69 | maven-jar-plugin 70 | 3.0.2 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 3.7.0 76 | 77 | ${jdk.version} 78 | ${jdk.version} 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-surefire-plugin 84 | 2.22.0 85 | 86 | 87 | true 88 | 89 | -Dfile.encoding=${project.build.sourceEncoding} @{argLine} 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-javadoc-plugin 95 | 2.10.4 96 | 97 | 98 | attach-javadocs 99 | 100 | aggregate 101 | jar 102 | 103 | 104 | 105 | 106 | public 107 | false 108 | 109 | 110 | 111 | org.apache.maven.plugins 112 | maven-source-plugin 113 | 3.0.1 114 | 115 | 116 | attach-sources 117 | 118 | jar 119 | 120 | 121 | 122 | 123 | 124 | org.apache.maven.plugins 125 | maven-install-plugin 126 | 2.5.2 127 | 128 | 129 | org.apache.maven.plugins 130 | maven-deploy-plugin 131 | 2.8.2 132 | 133 | 134 | 135 | 136 | 137 | 138 | deploy 139 | 140 | true 141 | 142 | 143 | 144 | opencollab-release-repo 145 | https://repo.opencollab.dev/maven-releases/ 146 | 147 | 148 | opencollab-snapshot-repo 149 | https://repo.opencollab.dev/maven-snapshots/ 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/NBTIO.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt; 2 | 3 | import com.github.steveice10.opennbt.tag.TagCreateException; 4 | import com.github.steveice10.opennbt.tag.TagRegistry; 5 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 6 | import com.github.steveice10.opennbt.tag.builtin.Tag; 7 | 8 | import java.io.DataInput; 9 | import java.io.DataInputStream; 10 | import java.io.DataOutput; 11 | import java.io.DataOutputStream; 12 | import java.io.EOFException; 13 | import java.io.File; 14 | import java.io.FileInputStream; 15 | import java.io.FileOutputStream; 16 | import java.io.FilterInputStream; 17 | import java.io.FilterOutputStream; 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.io.OutputStream; 21 | import java.util.zip.GZIPInputStream; 22 | import java.util.zip.GZIPOutputStream; 23 | 24 | /** 25 | * A class containing methods for reading/writing NBT tags. 26 | */ 27 | public class NBTIO { 28 | /** 29 | * Reads the compressed, big endian root CompoundTag from the given file. 30 | * 31 | * @param path Path of the file. 32 | * @return The read compound tag. 33 | * @throws java.io.IOException If an I/O error occurs. 34 | */ 35 | public static CompoundTag readFile(String path) throws IOException { 36 | return readFile(new File(path)); 37 | } 38 | 39 | /** 40 | * Reads the compressed, big endian root CompoundTag from the given file. 41 | * 42 | * @param file File to read from. 43 | * @return The read compound tag. 44 | * @throws java.io.IOException If an I/O error occurs. 45 | */ 46 | public static CompoundTag readFile(File file) throws IOException { 47 | return readFile(file, true, false); 48 | } 49 | 50 | /** 51 | * Reads the root CompoundTag from the given file. 52 | * 53 | * @param path Path of the file. 54 | * @param compressed Whether the NBT file is compressed. 55 | * @param littleEndian Whether the NBT file is little endian. 56 | * @return The read compound tag. 57 | * @throws java.io.IOException If an I/O error occurs. 58 | */ 59 | public static CompoundTag readFile(String path, boolean compressed, boolean littleEndian) throws IOException { 60 | return readFile(new File(path), compressed, littleEndian); 61 | } 62 | 63 | /** 64 | * Reads the root CompoundTag from the given file. 65 | * 66 | * @param file File to read from. 67 | * @param compressed Whether the NBT file is compressed. 68 | * @param littleEndian Whether the NBT file is little endian. 69 | * @return The read compound tag. 70 | * @throws java.io.IOException If an I/O error occurs. 71 | */ 72 | public static CompoundTag readFile(File file, boolean compressed, boolean littleEndian) throws IOException { 73 | InputStream in = new FileInputStream(file); 74 | try { 75 | if (compressed) { 76 | in = new GZIPInputStream(in); 77 | } 78 | 79 | Tag tag = readTag(in, littleEndian); 80 | if (!(tag instanceof CompoundTag)) { 81 | throw new IOException("Root tag is not a CompoundTag!"); 82 | } 83 | 84 | return (CompoundTag) tag; 85 | } finally { 86 | in.close(); 87 | } 88 | } 89 | 90 | /** 91 | * Writes the given root CompoundTag to the given file, compressed and in big endian. 92 | * 93 | * @param tag Tag to write. 94 | * @param path Path to write to. 95 | * @throws java.io.IOException If an I/O error occurs. 96 | */ 97 | public static void writeFile(CompoundTag tag, String path) throws IOException { 98 | writeFile(tag, new File(path)); 99 | } 100 | 101 | /** 102 | * Writes the given root CompoundTag to the given file, compressed and in big endian. 103 | * 104 | * @param tag Tag to write. 105 | * @param file File to write to. 106 | * @throws java.io.IOException If an I/O error occurs. 107 | */ 108 | public static void writeFile(CompoundTag tag, File file) throws IOException { 109 | writeFile(tag, file, true, false); 110 | } 111 | 112 | /** 113 | * Writes the given root CompoundTag to the given file. 114 | * 115 | * @param tag Tag to write. 116 | * @param path Path to write to. 117 | * @param compressed Whether the NBT file should be compressed. 118 | * @param littleEndian Whether to write little endian NBT. 119 | * @throws java.io.IOException If an I/O error occurs. 120 | */ 121 | public static void writeFile(CompoundTag tag, String path, boolean compressed, boolean littleEndian) throws IOException { 122 | writeFile(tag, new File(path), compressed, littleEndian); 123 | } 124 | 125 | /** 126 | * Writes the given root CompoundTag to the given file. 127 | * 128 | * @param tag Tag to write. 129 | * @param file File to write to. 130 | * @param compressed Whether the NBT file should be compressed. 131 | * @param littleEndian Whether to write little endian NBT. 132 | * @throws java.io.IOException If an I/O error occurs. 133 | */ 134 | public static void writeFile(CompoundTag tag, File file, boolean compressed, boolean littleEndian) throws IOException { 135 | if(!file.exists()) { 136 | if(file.getParentFile() != null && !file.getParentFile().exists()) { 137 | file.getParentFile().mkdirs(); 138 | } 139 | 140 | file.createNewFile(); 141 | } 142 | 143 | OutputStream out = new FileOutputStream(file); 144 | try { 145 | if (compressed) { 146 | out = new GZIPOutputStream(out); 147 | } 148 | 149 | writeTag(out, tag, littleEndian); 150 | } finally { 151 | out.close(); 152 | } 153 | } 154 | 155 | /** 156 | * Reads a big endian NBT tag. 157 | * 158 | * @param in Input stream to read from. 159 | * @return The read tag, or null if the tag is an end tag. 160 | * @throws java.io.IOException If an I/O error occurs. 161 | */ 162 | public static Tag readTag(InputStream in) throws IOException { 163 | return readTag(in, false); 164 | } 165 | 166 | /** 167 | * Reads an NBT tag. 168 | * 169 | * @param in Input stream to read from. 170 | * @param littleEndian Whether to read little endian NBT. 171 | * @return The read tag, or null if the tag is an end tag. 172 | * @throws java.io.IOException If an I/O error occurs. 173 | */ 174 | public static Tag readTag(InputStream in, boolean littleEndian) throws IOException { 175 | return readTag((DataInput) (littleEndian ? new LittleEndianDataInputStream(in) : new DataInputStream(in))); 176 | } 177 | 178 | /** 179 | * Reads an NBT tag. 180 | * 181 | * @param in Data input to read from. 182 | * @return The read tag, or null if the tag is an end tag. 183 | * @throws java.io.IOException If an I/O error occurs. 184 | */ 185 | public static Tag readTag(DataInput in) throws IOException { 186 | int id = in.readUnsignedByte(); 187 | if(id == 0) { 188 | return null; 189 | } 190 | 191 | String name = in.readUTF(); 192 | Tag tag; 193 | 194 | try { 195 | tag = TagRegistry.createInstance(id, name); 196 | } catch(TagCreateException e) { 197 | throw new IOException("Failed to create tag.", e); 198 | } 199 | 200 | tag.read(in); 201 | return tag; 202 | } 203 | 204 | /** 205 | * Reads a big endian NBT tag. 206 | * 207 | * @param in Input stream to read from. 208 | * @return The read tag, or null if the tag is an end tag. 209 | * @throws java.io.IOException If an I/O error occurs. 210 | */ 211 | public static Tag readAnyTag(InputStream in) throws IOException { 212 | return readAnyTag(in, false); 213 | } 214 | 215 | /** 216 | * Reads an NBT tag. 217 | * 218 | * @param in Input stream to read from. 219 | * @param littleEndian Whether to read little endian NBT. 220 | * @return The read tag, or null if the tag is an end tag. 221 | * @throws java.io.IOException If an I/O error occurs. 222 | */ 223 | public static Tag readAnyTag(InputStream in, boolean littleEndian) throws IOException { 224 | return readAnyTag((DataInput) (littleEndian ? new LittleEndianDataInputStream(in) : new DataInputStream(in))); 225 | } 226 | 227 | /** 228 | * Reads an NBT tag. 229 | * 230 | * @param in Data input to read from. 231 | * @return The read tag, or null if the tag is an end tag. 232 | * @throws java.io.IOException If an I/O error occurs. 233 | */ 234 | public static Tag readAnyTag(DataInput in) throws IOException { 235 | int id = in.readUnsignedByte(); 236 | if(id == 0) { 237 | return null; 238 | } 239 | 240 | Tag tag; 241 | 242 | try { 243 | tag = TagRegistry.createInstance(id, ""); 244 | } catch(TagCreateException e) { 245 | throw new IOException("Failed to create tag.", e); 246 | } 247 | 248 | tag.read(in); 249 | return tag; 250 | } 251 | 252 | /** 253 | * Writes an NBT tag in big endian. 254 | * 255 | * @param out Output stream to write to. 256 | * @param tag Tag to write. 257 | * @throws java.io.IOException If an I/O error occurs. 258 | */ 259 | public static void writeTag(OutputStream out, Tag tag) throws IOException { 260 | writeTag(out, tag, false); 261 | } 262 | 263 | /** 264 | * Writes an NBT tag. 265 | * 266 | * @param out Output stream to write to. 267 | * @param tag Tag to write. 268 | * @param littleEndian Whether to write little endian NBT. 269 | * @throws java.io.IOException If an I/O error occurs. 270 | */ 271 | public static void writeTag(OutputStream out, Tag tag, boolean littleEndian) throws IOException { 272 | writeTag((DataOutput) (littleEndian ? new LittleEndianDataOutputStream(out) : new DataOutputStream(out)), tag); 273 | } 274 | 275 | /** 276 | * Writes an NBT tag. 277 | * 278 | * @param out Data output to write to. 279 | * @param tag Tag to write. 280 | * @throws java.io.IOException If an I/O error occurs. 281 | */ 282 | public static void writeTag(DataOutput out, Tag tag) throws IOException { 283 | if(tag != null) { 284 | out.writeByte(TagRegistry.getIdFor(tag.getClass())); 285 | out.writeUTF(tag.getName()); 286 | tag.write(out); 287 | } else { 288 | out.writeByte(0); 289 | } 290 | } 291 | 292 | /** 293 | * Writes an NBT tag in big endian. 294 | * 295 | * @param out Output stream to write to. 296 | * @param tag Tag to write. 297 | * @throws java.io.IOException If an I/O error occurs. 298 | */ 299 | public static void writeAnyTag(OutputStream out, Tag tag) throws IOException { 300 | writeAnyTag(out, tag, false); 301 | } 302 | 303 | /** 304 | * Writes an NBT tag. 305 | * 306 | * @param out Output stream to write to. 307 | * @param tag Tag to write. 308 | * @param littleEndian Whether to write little endian NBT. 309 | * @throws java.io.IOException If an I/O error occurs. 310 | */ 311 | public static void writeAnyTag(OutputStream out, Tag tag, boolean littleEndian) throws IOException { 312 | writeAnyTag((DataOutput) (littleEndian ? new LittleEndianDataOutputStream(out) : new DataOutputStream(out)), tag); 313 | } 314 | 315 | public static void writeAnyTag(DataOutput out, Tag tag) throws IOException { 316 | if (tag != null) { 317 | out.writeByte(TagRegistry.getIdFor(tag.getClass())); 318 | tag.write(out); 319 | } else { 320 | out.writeByte(0); 321 | } 322 | } 323 | 324 | private static class LittleEndianDataInputStream extends FilterInputStream implements DataInput { 325 | public LittleEndianDataInputStream(InputStream in) { 326 | super(in); 327 | } 328 | 329 | @Override 330 | public int read(byte[] b) throws IOException { 331 | return this.in.read(b, 0, b.length); 332 | 333 | } 334 | 335 | @Override 336 | public int read(byte[] b, int off, int len) throws IOException { 337 | return this.in.read(b, off, len); 338 | } 339 | 340 | @Override 341 | public void readFully(byte[] b) throws IOException { 342 | this.readFully(b, 0, b.length); 343 | } 344 | 345 | @Override 346 | public void readFully(byte[] b, int off, int len) throws IOException { 347 | if(len < 0) { 348 | throw new IndexOutOfBoundsException(); 349 | } else { 350 | int read; 351 | for(int pos = 0; pos < len; pos += read) { 352 | read = this.in.read(b, off + pos, len - pos); 353 | if(read < 0) { 354 | throw new EOFException(); 355 | } 356 | } 357 | } 358 | } 359 | 360 | @Override 361 | public int skipBytes(int n) throws IOException { 362 | int total = 0; 363 | int skipped = 0; 364 | while(total < n && (skipped = (int) this.in.skip(n - total)) > 0) { 365 | total += skipped; 366 | } 367 | 368 | return total; 369 | } 370 | 371 | @Override 372 | public boolean readBoolean() throws IOException { 373 | int val = this.in.read(); 374 | if(val < 0) { 375 | throw new EOFException(); 376 | } 377 | 378 | return val != 0; 379 | } 380 | 381 | @Override 382 | public byte readByte() throws IOException { 383 | int val = this.in.read(); 384 | if(val < 0) { 385 | throw new EOFException(); 386 | } 387 | 388 | return (byte) val; 389 | } 390 | 391 | @Override 392 | public int readUnsignedByte() throws IOException { 393 | int val = this.in.read(); 394 | if(val < 0) { 395 | throw new EOFException(); 396 | } 397 | 398 | return val; 399 | } 400 | 401 | @Override 402 | public short readShort() throws IOException { 403 | int b1 = this.in.read(); 404 | int b2 = this.in.read(); 405 | if((b1 | b2) < 0) { 406 | throw new EOFException(); 407 | } 408 | 409 | return (short) (b1 | (b2 << 8)); 410 | } 411 | 412 | @Override 413 | public int readUnsignedShort() throws IOException { 414 | int b1 = this.in.read(); 415 | int b2 = this.in.read(); 416 | if((b1 | b2) < 0) { 417 | throw new EOFException(); 418 | } 419 | 420 | return b1 | (b2 << 8); 421 | } 422 | 423 | @Override 424 | public char readChar() throws IOException { 425 | int b1 = this.in.read(); 426 | int b2 = this.in.read(); 427 | if((b1 | b2) < 0) { 428 | throw new EOFException(); 429 | } 430 | 431 | return (char) (b1 | (b2 << 8)); 432 | } 433 | 434 | @Override 435 | public int readInt() throws IOException { 436 | int b1 = this.in.read(); 437 | int b2 = this.in.read(); 438 | int b3 = this.in.read(); 439 | int b4 = this.in.read(); 440 | if((b1 | b2 | b3 | b4) < 0) { 441 | throw new EOFException(); 442 | } 443 | 444 | return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24); 445 | } 446 | 447 | @Override 448 | public long readLong() throws IOException { 449 | long b1 = this.in.read(); 450 | long b2 = this.in.read(); 451 | long b3 = this.in.read(); 452 | long b4 = this.in.read(); 453 | long b5 = this.in.read(); 454 | long b6 = this.in.read(); 455 | long b7 = this.in.read(); 456 | long b8 = this.in.read(); 457 | if((b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8) < 0) { 458 | throw new EOFException(); 459 | } 460 | 461 | return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24) | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56); 462 | } 463 | 464 | @Override 465 | public float readFloat() throws IOException { 466 | return Float.intBitsToFloat(this.readInt()); 467 | } 468 | 469 | @Override 470 | public double readDouble() throws IOException { 471 | return Double.longBitsToDouble(this.readLong()); 472 | } 473 | 474 | @Override 475 | public String readLine() throws IOException { 476 | throw new UnsupportedOperationException("Use readUTF."); 477 | } 478 | 479 | @Override 480 | public String readUTF() throws IOException { 481 | byte[] bytes = new byte[this.readUnsignedShort()]; 482 | this.readFully(bytes); 483 | 484 | return new String(bytes, "UTF-8"); 485 | } 486 | } 487 | 488 | private static class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput { 489 | public LittleEndianDataOutputStream(OutputStream out) { 490 | super(out); 491 | } 492 | 493 | @Override 494 | public synchronized void write(int b) throws IOException { 495 | this.out.write(b); 496 | } 497 | 498 | @Override 499 | public synchronized void write(byte[] b, int off, int len) throws IOException { 500 | this.out.write(b, off, len); 501 | } 502 | 503 | @Override 504 | public void flush() throws IOException { 505 | this.out.flush(); 506 | } 507 | 508 | @Override 509 | public void writeBoolean(boolean b) throws IOException { 510 | this.out.write(b ? 1 : 0); 511 | } 512 | 513 | @Override 514 | public void writeByte(int b) throws IOException { 515 | this.out.write(b); 516 | } 517 | 518 | @Override 519 | public void writeShort(int s) throws IOException { 520 | this.out.write(s & 0xFF); 521 | this.out.write((s >>> 8) & 0xFF); 522 | } 523 | 524 | @Override 525 | public void writeChar(int c) throws IOException { 526 | this.out.write(c & 0xFF); 527 | this.out.write((c >>> 8) & 0xFF); 528 | } 529 | 530 | @Override 531 | public void writeInt(int i) throws IOException { 532 | this.out.write(i & 0xFF); 533 | this.out.write((i >>> 8) & 0xFF); 534 | this.out.write((i >>> 16) & 0xFF); 535 | this.out.write((i >>> 24) & 0xFF); 536 | } 537 | 538 | @Override 539 | public void writeLong(long l) throws IOException { 540 | this.out.write((int) (l & 0xFF)); 541 | this.out.write((int) ((l >>> 8) & 0xFF)); 542 | this.out.write((int) ((l >>> 16) & 0xFF)); 543 | this.out.write((int) ((l >>> 24) & 0xFF)); 544 | this.out.write((int) ((l >>> 32) & 0xFF)); 545 | this.out.write((int) ((l >>> 40) & 0xFF)); 546 | this.out.write((int) ((l >>> 48) & 0xFF)); 547 | this.out.write((int) ((l >>> 56) & 0xFF)); 548 | } 549 | 550 | @Override 551 | public void writeFloat(float f) throws IOException { 552 | this.writeInt(Float.floatToIntBits(f)); 553 | } 554 | 555 | @Override 556 | public void writeDouble(double d) throws IOException { 557 | this.writeLong(Double.doubleToLongBits(d)); 558 | } 559 | 560 | @Override 561 | public void writeBytes(String s) throws IOException { 562 | int len = s.length(); 563 | for(int index = 0; index < len; index++) { 564 | this.out.write((byte) s.charAt(index)); 565 | } 566 | } 567 | 568 | @Override 569 | public void writeChars(String s) throws IOException { 570 | int len = s.length(); 571 | for(int index = 0; index < len; index++) { 572 | char c = s.charAt(index); 573 | this.out.write(c & 0xFF); 574 | this.out.write((c >>> 8) & 0xFF); 575 | } 576 | } 577 | 578 | @Override 579 | public void writeUTF(String s) throws IOException { 580 | byte[] bytes = s.getBytes("UTF-8"); 581 | 582 | this.writeShort(bytes.length); 583 | this.write(bytes); 584 | } 585 | } 586 | } 587 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/SNBTIO.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.OutputStream; 11 | import java.io.OutputStreamWriter; 12 | import java.io.PushbackReader; 13 | import java.util.regex.Pattern; 14 | 15 | import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; 16 | import com.github.steveice10.opennbt.tag.builtin.ByteTag; 17 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 18 | import com.github.steveice10.opennbt.tag.builtin.DoubleTag; 19 | import com.github.steveice10.opennbt.tag.builtin.FloatTag; 20 | import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; 21 | import com.github.steveice10.opennbt.tag.builtin.IntTag; 22 | import com.github.steveice10.opennbt.tag.builtin.ListTag; 23 | import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; 24 | import com.github.steveice10.opennbt.tag.builtin.LongTag; 25 | import com.github.steveice10.opennbt.tag.builtin.ShortTag; 26 | import com.github.steveice10.opennbt.tag.builtin.StringTag; 27 | import com.github.steveice10.opennbt.tag.builtin.Tag; 28 | import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag; 29 | import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag; 30 | import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag; 31 | 32 | /** 33 | * A class containing methods for reading/writing stringified NBT tags. 34 | */ 35 | public class SNBTIO { 36 | /** 37 | * Reads stringified root CompoundTag from the given file. 38 | * 39 | * @param path Path of the file. 40 | * @return The read compound tag. 41 | * @throws java.io.IOException If an I/O error occurs. 42 | */ 43 | public static CompoundTag readFile(String path) throws IOException { 44 | return readFile(new File(path)); 45 | } 46 | 47 | /** 48 | * Reads the stringified CompoundTag from the given file. 49 | * 50 | * @param file File to read from. 51 | * @return The read compound tag. 52 | * @throws java.io.IOException If an I/O error occurs. 53 | */ 54 | public static CompoundTag readFile(File file) throws IOException { 55 | try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { 56 | Tag tag = readTag(in); 57 | if (!(tag instanceof CompoundTag)) { 58 | throw new IOException("Root tag is not a CompoundTag!"); 59 | } 60 | 61 | return (CompoundTag) tag; 62 | } 63 | } 64 | 65 | /** 66 | * Writes the given root CompoundTag to the given file as stringified NBT. 67 | * 68 | * @param tag Tag to write. 69 | * @param path Path to write to. 70 | * @throws java.io.IOException If an I/O error occurs. 71 | */ 72 | public static void writeFile(CompoundTag tag, String path) throws IOException { 73 | writeFile(tag, new File(path)); 74 | } 75 | 76 | /** 77 | * Writes the given root CompoundTag to the given file as stringified NBT. 78 | * 79 | * @param tag Tag to write. 80 | * @param file File to write to. 81 | * @throws java.io.IOException If an I/O error occurs. 82 | */ 83 | public static void writeFile(CompoundTag tag, File file) throws IOException { 84 | writeFile(tag, file, false); 85 | } 86 | 87 | /** 88 | * Writes the given root CompoundTag to the given file as stringified NBT. 89 | * 90 | * @param tag Tag to write. 91 | * @param path Path to write to. 92 | * @param linebreak Whether the SNBT file should be formated with line breaks or as a single line. 93 | * @throws java.io.IOException If an I/O error occurs. 94 | */ 95 | public static void writeFile(CompoundTag tag, String path, boolean linebreak) throws IOException { 96 | writeFile(tag, new File(path), linebreak); 97 | } 98 | 99 | /** 100 | * Writes the given root CompoundTag to the given file as stringified NBT. 101 | * 102 | * @param tag Tag to write. 103 | * @param file File to write to. 104 | * @param linebreak Whether the SNBT file should be formated with line breaks or as a single line. 105 | * @throws java.io.IOException If an I/O error occurs. 106 | */ 107 | public static void writeFile(CompoundTag tag, File file, boolean linebreak) throws IOException { 108 | if(!file.exists()) { 109 | if(file.getParentFile() != null && !file.getParentFile().exists()) { 110 | file.getParentFile().mkdirs(); 111 | } 112 | 113 | file.createNewFile(); 114 | } 115 | 116 | try (OutputStream out = new FileOutputStream(file)) { 117 | writeTag(out, tag, linebreak); 118 | } 119 | } 120 | 121 | /** 122 | * Reads a stringified NBT tag. 123 | * 124 | * @param in Input stream to read from. 125 | * @return The read tag, or null if the tag is an end tag. 126 | * @throws java.io.IOException If an I/O error occurs. 127 | */ 128 | public static Tag readTag(InputStream in) throws IOException { 129 | try (StringifiedNBTReader reader = new StringifiedNBTReader(in)) { 130 | return reader.readNextTag(""); 131 | } 132 | } 133 | 134 | /** 135 | * Writes a stringified NBT tag. 136 | * 137 | * @param out Output stream to write to. 138 | * @param tag Tag to write. 139 | * @throws java.io.IOException If an I/O error occurs. 140 | */ 141 | public static void writeTag(OutputStream out, Tag tag) throws IOException { 142 | writeTag(out, tag, false); 143 | } 144 | 145 | /** 146 | * Writes a stringified NBT tag. 147 | * 148 | * @param out Output stream to write to. 149 | * @param tag Tag to write. 150 | * @param linebreak Whether the SNBT should be formated with line breaks or as a single line. 151 | * @throws java.io.IOException If an I/O error occurs. 152 | */ 153 | public static void writeTag(OutputStream out, Tag tag, boolean linebreak) throws IOException { 154 | try (StringifiedNBTWriter writer = new StringifiedNBTWriter(out)) { 155 | writer.writeTag(tag, linebreak); 156 | } 157 | } 158 | 159 | public static class StringifiedNBTReader extends PushbackReader { 160 | public StringifiedNBTReader(InputStream in) { 161 | super(new InputStreamReader(in), 32); 162 | } 163 | 164 | public Tag readNextTag(String name) throws IOException { 165 | skipWhitespace(); 166 | if(lookAhead(0) == '{') { 167 | return readCompoundTag(name); 168 | } else if(lookAhead(0) == '[') { 169 | return readListOrArrayTag(name); 170 | } else { 171 | return readPrimitiveTag(name); 172 | } 173 | } 174 | 175 | public Tag readCompoundTag(String name) throws IOException { 176 | return parseTag(new CompoundTag(name)); 177 | } 178 | 179 | private Tag readListOrArrayTag(String name) throws IOException { 180 | if(lookAhead(2) == ';') { 181 | switch(lookAhead(1)) { 182 | case 'B': 183 | // Byte array 184 | return parseTag(new ByteArrayTag(name)); 185 | case 'S': 186 | // Short array 187 | return parseTag(new ShortArrayTag(name)); 188 | case 'I': 189 | // Integer array 190 | return parseTag(new IntArrayTag(name)); 191 | case 'L': 192 | // Long array 193 | return parseTag(new LongArrayTag(name)); 194 | case 'F': 195 | // Float array 196 | return parseTag(new FloatArrayTag(name)); 197 | case 'D': 198 | // Double array 199 | return parseTag(new DoubleArrayTag(name)); 200 | default: 201 | // Treat as list tag 202 | break; 203 | } 204 | } 205 | 206 | // This is a list tag 207 | return parseTag(new ListTag(name)); 208 | } 209 | 210 | private Tag readPrimitiveTag(String name) throws IOException { 211 | String valueString = readNextSingleValueString(32); 212 | unread(valueString.toCharArray()); 213 | return parseTag(getTagForStringifiedValue(name, valueString)); 214 | } 215 | 216 | public String readNextSingleValueString() throws IOException { 217 | return readNextSingleValueString(Integer.MAX_VALUE); 218 | } 219 | 220 | // Used when expecting to unread to limit read to the length of the pushback buffer. 221 | public String readNextSingleValueString(int maxReadLenght) throws IOException { 222 | String valueString; 223 | if(lookAhead(0) == '\'' || lookAhead(0) == '\"') { 224 | char c = (char) read(); 225 | valueString = c + readUntil(maxReadLenght, true, c); 226 | } else { 227 | valueString = readUntil(maxReadLenght, false, ',', '}', ']', '\r', '\n', '\t'); 228 | } 229 | return valueString; 230 | } 231 | 232 | static final Pattern byteTagValuePattern = Pattern.compile("[-+]?\\d+[bB]"); 233 | static final Pattern doubleTagValuePattern = Pattern.compile("[-+]?((\\d+(\\.\\d*)?)|(\\.\\d+))[dD]"); 234 | static final Pattern floatTagValuePattern = Pattern.compile("[-+]?((\\d+(\\.\\d*)?)|(\\.\\d+))[fF]"); 235 | static final Pattern intTagValuePattern = Pattern.compile("[-+]?\\d+"); 236 | static final Pattern longTagValuePattern = Pattern.compile("[-+]?\\d+[lL]"); 237 | static final Pattern shortTagValuePattern = Pattern.compile("[-+]?\\d+[sS]"); 238 | 239 | private Tag getTagForStringifiedValue(String name, String stringifiedValue) { 240 | if(byteTagValuePattern.matcher(stringifiedValue).matches()) { 241 | // Byte 242 | return new ByteTag(name); 243 | } else if(doubleTagValuePattern.matcher(stringifiedValue).matches()) { 244 | // Double 245 | return new DoubleTag(name); 246 | } else if(floatTagValuePattern.matcher(stringifiedValue).matches()) { 247 | // Float 248 | return new FloatTag(name); 249 | } else if(intTagValuePattern.matcher(stringifiedValue).matches()) { 250 | // Integer 251 | return new IntTag(name); 252 | } else if(longTagValuePattern.matcher(stringifiedValue).matches()) { 253 | // Long 254 | return new LongTag(name); 255 | } else if(shortTagValuePattern.matcher(stringifiedValue).matches()) { 256 | // Short 257 | return new ShortTag(name); 258 | } 259 | // String 260 | return new StringTag(name); 261 | } 262 | 263 | public Tag parseTag(Tag tag) throws IOException { 264 | tag.destringify(this); 265 | return tag; 266 | } 267 | 268 | public void skipWhitespace() throws IOException { 269 | char c; 270 | while((c = (char) read()) != -1) { 271 | if(c == '\t' || c == '\r' || c == '\n' || c == ' ') { 272 | continue; 273 | } else { 274 | unread(c); 275 | return; 276 | } 277 | } 278 | } 279 | 280 | public char readSkipWhitespace() throws IOException { 281 | skipWhitespace(); 282 | return (char) read(); 283 | } 284 | 285 | public String readUntil(boolean includeEndChar, char... endChar) throws IOException { 286 | return readUntil(Integer.MAX_VALUE, includeEndChar, endChar); 287 | } 288 | 289 | // Used when expecting to unread to limit read to the length of the pushback buffer. 290 | public String readUntil(int maxReadLenght, boolean includeEndChar, char... endChar) throws IOException { 291 | StringBuilder sb = new StringBuilder(); 292 | boolean escapeEnd = false; 293 | int reads = 0; 294 | char c; 295 | while(++reads < maxReadLenght && (c = (char) read()) != -1) { 296 | if(c == '\\') { 297 | sb.append(c); 298 | escapeEnd = true; 299 | continue; 300 | } 301 | if(!escapeEnd && matchesAny(c, endChar)) { 302 | if(includeEndChar) { 303 | sb.append(c); 304 | } else { 305 | unread(c); 306 | } 307 | break; 308 | } 309 | sb.append(c); 310 | escapeEnd = false; 311 | } 312 | return sb.toString(); 313 | } 314 | 315 | public char lookAhead(int offset) throws IOException { 316 | char[] future = new char[offset + 1]; 317 | read(future); 318 | unread(future); 319 | return future[offset]; 320 | } 321 | 322 | public static boolean matchesAny(char c, char[] matchable) { 323 | for(char m : matchable) { 324 | if(c == m) 325 | return true; 326 | } 327 | return false; 328 | } 329 | } 330 | 331 | public static class StringifiedNBTWriter extends OutputStreamWriter { 332 | 333 | public StringifiedNBTWriter(OutputStream out) { 334 | super(out); 335 | } 336 | 337 | public void writeTag(Tag tag, boolean linebreak) throws IOException { 338 | writeTag(tag, linebreak, 0); 339 | flush(); 340 | } 341 | 342 | public void writeTag(Tag tag, boolean linebreak, int depth) throws IOException { 343 | if(linebreak && depth > 0) { 344 | append('\n'); 345 | indent(depth); 346 | } 347 | 348 | if(tag.getName() != null && !tag.getName().equals("")) { 349 | appendTagName(tag.getName()); 350 | 351 | append(':'); 352 | append(' '); 353 | } 354 | 355 | if(tag instanceof CompoundTag) { 356 | tag.stringify(this, linebreak, depth); 357 | } else if(tag instanceof ListTag) { 358 | tag.stringify(this, linebreak, depth); 359 | } else { 360 | tag.stringify(this, linebreak, depth); 361 | } 362 | } 363 | 364 | public static Pattern nonEscapedTagName = Pattern.compile("(?!\\d+)[\\w\\d]*"); 365 | 366 | public void appendTagName(String tagName) throws IOException { 367 | if(!nonEscapedTagName.matcher(tagName).matches()) { 368 | append('"'); 369 | append(tagName.replaceAll("\\\"", "\\\"")); 370 | append('"'); 371 | } else { 372 | append(tagName); 373 | } 374 | } 375 | 376 | public void indent(int depth) throws IOException { 377 | for(int i = 0; i < depth; i++) { 378 | append('\t'); 379 | } 380 | } 381 | } 382 | } -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/ConversionException.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion; 2 | 3 | /** 4 | * An exception thrown when an error occurs while converting something. 5 | */ 6 | public class ConversionException extends RuntimeException { 7 | private static final long serialVersionUID = -2022049594558041160L; 8 | 9 | public ConversionException() { 10 | super(); 11 | } 12 | 13 | public ConversionException(String message) { 14 | super(message); 15 | } 16 | 17 | public ConversionException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public ConversionException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegisterException.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion; 2 | 3 | /** 4 | * An exception thrown when an error occurs while registering a converter. 5 | */ 6 | public class ConverterRegisterException extends RuntimeException { 7 | private static final long serialVersionUID = -2022049594558041160L; 8 | 9 | public ConverterRegisterException() { 10 | super(); 11 | } 12 | 13 | public ConverterRegisterException(String message) { 14 | super(message); 15 | } 16 | 17 | public ConverterRegisterException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public ConverterRegisterException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegistry.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion; 2 | 3 | import com.github.steveice10.opennbt.conversion.builtin.*; 4 | import com.github.steveice10.opennbt.conversion.builtin.custom.DoubleArrayTagConverter; 5 | import com.github.steveice10.opennbt.conversion.builtin.custom.FloatArrayTagConverter; 6 | import com.github.steveice10.opennbt.conversion.builtin.custom.ShortArrayTagConverter; 7 | import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; 8 | import com.github.steveice10.opennbt.tag.builtin.ByteTag; 9 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 10 | import com.github.steveice10.opennbt.tag.builtin.DoubleTag; 11 | import com.github.steveice10.opennbt.tag.builtin.FloatTag; 12 | import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; 13 | import com.github.steveice10.opennbt.tag.builtin.IntTag; 14 | import com.github.steveice10.opennbt.tag.builtin.ListTag; 15 | import com.github.steveice10.opennbt.tag.builtin.LongTag; 16 | import com.github.steveice10.opennbt.tag.builtin.ShortTag; 17 | import com.github.steveice10.opennbt.tag.builtin.StringTag; 18 | import com.github.steveice10.opennbt.tag.builtin.Tag; 19 | import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag; 20 | import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag; 21 | import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; 22 | import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag; 23 | 24 | import java.io.Serializable; 25 | import java.util.HashMap; 26 | import java.util.HashSet; 27 | import java.util.LinkedHashSet; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.Set; 31 | 32 | /** 33 | * A registry mapping tags and value types to converters. 34 | */ 35 | public class ConverterRegistry { 36 | private static final Map, TagConverter> tagToConverter = new HashMap, TagConverter>(); 37 | private static final Map, TagConverter> typeToConverter = new HashMap, TagConverter>(); 38 | 39 | static { 40 | register(ByteTag.class, Byte.class, new ByteTagConverter()); 41 | register(ShortTag.class, Short.class, new ShortTagConverter()); 42 | register(IntTag.class, Integer.class, new IntTagConverter()); 43 | register(LongTag.class, Long.class, new LongTagConverter()); 44 | register(FloatTag.class, Float.class, new FloatTagConverter()); 45 | register(DoubleTag.class, Double.class, new DoubleTagConverter()); 46 | register(ByteArrayTag.class, byte[].class, new ByteArrayTagConverter()); 47 | register(StringTag.class, String.class, new StringTagConverter()); 48 | register(ListTag.class, List.class, new ListTagConverter()); 49 | register(CompoundTag.class, Map.class, new CompoundTagConverter()); 50 | register(IntArrayTag.class, int[].class, new IntArrayTagConverter()); 51 | register(LongArrayTag.class, long[].class, new LongArrayTagConverter()); 52 | 53 | register(DoubleArrayTag.class, double[].class, new DoubleArrayTagConverter()); 54 | register(FloatArrayTag.class, float[].class, new FloatArrayTagConverter()); 55 | register(ShortArrayTag.class, short[].class, new ShortArrayTagConverter()); 56 | } 57 | 58 | /** 59 | * Registers a converter. 60 | * 61 | * @param Tag type to convert from. 62 | * @param Value type to convert to. 63 | * @param tag Tag type class to register the converter to. 64 | * @param type Value type class to register the converter to. 65 | * @param converter Converter to register. 66 | * @throws ConverterRegisterException If an error occurs while registering the converter. 67 | */ 68 | public static void register(Class tag, Class type, TagConverter converter) throws ConverterRegisterException { 69 | if(tagToConverter.containsKey(tag)) { 70 | throw new ConverterRegisterException("Type conversion to tag " + tag.getName() + " is already registered."); 71 | } 72 | 73 | if(typeToConverter.containsKey(type)) { 74 | throw new ConverterRegisterException("Tag conversion to type " + type.getName() + " is already registered."); 75 | } 76 | 77 | tagToConverter.put(tag, converter); 78 | typeToConverter.put(type, converter); 79 | } 80 | 81 | /** 82 | * Unregisters a converter. 83 | * 84 | * @param Tag type to unregister. 85 | * @param Value type to unregister. 86 | * @param tag Tag type class to unregister. 87 | * @param type Value type class to unregister. 88 | */ 89 | public static void unregister(Class tag, Class type) { 90 | tagToConverter.remove(tag); 91 | typeToConverter.remove(type); 92 | } 93 | 94 | /** 95 | * Converts the given tag to a value. 96 | * 97 | * @param Tag type to convert from. 98 | * @param Value type to convert to. 99 | * @param tag Tag to convert. 100 | * @return The converted value. 101 | * @throws ConversionException If a suitable converter could not be found. 102 | */ 103 | public static V convertToValue(T tag) throws ConversionException { 104 | if(tag == null || tag.getValue() == null) { 105 | return null; 106 | } 107 | 108 | if(!tagToConverter.containsKey(tag.getClass())) { 109 | throw new ConversionException("Tag type " + tag.getClass().getName() + " has no converter."); 110 | } 111 | 112 | TagConverter converter = (TagConverter) tagToConverter.get(tag.getClass()); 113 | return (V) converter.convert(tag); 114 | } 115 | 116 | /** 117 | * Converts the given value to a tag. 118 | * 119 | * @param Value type to convert from. 120 | * @param Tag type to convert to. 121 | * @param name Name of the resulting tag. 122 | * @param value Value to convert. 123 | * @return The converted tag. 124 | * @throws ConversionException If a suitable converter could not be found. 125 | */ 126 | public static T convertToTag(String name, V value) throws ConversionException { 127 | if(value == null) { 128 | return null; 129 | } 130 | 131 | TagConverter converter = (TagConverter) typeToConverter.get(value.getClass()); 132 | if(converter == null) { 133 | for(Class clazz : getAllClasses(value.getClass())) { 134 | if(typeToConverter.containsKey(clazz)) { 135 | try { 136 | converter = (TagConverter) typeToConverter.get(clazz); 137 | break; 138 | } catch(ClassCastException e) { 139 | } 140 | } 141 | } 142 | } 143 | 144 | if(converter == null) { 145 | throw new ConversionException("Value type " + value.getClass().getName() + " has no converter."); 146 | } 147 | 148 | return converter.convert(name, value); 149 | } 150 | 151 | private static Set> getAllClasses(Class clazz) { 152 | Set> ret = new LinkedHashSet>(); 153 | Class c = clazz; 154 | while(c != null) { 155 | ret.add(c); 156 | ret.addAll(getAllSuperInterfaces(c)); 157 | c = c.getSuperclass(); 158 | } 159 | 160 | // Make sure Serializable is at the end to avoid mix-ups. 161 | if(ret.contains(Serializable.class)) { 162 | ret.remove(Serializable.class); 163 | ret.add(Serializable.class); 164 | } 165 | 166 | return ret; 167 | } 168 | 169 | private static Set> getAllSuperInterfaces(Class clazz) { 170 | Set> ret = new HashSet>(); 171 | for(Class c : clazz.getInterfaces()) { 172 | ret.add(c); 173 | ret.addAll(getAllSuperInterfaces(c)); 174 | } 175 | 176 | return ret; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/TagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion; 2 | 3 | import com.github.steveice10.opennbt.tag.builtin.Tag; 4 | 5 | /** 6 | * A converter that converts between a tag type and a value type. A converted tag will have its value and all children converted to raw types and vice versa. 7 | * 8 | * @param Tag type. 9 | * @param Value type. 10 | */ 11 | public interface TagConverter { 12 | /** 13 | * Converts a tag to a value. 14 | * 15 | * @param tag Tag to convert. 16 | * @return The converted value. 17 | */ 18 | public V convert(T tag); 19 | 20 | /** 21 | * Converts a value to a tag. 22 | * 23 | * @param name Name of the tag. 24 | * @param value Value to convert. 25 | * @return The converted tag. 26 | */ 27 | public T convert(String name, V value); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteArrayTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; 5 | 6 | /** 7 | * A converter that converts between ByteArrayTag and byte[]. 8 | */ 9 | public class ByteArrayTagConverter implements TagConverter { 10 | @Override 11 | public byte[] convert(ByteArrayTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public ByteArrayTag convert(String name, byte[] value) { 17 | return new ByteArrayTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.ByteTag; 5 | 6 | /** 7 | * A converter that converts between ByteTag and byte. 8 | */ 9 | public class ByteTagConverter implements TagConverter { 10 | @Override 11 | public Byte convert(ByteTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public ByteTag convert(String name, Byte value) { 17 | return new ByteTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/CompoundTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.ConverterRegistry; 4 | import com.github.steveice10.opennbt.conversion.TagConverter; 5 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 6 | import com.github.steveice10.opennbt.tag.builtin.Tag; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * A converter that converts between CompoundTag and Map. 13 | */ 14 | public class CompoundTagConverter implements TagConverter { 15 | @Override 16 | public Map convert(CompoundTag tag) { 17 | Map ret = new HashMap(); 18 | Map tags = tag.getValue(); 19 | for(String name : tags.keySet()) { 20 | Tag t = tags.get(name); 21 | ret.put(t.getName(), ConverterRegistry.convertToValue(t)); 22 | } 23 | 24 | return ret; 25 | } 26 | 27 | @Override 28 | public CompoundTag convert(String name, Map value) { 29 | Map tags = new HashMap(); 30 | for(Object na : value.keySet()) { 31 | String n = (String) na; 32 | tags.put(n, ConverterRegistry.convertToTag(n, value.get(n))); 33 | } 34 | 35 | return new CompoundTag(name, tags); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/DoubleTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.DoubleTag; 5 | 6 | /** 7 | * A converter that converts between DoubleTag and double. 8 | */ 9 | public class DoubleTagConverter implements TagConverter { 10 | @Override 11 | public Double convert(DoubleTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public DoubleTag convert(String name, Double value) { 17 | return new DoubleTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/FloatTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.FloatTag; 5 | 6 | /** 7 | * A converter that converts between FloatTag and float. 8 | */ 9 | public class FloatTagConverter implements TagConverter { 10 | @Override 11 | public Float convert(FloatTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public FloatTag convert(String name, Float value) { 17 | return new FloatTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntArrayTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; 5 | 6 | /** 7 | * A converter that converts between IntArrayTag and int[]. 8 | */ 9 | public class IntArrayTagConverter implements TagConverter { 10 | @Override 11 | public int[] convert(IntArrayTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public IntArrayTag convert(String name, int[] value) { 17 | return new IntArrayTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.IntTag; 5 | 6 | /** 7 | * A converter that converts between IntTag and int. 8 | */ 9 | public class IntTagConverter implements TagConverter { 10 | @Override 11 | public Integer convert(IntTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public IntTag convert(String name, Integer value) { 17 | return new IntTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/ListTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.ConverterRegistry; 4 | import com.github.steveice10.opennbt.conversion.TagConverter; 5 | import com.github.steveice10.opennbt.tag.builtin.ListTag; 6 | import com.github.steveice10.opennbt.tag.builtin.Tag; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * A converter that converts between CompoundTag and Map. 13 | */ 14 | public class ListTagConverter implements TagConverter { 15 | @Override 16 | public List convert(ListTag tag) { 17 | List ret = new ArrayList(); 18 | List tags = tag.getValue(); 19 | for(Tag t : tags) { 20 | ret.add(ConverterRegistry.convertToValue(t)); 21 | } 22 | 23 | return ret; 24 | } 25 | 26 | @Override 27 | public ListTag convert(String name, List value) { 28 | List tags = new ArrayList(); 29 | for(Object o : value) { 30 | tags.add(ConverterRegistry.convertToTag("", o)); 31 | } 32 | 33 | return new ListTag(name, tags); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongArrayTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; 5 | 6 | /** 7 | * A converter that converts between LongArrayTag and long[]. 8 | */ 9 | public class LongArrayTagConverter implements TagConverter { 10 | @Override 11 | public long[] convert(LongArrayTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public LongArrayTag convert(String name, long[] value) { 17 | return new LongArrayTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.LongTag; 5 | 6 | /** 7 | * A converter that converts between LongTag and long. 8 | */ 9 | public class LongTagConverter implements TagConverter { 10 | @Override 11 | public Long convert(LongTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public LongTag convert(String name, Long value) { 17 | return new LongTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/ShortTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.ShortTag; 5 | 6 | /** 7 | * A converter that converts between ShortTag and short. 8 | */ 9 | public class ShortTagConverter implements TagConverter { 10 | @Override 11 | public Short convert(ShortTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public ShortTag convert(String name, Short value) { 17 | return new ShortTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/StringTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.StringTag; 5 | 6 | /** 7 | * A converter that converts between StringTag and String. 8 | */ 9 | public class StringTagConverter implements TagConverter { 10 | @Override 11 | public String convert(StringTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public StringTag convert(String name, String value) { 17 | return new StringTag(name, value); 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/custom/DoubleArrayTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin.custom; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag; 5 | 6 | /** 7 | * A converter that converts between DoubleArrayTag and double[]. 8 | */ 9 | public class DoubleArrayTagConverter implements TagConverter { 10 | @Override 11 | public double[] convert(DoubleArrayTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public DoubleArrayTag convert(String name, double[] value) { 17 | return new DoubleArrayTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/custom/FloatArrayTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin.custom; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag; 5 | 6 | /** 7 | * A converter that converts between FloatArrayTag and float[]. 8 | */ 9 | public class FloatArrayTagConverter implements TagConverter { 10 | @Override 11 | public float[] convert(FloatArrayTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public FloatArrayTag convert(String name, float[] value) { 17 | return new FloatArrayTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/conversion/builtin/custom/ShortArrayTagConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.conversion.builtin.custom; 2 | 3 | import com.github.steveice10.opennbt.conversion.TagConverter; 4 | import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag; 5 | 6 | /** 7 | * A converter that converts between ShortArrayTag and short[]. 8 | */ 9 | public class ShortArrayTagConverter implements TagConverter { 10 | @Override 11 | public short[] convert(ShortArrayTag tag) { 12 | return tag.getValue(); 13 | } 14 | 15 | @Override 16 | public ShortArrayTag convert(String name, short[] value) { 17 | return new ShortArrayTag(name, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/TagCreateException.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag; 2 | 3 | /** 4 | * An exception thrown when an error occurs while created a tag instance. 5 | */ 6 | public class TagCreateException extends Exception { 7 | private static final long serialVersionUID = -2022049594558041160L; 8 | 9 | public TagCreateException() { 10 | super(); 11 | } 12 | 13 | public TagCreateException(String message) { 14 | super(message); 15 | } 16 | 17 | public TagCreateException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public TagCreateException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/TagRegisterException.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag; 2 | 3 | /** 4 | * An exception thrown when an error occurs while registering a tag. 5 | */ 6 | public class TagRegisterException extends RuntimeException { 7 | private static final long serialVersionUID = -2022049594558041160L; 8 | 9 | public TagRegisterException() { 10 | super(); 11 | } 12 | 13 | public TagRegisterException(String message) { 14 | super(message); 15 | } 16 | 17 | public TagRegisterException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public TagRegisterException(String message, Throwable cause) { 22 | super(message, cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/TagRegistry.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag; 2 | 3 | import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; 4 | import com.github.steveice10.opennbt.tag.builtin.ByteTag; 5 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 6 | import com.github.steveice10.opennbt.tag.builtin.DoubleTag; 7 | import com.github.steveice10.opennbt.tag.builtin.FloatTag; 8 | import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; 9 | import com.github.steveice10.opennbt.tag.builtin.IntTag; 10 | import com.github.steveice10.opennbt.tag.builtin.ListTag; 11 | import com.github.steveice10.opennbt.tag.builtin.LongTag; 12 | import com.github.steveice10.opennbt.tag.builtin.ShortTag; 13 | import com.github.steveice10.opennbt.tag.builtin.StringTag; 14 | import com.github.steveice10.opennbt.tag.builtin.Tag; 15 | import com.github.steveice10.opennbt.tag.builtin.custom.DoubleArrayTag; 16 | import com.github.steveice10.opennbt.tag.builtin.custom.FloatArrayTag; 17 | import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; 18 | import com.github.steveice10.opennbt.tag.builtin.custom.ShortArrayTag; 19 | 20 | import java.lang.reflect.Constructor; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * A registry containing different tag classes. 26 | */ 27 | public class TagRegistry { 28 | private static final Map> idToTag = new HashMap>(); 29 | private static final Map, Integer> tagToId = new HashMap, Integer>(); 30 | 31 | static { 32 | register(1, ByteTag.class); 33 | register(2, ShortTag.class); 34 | register(3, IntTag.class); 35 | register(4, LongTag.class); 36 | register(5, FloatTag.class); 37 | register(6, DoubleTag.class); 38 | register(7, ByteArrayTag.class); 39 | register(8, StringTag.class); 40 | register(9, ListTag.class); 41 | register(10, CompoundTag.class); 42 | register(11, IntArrayTag.class); 43 | register(12, LongArrayTag.class); 44 | 45 | register(60, DoubleArrayTag.class); 46 | register(61, FloatArrayTag.class); 47 | register(65, ShortArrayTag.class); 48 | } 49 | 50 | /** 51 | * Registers a tag class. 52 | * 53 | * @param id ID of the tag. 54 | * @param tag Tag class to register. 55 | * @throws TagRegisterException If an error occurs while registering the tag. 56 | */ 57 | public static void register(int id, Class tag) throws TagRegisterException { 58 | if(idToTag.containsKey(id)) { 59 | throw new TagRegisterException("Tag ID \"" + id + "\" is already in use."); 60 | } 61 | 62 | if(tagToId.containsKey(tag)) { 63 | throw new TagRegisterException("Tag \"" + tag.getSimpleName() + "\" is already registered."); 64 | } 65 | 66 | idToTag.put(id, tag); 67 | tagToId.put(tag, id); 68 | } 69 | 70 | /** 71 | * Unregisters a tag class. 72 | * 73 | * @param id ID of the tag to unregister. 74 | */ 75 | public static void unregister(int id) { 76 | tagToId.remove(getClassFor(id)); 77 | idToTag.remove(id); 78 | } 79 | 80 | /** 81 | * Gets the tag class with the given id. 82 | * 83 | * @param id Id of the tag. 84 | * @return The tag class with the given id, or null if it cannot be found. 85 | */ 86 | public static Class getClassFor(int id) { 87 | if(!idToTag.containsKey(id)) { 88 | return null; 89 | } 90 | 91 | return idToTag.get(id); 92 | } 93 | 94 | /** 95 | * Gets the id of the given tag class. 96 | * 97 | * @param clazz The tag class to get the id of. 98 | * @return The id of the given tag class, or -1 if it cannot be found. 99 | */ 100 | public static int getIdFor(Class clazz) { 101 | if(!tagToId.containsKey(clazz)) { 102 | return -1; 103 | } 104 | 105 | return tagToId.get(clazz); 106 | } 107 | 108 | /** 109 | * Creates an instance of the tag with the given id, using the String constructor. 110 | * 111 | * @param id Id of the tag. 112 | * @param tagName Name to give the tag. 113 | * @return The created tag. 114 | * @throws TagCreateException If an error occurs while creating the tag. 115 | */ 116 | public static Tag createInstance(int id, String tagName) throws TagCreateException { 117 | Class clazz = idToTag.get(id); 118 | if(clazz == null) { 119 | throw new TagCreateException("Could not find tag with ID \"" + id + "\"."); 120 | } 121 | 122 | try { 123 | Constructor constructor = clazz.getDeclaredConstructor(String.class); 124 | constructor.setAccessible(true); 125 | return constructor.newInstance(tagName); 126 | } catch(Exception e) { 127 | throw new TagCreateException("Failed to create instance of tag \"" + clazz.getSimpleName() + "\".", e); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/ByteArrayTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a byte array. 12 | */ 13 | public class ByteArrayTag extends Tag { 14 | private byte[] value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public ByteArrayTag(String name) { 22 | this(name, new byte[0]); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public ByteArrayTag(String name, byte[] value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public byte[] getValue() { 38 | return this.value.clone(); 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(byte[] value) { 47 | if(value == null) { 48 | return; 49 | } 50 | 51 | this.value = value.clone(); 52 | } 53 | 54 | /** 55 | * Gets a value in this tag's array. 56 | * 57 | * @param index Index of the value. 58 | * @return The value at the given index. 59 | */ 60 | public byte getValue(int index) { 61 | return this.value[index]; 62 | } 63 | 64 | /** 65 | * Sets a value in this tag's array. 66 | * 67 | * @param index Index of the value. 68 | * @param value Value to set. 69 | */ 70 | public void setValue(int index, byte value) { 71 | this.value[index] = value; 72 | } 73 | 74 | /** 75 | * Gets the length of this tag's array. 76 | * 77 | * @return This tag's array length. 78 | */ 79 | public int length() { 80 | return this.value.length; 81 | } 82 | 83 | @Override 84 | public void read(DataInput in) throws IOException { 85 | this.value = new byte[in.readInt()]; 86 | in.readFully(this.value); 87 | } 88 | 89 | @Override 90 | public void write(DataOutput out) throws IOException { 91 | out.writeInt(this.value.length); 92 | out.write(this.value); 93 | } 94 | 95 | @Override 96 | public void destringify(StringifiedNBTReader in) throws IOException { 97 | String s = in.readUntil(true, ']'); 98 | String[] valueStrings = s.substring(s.indexOf(';') + 1, s.length() - 1).replaceAll(" ", "").split(","); 99 | value = new byte[valueStrings.length]; 100 | for(int i = 0; i < value.length; i++) { 101 | value[i] = Byte.parseByte(valueStrings[i]); 102 | } 103 | } 104 | 105 | @Override 106 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 107 | StringBuilder sb = new StringBuilder("[B; "); 108 | for(byte b : value) { 109 | sb.append(b); 110 | sb.append(','); 111 | sb.append(' '); 112 | } 113 | sb.setLength(sb.length() - 2); 114 | sb.append(']'); 115 | out.append(sb.toString()); 116 | } 117 | 118 | @Override 119 | public ByteArrayTag clone() { 120 | return new ByteArrayTag(this.getName(), this.getValue()); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/ByteTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a byte. 12 | */ 13 | public class ByteTag extends Tag { 14 | private byte value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public ByteTag(String name) { 22 | this(name, (byte) 0); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public ByteTag(String name, byte value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public Byte getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(byte value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readByte(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeByte(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | s = s.toLowerCase().substring(0, s.length() - 1); 64 | value = Byte.parseByte(s); 65 | } 66 | 67 | @Override 68 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 69 | StringBuilder sb = new StringBuilder(); 70 | sb.append(value); 71 | sb.append('b'); 72 | out.append(sb.toString()); 73 | } 74 | 75 | @Override 76 | public ByteTag clone() { 77 | return new ByteTag(this.getName(), this.getValue()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/CompoundTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.EOFException; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Iterator; 10 | import java.util.LinkedHashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Map.Entry; 14 | import java.util.Set; 15 | 16 | import com.github.steveice10.opennbt.NBTIO; 17 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 18 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 19 | 20 | /** 21 | * A compound tag containing other tags. 22 | */ 23 | public class CompoundTag extends Tag implements Iterable { 24 | private Map value; 25 | 26 | /** 27 | * Creates a tag with the specified name. 28 | * 29 | * @param name The name of the tag. 30 | */ 31 | public CompoundTag(String name) { 32 | this(name, new LinkedHashMap()); 33 | } 34 | 35 | /** 36 | * Creates a tag with the specified name. 37 | * 38 | * @param name The name of the tag. 39 | * @param value The value of the tag. 40 | */ 41 | public CompoundTag(String name, Map value) { 42 | super(name); 43 | this.value = new LinkedHashMap(value); 44 | } 45 | 46 | @Override 47 | public Map getValue() { 48 | return new LinkedHashMap(this.value); 49 | } 50 | 51 | /** 52 | * Sets the value of this tag. 53 | * 54 | * @param value New value of this tag. 55 | */ 56 | public void setValue(Map value) { 57 | this.value = new LinkedHashMap(value); 58 | } 59 | 60 | /** 61 | * Checks whether the compound tag is empty. 62 | * 63 | * @return Whether the compound tag is empty. 64 | */ 65 | public boolean isEmpty() { 66 | return this.value.isEmpty(); 67 | } 68 | 69 | /** 70 | * Checks whether the compound tag contains a tag with the specified name. 71 | * 72 | * @param tagName Name of the tag to check for. 73 | * @return Whether the compound tag contains a tag with the specified name. 74 | */ 75 | public boolean contains(String tagName) { 76 | return this.value.containsKey(tagName); 77 | } 78 | 79 | /** 80 | * Gets the tag with the specified name. 81 | * 82 | * @param Type of tag to get. 83 | * @param tagName Name of the tag. 84 | * @return The tag with the specified name. 85 | */ 86 | public T get(String tagName) { 87 | return (T) this.value.get(tagName); 88 | } 89 | 90 | /** 91 | * Puts the tag into this compound tag. 92 | * 93 | * @param Type of tag to put. 94 | * @param tag Tag to put into this compound tag. 95 | * @return The previous tag associated with its name, or null if there wasn't one. 96 | */ 97 | public T put(T tag) { 98 | return (T) this.value.put(tag.getName(), tag); 99 | } 100 | 101 | /** 102 | * Removes a tag from this compound tag. 103 | * 104 | * @param Type of tag to remove. 105 | * @param tagName Name of the tag to remove. 106 | * @return The removed tag. 107 | */ 108 | public T remove(String tagName) { 109 | return (T) this.value.remove(tagName); 110 | } 111 | 112 | /** 113 | * Gets a set of keys in this compound tag. 114 | * 115 | * @return The compound tag's key set. 116 | */ 117 | public Set keySet() { 118 | return this.value.keySet(); 119 | } 120 | 121 | /** 122 | * Gets a collection of tags in this compound tag. 123 | * 124 | * @return This compound tag's tags. 125 | */ 126 | public Collection values() { 127 | return this.value.values(); 128 | } 129 | 130 | /** 131 | * Gets the number of tags in this compound tag. 132 | * 133 | * @return This compound tag's size. 134 | */ 135 | public int size() { 136 | return this.value.size(); 137 | } 138 | 139 | /** 140 | * Clears all tags from this compound tag. 141 | */ 142 | public void clear() { 143 | this.value.clear(); 144 | } 145 | 146 | @Override 147 | public Iterator iterator() { 148 | return this.values().iterator(); 149 | } 150 | 151 | @Override 152 | public void read(DataInput in) throws IOException { 153 | List tags = new ArrayList(); 154 | try { 155 | Tag tag; 156 | while((tag = NBTIO.readTag(in)) != null) { 157 | tags.add(tag); 158 | } 159 | } catch(EOFException e) { 160 | throw new IOException("Closing EndTag was not found!"); 161 | } 162 | 163 | for(Tag tag : tags) { 164 | this.put(tag); 165 | } 166 | } 167 | 168 | @Override 169 | public void write(DataOutput out) throws IOException { 170 | for(Tag tag : this.value.values()) { 171 | NBTIO.writeTag(out, tag); 172 | } 173 | 174 | out.writeByte(0); 175 | } 176 | 177 | @Override 178 | public void destringify(StringifiedNBTReader in) throws IOException { 179 | in.readSkipWhitespace(); 180 | while(true) { 181 | String tagName = ""; 182 | if((tagName += in.readSkipWhitespace()).equals("\"")) { 183 | tagName = in.readUntil(false, '"'); 184 | in.read(); 185 | } 186 | tagName += in.readUntil(false, ':'); 187 | in.read(); 188 | 189 | put(in.readNextTag(tagName)); 190 | 191 | char endChar = in.readSkipWhitespace(); 192 | if(endChar == ',') 193 | continue; 194 | if(endChar == '}') 195 | break; 196 | } 197 | } 198 | 199 | @Override 200 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 201 | out.append('{'); 202 | 203 | boolean first = true; 204 | for(Tag t: value.values()) { 205 | if(first) { 206 | first = false; 207 | } else { 208 | out.append(','); 209 | if(!linebreak) { 210 | out.append(' '); 211 | } 212 | } 213 | out.writeTag(t, linebreak, depth + 1); 214 | } 215 | 216 | if(linebreak) { 217 | out.append('\n'); 218 | out.indent(depth); 219 | } 220 | out.append('}'); 221 | } 222 | 223 | @Override 224 | public CompoundTag clone() { 225 | Map newMap = new LinkedHashMap(); 226 | for(Entry entry : this.value.entrySet()) { 227 | newMap.put(entry.getKey(), entry.getValue().clone()); 228 | } 229 | 230 | return new CompoundTag(this.getName(), newMap); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/DoubleTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a double. 12 | */ 13 | public class DoubleTag extends Tag { 14 | private double value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public DoubleTag(String name) { 22 | this(name, 0); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public DoubleTag(String name, double value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public Double getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(double value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readDouble(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeDouble(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | s = s.toLowerCase().substring(0, s.length() - 1); 64 | value = Double.parseDouble(s); 65 | } 66 | 67 | @Override 68 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 69 | StringBuilder sb = new StringBuilder(); 70 | sb.append(value); 71 | sb.append('d'); 72 | out.append(sb.toString()); 73 | } 74 | 75 | @Override 76 | public DoubleTag clone() { 77 | return new DoubleTag(this.getName(), this.getValue()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/FloatTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a float. 12 | */ 13 | public class FloatTag extends Tag { 14 | private float value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public FloatTag(String name) { 22 | this(name, 0); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public FloatTag(String name, float value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public Float getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(float value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readFloat(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeFloat(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | s = s.toLowerCase().substring(0, s.length() - 1); 64 | value = Float.parseFloat(s); 65 | } 66 | 67 | @Override 68 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 69 | StringBuilder sb = new StringBuilder(); 70 | sb.append(value); 71 | sb.append('f'); 72 | out.append(sb.toString()); 73 | } 74 | 75 | @Override 76 | public FloatTag clone() { 77 | return new FloatTag(this.getName(), this.getValue()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/IntArrayTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing an integer array. 12 | */ 13 | public class IntArrayTag extends Tag { 14 | private int[] value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public IntArrayTag(String name) { 22 | this(name, new int[0]); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public IntArrayTag(String name, int[] value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public int[] getValue() { 38 | return this.value.clone(); 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(int[] value) { 47 | if(value == null) { 48 | return; 49 | } 50 | 51 | this.value = value.clone(); 52 | } 53 | 54 | /** 55 | * Gets a value in this tag's array. 56 | * 57 | * @param index Index of the value. 58 | * @return The value at the given index. 59 | */ 60 | public int getValue(int index) { 61 | return this.value[index]; 62 | } 63 | 64 | /** 65 | * Sets a value in this tag's array. 66 | * 67 | * @param index Index of the value. 68 | * @param value Value to set. 69 | */ 70 | public void setValue(int index, int value) { 71 | this.value[index] = value; 72 | } 73 | 74 | /** 75 | * Gets the length of this tag's array. 76 | * 77 | * @return This tag's array length. 78 | */ 79 | public int length() { 80 | return this.value.length; 81 | } 82 | 83 | @Override 84 | public void read(DataInput in) throws IOException { 85 | this.value = new int[in.readInt()]; 86 | for(int index = 0; index < this.value.length; index++) { 87 | this.value[index] = in.readInt(); 88 | } 89 | } 90 | 91 | @Override 92 | public void write(DataOutput out) throws IOException { 93 | out.writeInt(this.value.length); 94 | for(int index = 0; index < this.value.length; index++) { 95 | out.writeInt(this.value[index]); 96 | } 97 | } 98 | 99 | @Override 100 | public void destringify(StringifiedNBTReader in) throws IOException { 101 | String s = in.readUntil(true, ']'); 102 | String[] valueStrings = s.substring(s.indexOf(';') + 1, s.length() - 1).replaceAll(" ", "").split(","); 103 | value = new int[valueStrings.length]; 104 | for(int i = 0; i < value.length; i++) { 105 | value[i] = Integer.parseInt(valueStrings[i]); 106 | } 107 | } 108 | 109 | @Override 110 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 111 | StringBuilder sb = new StringBuilder("[I; "); 112 | for(int b : value) { 113 | sb.append(b); 114 | sb.append(','); 115 | sb.append(' '); 116 | } 117 | sb.setLength(sb.length() - 2); 118 | sb.append(']'); 119 | out.append(sb.toString()); 120 | } 121 | 122 | @Override 123 | public IntArrayTag clone() { 124 | return new IntArrayTag(this.getName(), this.getValue()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/IntTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing an integer. 12 | */ 13 | public class IntTag extends Tag { 14 | private int value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public IntTag(String name) { 22 | this(name, 0); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public IntTag(String name, int value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public Integer getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(int value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readInt(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeInt(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | value = Integer.parseInt(s); 64 | } 65 | 66 | @Override 67 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 68 | StringBuilder sb = new StringBuilder(); 69 | sb.append(value); 70 | out.append(sb.toString()); 71 | } 72 | 73 | @Override 74 | public IntTag clone() { 75 | return new IntTag(this.getName(), this.getValue()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/ListTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | 10 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 11 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 12 | import com.github.steveice10.opennbt.tag.TagCreateException; 13 | import com.github.steveice10.opennbt.tag.TagRegistry; 14 | 15 | /** 16 | * A tag containing a list of tags. 17 | */ 18 | public class ListTag extends Tag implements Iterable { 19 | private Class type; 20 | private List value; 21 | 22 | /** 23 | * Creates an empty list tag with the specified name and no defined type. 24 | * 25 | * @param name The name of the tag. 26 | */ 27 | public ListTag(String name) { 28 | super(name); 29 | 30 | this.type = null; 31 | this.value = new ArrayList(); 32 | } 33 | 34 | /** 35 | * Creates an empty list tag with the specified name and type. 36 | * 37 | * @param name The name of the tag. 38 | * @param type Tag type of the list. 39 | */ 40 | public ListTag(String name, Class type) { 41 | this(name); 42 | 43 | this.type = type; 44 | } 45 | 46 | /** 47 | * Creates a list tag with the specified name and value. 48 | * The list tag's type will be set to that of the first tag being added, or null if the given list is empty. 49 | * 50 | * @param name The name of the tag. 51 | * @param value The value of the tag. 52 | * @throws IllegalArgumentException If all tags in the list are not of the same type. 53 | */ 54 | public ListTag(String name, List value) throws IllegalArgumentException { 55 | this(name); 56 | 57 | this.setValue(value); 58 | } 59 | 60 | @Override 61 | public List getValue() { 62 | return new ArrayList(this.value); 63 | } 64 | 65 | /** 66 | * Sets the value of this tag. 67 | * The list tag's type will be set to that of the first tag being added, or null if the given list is empty. 68 | * 69 | * @param value New value of this tag. 70 | * @throws IllegalArgumentException If all tags in the list are not of the same type. 71 | */ 72 | public void setValue(List value) throws IllegalArgumentException { 73 | this.type = null; 74 | this.value.clear(); 75 | 76 | for(Tag tag : value) { 77 | this.add(tag); 78 | } 79 | } 80 | 81 | /** 82 | * Gets the element type of the ListTag. 83 | * 84 | * @return The ListTag's element type, or null if the list does not yet have a defined type. 85 | */ 86 | public Class getElementType() { 87 | return this.type; 88 | } 89 | 90 | /** 91 | * Adds a tag to this list tag. 92 | * If the list does not yet have a type, it will be set to the type of the tag being added. 93 | * 94 | * @param tag Tag to add. Should not be null. 95 | * @return If the list was changed as a result. 96 | * @throws IllegalArgumentException If the tag's type differs from the list tag's type. 97 | */ 98 | public boolean add(Tag tag) throws IllegalArgumentException { 99 | if(tag == null) { 100 | return false; 101 | } 102 | 103 | // If empty list, use this as tag type. 104 | if(this.type == null) { 105 | this.type = tag.getClass(); 106 | } else if(tag.getClass() != this.type) { 107 | throw new IllegalArgumentException("Tag type cannot differ from ListTag type."); 108 | } 109 | 110 | return this.value.add(tag); 111 | } 112 | 113 | /** 114 | * Removes a tag from this list tag. 115 | * 116 | * @param tag Tag to remove. 117 | * @return If the list contained the tag. 118 | */ 119 | public boolean remove(Tag tag) { 120 | return this.value.remove(tag); 121 | } 122 | 123 | /** 124 | * Gets the tag at the given index of this list tag. 125 | * 126 | * @param Type of tag to get 127 | * @param index Index of the tag. 128 | * @return The tag at the given index. 129 | */ 130 | public T get(int index) { 131 | return (T) this.value.get(index); 132 | } 133 | 134 | /** 135 | * Gets the number of tags in this list tag. 136 | * 137 | * @return The size of this list tag. 138 | */ 139 | public int size() { 140 | return this.value.size(); 141 | } 142 | 143 | @Override 144 | public Iterator iterator() { 145 | return this.value.iterator(); 146 | } 147 | 148 | @Override 149 | public void read(DataInput in) throws IOException { 150 | this.type = null; 151 | this.value.clear(); 152 | 153 | int id = in.readUnsignedByte(); 154 | if(id != 0) { 155 | this.type = TagRegistry.getClassFor(id); 156 | if(this.type == null) { 157 | throw new IOException("Unknown tag ID in ListTag: " + id); 158 | } 159 | } 160 | 161 | int count = in.readInt(); 162 | for(int index = 0; index < count; index++) { 163 | Tag tag = null; 164 | try { 165 | tag = TagRegistry.createInstance(id, ""); 166 | } catch(TagCreateException e) { 167 | throw new IOException("Failed to create tag.", e); 168 | } 169 | 170 | tag.read(in); 171 | this.add(tag); 172 | } 173 | } 174 | 175 | @Override 176 | public void write(DataOutput out) throws IOException { 177 | if(this.type == null) { 178 | out.writeByte(0); 179 | } else { 180 | int id = TagRegistry.getIdFor(this.type); 181 | if(id == -1) { 182 | throw new IOException("ListTag contains unregistered tag class."); 183 | } 184 | 185 | out.writeByte(id); 186 | } 187 | 188 | out.writeInt(this.value.size()); 189 | for(Tag tag : this.value) { 190 | tag.write(out); 191 | } 192 | } 193 | 194 | @Override 195 | public void destringify(StringifiedNBTReader in) throws IOException { 196 | in.readSkipWhitespace(); 197 | while(true) { 198 | add(in.readNextTag("")); 199 | 200 | char endChar = in.readSkipWhitespace(); 201 | if(endChar == ',') 202 | continue; 203 | if(endChar == ']') 204 | break; 205 | } 206 | } 207 | 208 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 209 | out.append('['); 210 | 211 | boolean first = true; 212 | for(Tag t: value) { 213 | if(first) { 214 | first = false; 215 | } else { 216 | out.append(','); 217 | if(!linebreak) { 218 | out.append(' '); 219 | } 220 | } 221 | out.writeTag(t, linebreak, depth + 1); 222 | } 223 | 224 | if(linebreak) { 225 | out.append('\n'); 226 | out.indent(depth); 227 | } 228 | out.append(']'); 229 | } 230 | 231 | @Override 232 | public ListTag clone() { 233 | List newList = new ArrayList(); 234 | for(Tag value : this.value) { 235 | newList.add(value.clone()); 236 | } 237 | 238 | return new ListTag(this.getName(), newList); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/LongArrayTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a long array. 12 | */ 13 | public class LongArrayTag extends Tag { 14 | private long[] value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public LongArrayTag(String name) { 22 | this(name, new long[0]); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public LongArrayTag(String name, long[] value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public long[] getValue() { 38 | return this.value.clone(); 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(long[] value) { 47 | if(value == null) { 48 | return; 49 | } 50 | 51 | this.value = value.clone(); 52 | } 53 | 54 | /** 55 | * Gets a value in this tag's array. 56 | * 57 | * @param index Index of the value. 58 | * @return The value at the given index. 59 | */ 60 | public long getValue(int index) { 61 | return this.value[index]; 62 | } 63 | 64 | /** 65 | * Sets a value in this tag's array. 66 | * 67 | * @param index Index of the value. 68 | * @param value Value to set. 69 | */ 70 | public void setValue(int index, long value) { 71 | this.value[index] = value; 72 | } 73 | 74 | /** 75 | * Gets the length of this tag's array. 76 | * 77 | * @return This tag's array length. 78 | */ 79 | public int length() { 80 | return this.value.length; 81 | } 82 | 83 | @Override 84 | public void read(DataInput in) throws IOException { 85 | this.value = new long[in.readInt()]; 86 | for(int index = 0; index < this.value.length; index++) { 87 | this.value[index] = in.readLong(); 88 | } 89 | } 90 | 91 | @Override 92 | public void write(DataOutput out) throws IOException { 93 | out.writeInt(this.value.length); 94 | for(int index = 0; index < this.value.length; index++) { 95 | out.writeLong(this.value[index]); 96 | } 97 | } 98 | 99 | @Override 100 | public void destringify(StringifiedNBTReader in) throws IOException { 101 | String s = in.readUntil(true, ']'); 102 | String[] valueStrings = s.substring(s.indexOf(';') + 1, s.length() - 1).replaceAll(" ", "").split(","); 103 | value = new long[valueStrings.length]; 104 | for(int i = 0; i < value.length; i++) { 105 | value[i] = Long.parseLong(valueStrings[i]); 106 | } 107 | } 108 | 109 | @Override 110 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 111 | StringBuilder sb = new StringBuilder("[L; "); 112 | for(long b : value) { 113 | sb.append(b); 114 | sb.append(','); 115 | sb.append(' '); 116 | } 117 | sb.setLength(sb.length() - 2); 118 | sb.append(']'); 119 | out.append(sb.toString()); 120 | } 121 | 122 | @Override 123 | public LongArrayTag clone() { 124 | return new LongArrayTag(this.getName(), this.getValue()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/LongTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a long. 12 | */ 13 | public class LongTag extends Tag { 14 | private long value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public LongTag(String name) { 22 | this(name, 0); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public LongTag(String name, long value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public Long getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(long value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readLong(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeLong(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | s = s.toLowerCase().substring(0, s.length() - 1); 64 | value = Long.parseLong(s); 65 | } 66 | 67 | @Override 68 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 69 | StringBuilder sb = new StringBuilder(); 70 | sb.append(value); 71 | sb.append('l'); 72 | out.append(sb.toString()); 73 | } 74 | 75 | @Override 76 | public LongTag clone() { 77 | return new LongTag(this.getName(), this.getValue()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/ShortTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a short. 12 | */ 13 | public class ShortTag extends Tag { 14 | private short value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public ShortTag(String name) { 22 | this(name, (short) 0); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public ShortTag(String name, short value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public Short getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(short value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readShort(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeShort(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | s = s.toLowerCase().substring(0, s.length() - 1); 64 | value = Short.parseShort(s); 65 | } 66 | 67 | @Override 68 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 69 | StringBuilder sb = new StringBuilder(); 70 | sb.append(value); 71 | sb.append('s'); 72 | out.append(sb.toString()); 73 | } 74 | 75 | @Override 76 | public ShortTag clone() { 77 | return new ShortTag(this.getName(), this.getValue()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/StringTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | 10 | /** 11 | * A tag containing a string. 12 | */ 13 | public class StringTag extends Tag { 14 | private String value; 15 | 16 | /** 17 | * Creates a tag with the specified name. 18 | * 19 | * @param name The name of the tag. 20 | */ 21 | public StringTag(String name) { 22 | this(name, ""); 23 | } 24 | 25 | /** 26 | * Creates a tag with the specified name. 27 | * 28 | * @param name The name of the tag. 29 | * @param value The value of the tag. 30 | */ 31 | public StringTag(String name, String value) { 32 | super(name); 33 | this.value = value; 34 | } 35 | 36 | @Override 37 | public String getValue() { 38 | return this.value; 39 | } 40 | 41 | /** 42 | * Sets the value of this tag. 43 | * 44 | * @param value New value of this tag. 45 | */ 46 | public void setValue(String value) { 47 | this.value = value; 48 | } 49 | 50 | @Override 51 | public void read(DataInput in) throws IOException { 52 | this.value = in.readUTF(); 53 | } 54 | 55 | @Override 56 | public void write(DataOutput out) throws IOException { 57 | out.writeUTF(this.value); 58 | } 59 | 60 | @Override 61 | public void destringify(StringifiedNBTReader in) throws IOException { 62 | String s = in.readNextSingleValueString(); 63 | if(s.charAt(0) == '"') { 64 | value = s.substring(1, s.length() - 1).replaceAll("\\\\\"", "\""); 65 | } else if(s.charAt(0) == '\'') { 66 | value = s.substring(1, s.length() - 1).replaceAll("\\\\\'", "'"); 67 | } else { 68 | value = s; 69 | } 70 | } 71 | 72 | @Override 73 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 74 | if(value.matches("(?!\\d+)[\\w\\d]*")) { 75 | out.append(value); 76 | return; 77 | } 78 | if(value.contains("\"")) { 79 | if(value.contains("'")) { 80 | StringBuilder sb = new StringBuilder("\""); 81 | sb.append(value.replaceAll("\"", "\\\\\"")); 82 | sb.append("\""); 83 | out.append(sb.toString()); 84 | return; 85 | } 86 | StringBuilder sb = new StringBuilder("'"); 87 | sb.append(value); 88 | sb.append("'"); 89 | out.append(sb.toString()); 90 | return; 91 | } 92 | StringBuilder sb = new StringBuilder("\""); 93 | sb.append(value); 94 | sb.append("\""); 95 | out.append(sb.toString()); 96 | } 97 | 98 | @Override 99 | public StringTag clone() { 100 | return new StringTag(this.getName(), this.getValue()); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/Tag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | import java.io.OutputStreamWriter; 7 | import java.lang.reflect.Array; 8 | 9 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 10 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 11 | 12 | /** 13 | * Represents an NBT tag. 14 | *

15 | * All tags must have a constructor with a single string parameter for reading tags (can be any visibility). 16 | * Tags should also have setter methods specific to their value types. 17 | */ 18 | public abstract class Tag implements Cloneable { 19 | private String name; 20 | 21 | /** 22 | * Creates a tag with the specified name. 23 | * 24 | * @param name The name. 25 | */ 26 | public Tag(String name) { 27 | this.name = name; 28 | } 29 | 30 | /** 31 | * Gets the name of this tag. 32 | * 33 | * @return The name of this tag. 34 | */ 35 | public final String getName() { 36 | return this.name; 37 | } 38 | 39 | /** 40 | * Gets the value of this tag. 41 | * 42 | * @return The value of this tag. 43 | */ 44 | public abstract Object getValue(); 45 | 46 | /** 47 | * Reads this tag from an input stream. 48 | * 49 | * @param in Stream to read from. 50 | * @throws java.io.IOException If an I/O error occurs. 51 | */ 52 | public abstract void read(DataInput in) throws IOException; 53 | 54 | /** 55 | * Writes this tag to an output stream. 56 | * 57 | * @param out Stream to write to. 58 | * @throws java.io.IOException If an I/O error occurs. 59 | */ 60 | public abstract void write(DataOutput out) throws IOException; 61 | 62 | /** 63 | * Parses this tag from stringified NBT. 64 | * 65 | * @param in String to parse. 66 | */ 67 | public abstract void destringify(StringifiedNBTReader in) throws IOException; 68 | 69 | /** 70 | * Write this tag as stringified NBT. 71 | */ 72 | public abstract void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException; 73 | 74 | @Override 75 | public abstract Tag clone(); 76 | 77 | @Override 78 | public boolean equals(Object obj) { 79 | if(!(obj instanceof Tag)) { 80 | return false; 81 | } 82 | 83 | Tag tag = (Tag) obj; 84 | if(!this.getName().equals(tag.getName())) { 85 | return false; 86 | } 87 | 88 | if(this.getValue() == null) { 89 | return tag.getValue() == null; 90 | } else if(tag.getValue() == null) { 91 | return false; 92 | } 93 | 94 | if(this.getValue().getClass().isArray() && tag.getValue().getClass().isArray()) { 95 | int length = Array.getLength(this.getValue()); 96 | if(Array.getLength(tag.getValue()) != length) { 97 | return false; 98 | } 99 | 100 | for(int index = 0; index < length; index++) { 101 | Object o = Array.get(this.getValue(), index); 102 | Object other = Array.get(tag.getValue(), index); 103 | if(o == null && other != null || o != null && !o.equals(other)) { 104 | return false; 105 | } 106 | } 107 | 108 | return true; 109 | } 110 | 111 | return this.getValue().equals(tag.getValue()); 112 | } 113 | 114 | @Override 115 | public String toString() { 116 | String name = this.getName() != null && !this.getName().equals("") ? "(" + this.getName() + ")" : ""; 117 | String value = ""; 118 | if(this.getValue() != null) { 119 | value = this.getValue().toString(); 120 | if(this.getValue().getClass().isArray()) { 121 | StringBuilder build = new StringBuilder(); 122 | build.append("["); 123 | for(int index = 0; index < Array.getLength(this.getValue()); index++) { 124 | if(index > 0) { 125 | build.append(", "); 126 | } 127 | 128 | build.append(Array.get(this.getValue(), index)); 129 | } 130 | 131 | build.append("]"); 132 | value = build.toString(); 133 | } 134 | } 135 | 136 | return this.getClass().getSimpleName() + name + " { " + value + " }"; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/custom/DoubleArrayTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin.custom; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | import com.github.steveice10.opennbt.tag.builtin.Tag; 10 | 11 | /** 12 | * A tag containing a double array. 13 | */ 14 | public class DoubleArrayTag extends Tag { 15 | private double[] value; 16 | 17 | /** 18 | * Creates a tag with the specified name. 19 | * 20 | * @param name The name of the tag. 21 | */ 22 | public DoubleArrayTag(String name) { 23 | this(name, new double[0]); 24 | } 25 | 26 | /** 27 | * Creates a tag with the specified name. 28 | * 29 | * @param name The name of the tag. 30 | * @param value The value of the tag. 31 | */ 32 | public DoubleArrayTag(String name, double[] value) { 33 | super(name); 34 | this.value = value; 35 | } 36 | 37 | @Override 38 | public double[] getValue() { 39 | return this.value.clone(); 40 | } 41 | 42 | /** 43 | * Sets the value of this tag. 44 | * 45 | * @param value New value of this tag. 46 | */ 47 | public void setValue(double[] value) { 48 | if(value == null) { 49 | return; 50 | } 51 | 52 | this.value = value.clone(); 53 | } 54 | 55 | /** 56 | * Gets a value in this tag's array. 57 | * 58 | * @param index Index of the value. 59 | * @return The value at the given index. 60 | */ 61 | public double getValue(int index) { 62 | return this.value[index]; 63 | } 64 | 65 | /** 66 | * Sets a value in this tag's array. 67 | * 68 | * @param index Index of the value. 69 | * @param value Value to set. 70 | */ 71 | public void setValue(int index, double value) { 72 | this.value[index] = value; 73 | } 74 | 75 | /** 76 | * Gets the length of this tag's array. 77 | * 78 | * @return This tag's array length. 79 | */ 80 | public int length() { 81 | return this.value.length; 82 | } 83 | 84 | @Override 85 | public void read(DataInput in) throws IOException { 86 | this.value = new double[in.readInt()]; 87 | for(int index = 0; index < this.value.length; index++) { 88 | this.value[index] = in.readDouble(); 89 | } 90 | } 91 | 92 | @Override 93 | public void write(DataOutput out) throws IOException { 94 | out.writeInt(this.value.length); 95 | for(int index = 0; index < this.value.length; index++) { 96 | out.writeDouble(this.value[index]); 97 | } 98 | } 99 | 100 | @Override 101 | public void destringify(StringifiedNBTReader in) throws IOException { 102 | String s = in.readUntil(true, ']'); 103 | String[] valueStrings = s.substring(s.indexOf(';') + 1, s.length() - 1).replaceAll(" ", "").split(","); 104 | value = new double[valueStrings.length]; 105 | for(int i = 0; i < value.length; i++) { 106 | value[i] = Double.parseDouble(valueStrings[i]); 107 | } 108 | } 109 | 110 | @Override 111 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 112 | StringBuilder sb = new StringBuilder("[D; "); 113 | for(double b : value) { 114 | sb.append(b); 115 | sb.append(','); 116 | sb.append(' '); 117 | } 118 | sb.setLength(sb.length() - 2); 119 | sb.append(']'); 120 | out.append(sb.toString()); 121 | } 122 | 123 | @Override 124 | public DoubleArrayTag clone() { 125 | return new DoubleArrayTag(this.getName(), this.getValue()); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/custom/FloatArrayTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin.custom; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | import com.github.steveice10.opennbt.tag.builtin.Tag; 10 | 11 | /** 12 | * A tag containing a float array. 13 | */ 14 | public class FloatArrayTag extends Tag { 15 | private float[] value; 16 | 17 | /** 18 | * Creates a tag with the specified name. 19 | * 20 | * @param name The name of the tag. 21 | */ 22 | public FloatArrayTag(String name) { 23 | this(name, new float[0]); 24 | } 25 | 26 | /** 27 | * Creates a tag with the specified name. 28 | * 29 | * @param name The name of the tag. 30 | * @param value The value of the tag. 31 | */ 32 | public FloatArrayTag(String name, float[] value) { 33 | super(name); 34 | this.value = value; 35 | } 36 | 37 | @Override 38 | public float[] getValue() { 39 | return this.value.clone(); 40 | } 41 | 42 | /** 43 | * Sets the value of this tag. 44 | * 45 | * @param value New value of this tag. 46 | */ 47 | public void setValue(float[] value) { 48 | if(value == null) { 49 | return; 50 | } 51 | 52 | this.value = value.clone(); 53 | } 54 | 55 | /** 56 | * Gets a value in this tag's array. 57 | * 58 | * @param index Index of the value. 59 | * @return The value at the given index. 60 | */ 61 | public float getValue(int index) { 62 | return this.value[index]; 63 | } 64 | 65 | /** 66 | * Sets a value in this tag's array. 67 | * 68 | * @param index Index of the value. 69 | * @param value Value to set. 70 | */ 71 | public void setValue(int index, float value) { 72 | this.value[index] = value; 73 | } 74 | 75 | /** 76 | * Gets the length of this tag's array. 77 | * 78 | * @return This tag's array length. 79 | */ 80 | public int length() { 81 | return this.value.length; 82 | } 83 | 84 | @Override 85 | public void read(DataInput in) throws IOException { 86 | this.value = new float[in.readInt()]; 87 | for(int index = 0; index < this.value.length; index++) { 88 | this.value[index] = in.readFloat(); 89 | } 90 | } 91 | 92 | @Override 93 | public void write(DataOutput out) throws IOException { 94 | out.writeInt(this.value.length); 95 | for(int index = 0; index < this.value.length; index++) { 96 | out.writeFloat(this.value[index]); 97 | } 98 | } 99 | 100 | @Override 101 | public void destringify(StringifiedNBTReader in) throws IOException { 102 | String s = in.readUntil(true, ']'); 103 | String[] valueStrings = s.substring(s.indexOf(';') + 1, s.length() - 1).replaceAll(" ", "").split(","); 104 | value = new float[valueStrings.length]; 105 | for(int i = 0; i < value.length; i++) { 106 | value[i] = Float.parseFloat(valueStrings[i]); 107 | } 108 | } 109 | 110 | @Override 111 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 112 | StringBuilder sb = new StringBuilder("[F; "); 113 | for(float b : value) { 114 | sb.append(b); 115 | sb.append(','); 116 | sb.append(' '); 117 | } 118 | sb.setLength(sb.length() - 2); 119 | sb.append(']'); 120 | out.append(sb.toString()); 121 | } 122 | 123 | @Override 124 | public FloatArrayTag clone() { 125 | return new FloatArrayTag(this.getName(), this.getValue()); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/github/steveice10/opennbt/tag/builtin/custom/ShortArrayTag.java: -------------------------------------------------------------------------------- 1 | package com.github.steveice10.opennbt.tag.builtin.custom; 2 | 3 | import java.io.DataInput; 4 | import java.io.DataOutput; 5 | import java.io.IOException; 6 | 7 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTReader; 8 | import com.github.steveice10.opennbt.SNBTIO.StringifiedNBTWriter; 9 | import com.github.steveice10.opennbt.tag.builtin.Tag; 10 | 11 | /** 12 | * A tag containing a short array. 13 | */ 14 | public class ShortArrayTag extends Tag { 15 | private short[] value; 16 | 17 | /** 18 | * Creates a tag with the specified name. 19 | * 20 | * @param name The name of the tag. 21 | */ 22 | public ShortArrayTag(String name) { 23 | this(name, new short[0]); 24 | } 25 | 26 | /** 27 | * Creates a tag with the specified name. 28 | * 29 | * @param name The name of the tag. 30 | * @param value The value of the tag. 31 | */ 32 | public ShortArrayTag(String name, short[] value) { 33 | super(name); 34 | this.value = value; 35 | } 36 | 37 | @Override 38 | public short[] getValue() { 39 | return this.value.clone(); 40 | } 41 | 42 | /** 43 | * Sets the value of this tag. 44 | * 45 | * @param value New value of this tag. 46 | */ 47 | public void setValue(short[] value) { 48 | if(value == null) { 49 | return; 50 | } 51 | 52 | this.value = value.clone(); 53 | } 54 | 55 | /** 56 | * Gets a value in this tag's array. 57 | * 58 | * @param index Index of the value. 59 | * @return The value at the given index. 60 | */ 61 | public short getValue(int index) { 62 | return this.value[index]; 63 | } 64 | 65 | /** 66 | * Sets a value in this tag's array. 67 | * 68 | * @param index Index of the value. 69 | * @param value Value to set. 70 | */ 71 | public void setValue(int index, short value) { 72 | this.value[index] = value; 73 | } 74 | 75 | /** 76 | * Gets the length of this tag's array. 77 | * 78 | * @return This tag's array length. 79 | */ 80 | public int length() { 81 | return this.value.length; 82 | } 83 | 84 | @Override 85 | public void read(DataInput in) throws IOException { 86 | this.value = new short[in.readInt()]; 87 | for(int index = 0; index < this.value.length; index++) { 88 | this.value[index] = in.readShort(); 89 | } 90 | } 91 | 92 | @Override 93 | public void write(DataOutput out) throws IOException { 94 | out.writeInt(this.value.length); 95 | for(int index = 0; index < this.value.length; index++) { 96 | out.writeShort(this.value[index]); 97 | } 98 | } 99 | 100 | @Override 101 | public void destringify(StringifiedNBTReader in) throws IOException { 102 | String s = in.readUntil(true, ']'); 103 | String[] valueStrings = s.substring(s.indexOf(';') + 1, s.length() - 1).replaceAll(" ", "").split(","); 104 | value = new short[valueStrings.length]; 105 | for(int i = 0; i < value.length; i++) { 106 | value[i] = Short.parseShort(valueStrings[i]); 107 | } 108 | } 109 | 110 | @Override 111 | public void stringify(StringifiedNBTWriter out, boolean linebreak, int depth) throws IOException { 112 | StringBuilder sb = new StringBuilder("[S; "); 113 | for(short b : value) { 114 | sb.append(b); 115 | sb.append(','); 116 | sb.append(' '); 117 | } 118 | sb.setLength(sb.length() - 2); 119 | sb.append(']'); 120 | out.append(sb.toString()); 121 | } 122 | 123 | @Override 124 | public ShortArrayTag clone() { 125 | return new ShortArrayTag(this.getName(), this.getValue()); 126 | } 127 | } 128 | --------------------------------------------------------------------------------