1 // Package nbt implements a full Named Binary Tag reader/writer, based on the specs at 2 // http://web.archive.org/web/20110723210920/http://www.minecraft.net/docs/NBT.txt 3 package nbt 4 5 import "strconv" 6 7 // Tag Types 8 const ( 9 TagEnd TagID = 0 10 TagByte TagID = 1 11 TagShort TagID = 2 12 TagInt TagID = 3 13 TagLong TagID = 4 14 TagFloat TagID = 5 15 TagDouble TagID = 6 16 TagByteArray TagID = 7 17 TagString TagID = 8 18 TagList TagID = 9 19 TagCompound TagID = 10 20 TagIntArray TagID = 11 21 TagBool TagID = 12 22 TagUint8 TagID = 13 23 TagUint16 TagID = 14 24 TagUint32 TagID = 15 25 TagUint64 TagID = 16 26 TagComplex64 TagID = 17 27 TagComplex128 TagID = 18 28 ) 29 30 var tagIDNames = [...]string{ 31 "End", 32 "Byte", 33 "Short", 34 "Int", 35 "Long", 36 "Float", 37 "Double", 38 "Byte Array", 39 "String", 40 "List", 41 "Compound", 42 "Int Array", 43 } 44 45 // TagID represents the type of nbt tag 46 type TagID uint8 47 48 func (t TagID) String() string { 49 if int(t) < len(tagIDNames) { 50 return tagIDNames[t] 51 } 52 return "" 53 } 54 55 // Data is an interface representing the many different types that a tag can be 56 type Data interface { 57 Equal(interface{}) bool 58 Copy() Data 59 String() string 60 Type() TagID 61 } 62 63 // Tag is the main NBT type, a combination of a name and a Data type 64 type Tag struct { 65 name string 66 data Data 67 } 68 69 // NewTag constructs a new tag with the given name and data. 70 func NewTag(name string, d Data) Tag { 71 return Tag{ 72 name: name, 73 data: d, 74 } 75 } 76 77 // Copy simply returns a deep-copy the the tag 78 func (t Tag) Copy() Tag { 79 return Tag{ 80 t.name, 81 t.data.Copy(), 82 } 83 } 84 85 // Equal satisfies the equaler.Equaler interface, allowing for types to be 86 // checked for equality 87 func (t Tag) Equal(e interface{}) bool { 88 if m, ok := e.(Tag); ok { 89 if t.data.Type() == m.data.Type() && t.name == m.name { 90 return t.data.Equal(m.data) 91 } 92 } 93 return false 94 } 95 96 // Data returns the tags data type 97 func (t Tag) Data() Data { 98 if t.data == nil { 99 return end{} 100 } 101 return t.data 102 } 103 104 // Name returns the tags' name 105 func (t Tag) Name() string { 106 return t.name 107 } 108 109 // TagID returns the type of the data 110 func (t Tag) TagID() TagID { 111 if t.data == nil { 112 return TagEnd 113 } 114 return t.data.Type() 115 } 116 117 // String returns a textual representation of the tag 118 func (t Tag) String() string { 119 return t.data.Type().String() + "(" + strconv.Quote(t.name) + "): " + t.data.String() 120 } 121 122 type end struct{} 123 124 func (end) Copy() Data { 125 return &end{} 126 } 127 128 func (end) Equal(e interface{}) bool { 129 _, ok := e.(end) 130 return ok 131 } 132 133 func (end) Type() TagID { 134 return TagEnd 135 } 136 137 func (end) String() string { 138 return "" 139 } 140 141 // Byte is an implementation of the Data interface 142 // NB: Despite being an unsigned integer, it is still called a byte to match 143 // the spec. 144 type Byte int8 145 146 // Copy simply returns a copy the the data 147 func (b Byte) Copy() Data { 148 return b 149 } 150 151 // Equal satisfies the equaler.Equaler interface, allowing for types to be 152 // checked for equality 153 func (b Byte) Equal(e interface{}) bool { 154 if m, ok := e.(Byte); ok { 155 return b == m 156 } 157 return false 158 } 159 160 func (b Byte) String() string { 161 return strconv.FormatInt(int64(b), 10) 162 } 163 164 // Type returns the TagID of the data 165 func (Byte) Type() TagID { 166 return TagByte 167 } 168 169 // Short is an implementation of the Data interface 170 type Short int16 171 172 // Copy simply returns a copy the the data 173 func (s Short) Copy() Data { 174 return s 175 } 176 177 // Equal satisfies the equaler.Equaler interface, allowing for types to be 178 // checked for equality 179 func (s Short) Equal(e interface{}) bool { 180 if m, ok := e.(Short); ok { 181 return s == m 182 } 183 return false 184 } 185 186 func (s Short) String() string { 187 return strconv.FormatInt(int64(s), 10) 188 } 189 190 // Type returns the TagID of the data 191 func (Short) Type() TagID { 192 return TagShort 193 } 194 195 // Int is an implementation of the Data interface 196 type Int int32 197 198 // Copy simply returns a copy the the data 199 func (i Int) Copy() Data { 200 return i 201 } 202 203 // Equal satisfies the equaler.Equaler interface, allowing for types to be 204 // checked for equality 205 func (i Int) Equal(e interface{}) bool { 206 if m, ok := e.(Int); ok { 207 return i == m 208 } 209 return false 210 } 211 212 func (i Int) String() string { 213 return strconv.FormatInt(int64(i), 10) 214 } 215 216 // Type returns the TagID of the data 217 func (Int) Type() TagID { 218 return TagInt 219 } 220 221 // Long is an implementation of the Data interface 222 type Long int64 223 224 // Copy simply returns a copy the the data 225 func (l Long) Copy() Data { 226 return l 227 } 228 229 // Equal satisfies the equaler.Equaler interface, allowing for types to be 230 // checked for equality 231 func (l Long) Equal(e interface{}) bool { 232 if m, ok := e.(Long); ok { 233 return l == m 234 } 235 return false 236 } 237 238 func (l Long) String() string { 239 return strconv.FormatInt(int64(l), 10) 240 } 241 242 // Type returns the TagID of the data 243 func (Long) Type() TagID { 244 return TagLong 245 } 246 247 // Float is an implementation of the Data interface 248 type Float float32 249 250 // Copy simply returns a copy the the data 251 func (f Float) Copy() Data { 252 return f 253 } 254 255 // Equal satisfies the equaler.Equaler interface, allowing for types to be 256 // checked for equality 257 func (f Float) Equal(e interface{}) bool { 258 if m, ok := e.(Float); ok { 259 return f == m 260 } 261 return false 262 } 263 264 func (f Float) String() string { 265 return strconv.FormatFloat(float64(f), 'g', -1, 32) 266 } 267 268 // Type returns the TagID of the data 269 func (Float) Type() TagID { 270 return TagFloat 271 } 272 273 // Double is an implementation of the Data interface 274 type Double float64 275 276 // Copy simply returns a copy the the data 277 func (d Double) Copy() Data { 278 return d 279 } 280 281 // Equal satisfies the equaler.Equaler interface, allowing for types to be 282 // checked for equality 283 func (d Double) Equal(e interface{}) bool { 284 if m, ok := e.(Double); ok { 285 return d == m 286 } 287 return false 288 } 289 290 func (d Double) String() string { 291 return strconv.FormatFloat(float64(d), 'g', -1, 64) 292 } 293 294 // Type returns the TagID of the data 295 func (Double) Type() TagID { 296 return TagDouble 297 } 298 299 // ByteArray is an implementation of the Data interface 300 type ByteArray []int8 301 302 // Copy simply returns a copy the the data 303 func (b ByteArray) Copy() Data { 304 c := make(ByteArray, len(b)) 305 copy(c, b) 306 return c 307 } 308 309 // Equal satisfies the equaler.Equaler interface, allowing for types to be 310 // checked for equality 311 func (b ByteArray) Equal(e interface{}) bool { 312 if m, ok := e.(ByteArray); ok { 313 for i := 0; i < len(b); i++ { 314 if b[i] != m[i] { 315 return false 316 } 317 } 318 return true 319 } 320 return false 321 } 322 323 func (b ByteArray) String() string { 324 var data []byte 325 for n, d := range b { 326 if n > 0 { 327 data = append(data, ',', ' ') 328 } 329 data = append(data, strconv.FormatInt(int64(d), 10)...) 330 } 331 return "[" + strconv.FormatInt(int64(len(b)), 10) + " bytes] [" + string(data) + "]" 332 } 333 334 // Type returns the TagID of the data 335 func (ByteArray) Type() TagID { 336 return TagByteArray 337 } 338 339 // Bytes converts the ByteArray (actually int8) to an actual slice of bytes. 340 // NB: May uss unsafe, so the underlying array may be the same. 341 func (b ByteArray) Bytes() []byte { 342 return byteArrayToByteSlice(b) 343 } 344 345 // String is an implementation of the Data interface 346 type String string 347 348 // Copy simply returns a copy the the data 349 func (s String) Copy() Data { 350 return s 351 } 352 353 // Equal satisfies the equaler.Equaler interface, allowing for types to be 354 // checked for equality 355 func (s String) Equal(e interface{}) bool { 356 if m, ok := e.(String); ok { 357 return s == m 358 } 359 return false 360 } 361 362 func (s String) String() string { 363 return string(s) 364 } 365 366 // Type returns the TagID of the data 367 func (String) Type() TagID { 368 return TagString 369 } 370 371 // List interface descibes the methods for the lists of different data types 372 type List interface { 373 Data 374 Set(int, Data) error 375 Get(int) Data 376 Append(...Data) error 377 Insert(int, ...Data) error 378 Remove(int) 379 Len() int 380 TagType() TagID 381 } 382 383 // ListData is an implementation of the Data interface 384 type ListData struct { 385 tagType TagID 386 data []Data 387 } 388 389 // NewList returns a new List Data type, or nil if the given data is not of all 390 // the same Data type 391 func NewList(data []Data) List { 392 if len(data) == 0 { 393 return &ListByte{} 394 } 395 tagType := data[0].Type() 396 for i := 1; i < len(data); i++ { 397 if id := data[i].Type(); id != tagType { 398 return nil 399 } 400 } 401 l := newListWithLength(tagType, uint32(len(data))) 402 l.Append(data...) 403 return l 404 } 405 406 func newListWithLength(tagType TagID, length uint32) List { 407 var l List 408 switch tagType { 409 case TagEnd: 410 l = new(ListEnd) 411 case TagByte: 412 m := make(ListByte, 0, length) 413 l = &m 414 case TagShort: 415 m := make(ListShort, 0, length) 416 l = &m 417 case TagInt: 418 m := make(ListInt, 0, length) 419 l = &m 420 case TagLong: 421 m := make(ListLong, 0, length) 422 l = &m 423 case TagFloat: 424 m := make(ListFloat, 0, length) 425 l = &m 426 case TagDouble: 427 m := make(ListDouble, 0, length) 428 l = &m 429 case TagCompound: 430 m := make(ListCompound, 0, length) 431 l = &m 432 case TagIntArray: 433 m := make(ListIntArray, 0, length) 434 l = &m 435 case TagBool: 436 m := make(ListBool, 0, length) 437 l = &m 438 case TagUint8: 439 m := make(ListUint8, 0, length) 440 l = &m 441 case TagUint16: 442 m := make(ListUint16, 0, length) 443 l = &m 444 case TagUint32: 445 m := make(ListUint32, 0, length) 446 l = &m 447 case TagUint64: 448 m := make(ListUint64, 0, length) 449 l = &m 450 case TagComplex64: 451 m := make(ListComplex64, 0, length) 452 l = &m 453 case TagComplex128: 454 m := make(ListComplex128, 0, length) 455 l = &m 456 default: 457 l = &ListData{ 458 tagType, 459 make([]Data, 0, length), 460 } 461 } 462 return l 463 } 464 465 // NewEmptyList returns a new empty List Data type, set to the type given 466 func NewEmptyList(tagType TagID) List { 467 return newListWithLength(tagType, 0) 468 } 469 470 // TagType returns the TagID of the type of tag this list contains 471 func (l *ListData) TagType() TagID { 472 return l.tagType 473 } 474 475 // Copy simply returns a deep-copy the the data 476 func (l *ListData) Copy() Data { 477 c := new(ListData) 478 c.tagType = l.tagType 479 c.data = make([]Data, len(l.data)) 480 for i, d := range l.data { 481 c.data[i] = d.Copy() 482 } 483 return c 484 } 485 486 // Equal satisfies the equaler.Equaler interface, allowing for types to be 487 // checked for equality 488 func (l *ListData) Equal(e interface{}) bool { 489 if m, ok := e.(*ListData); ok { 490 if l.tagType == m.tagType && len(l.data) == len(m.data) { 491 for i, o := range l.data { 492 if !o.Equal(m.data[i]) { 493 return false 494 } 495 } 496 return true 497 } 498 } 499 return false 500 } 501 502 func (l *ListData) String() string { 503 s := strconv.FormatInt(int64(len(l.data)), 10) + " entries of type " + l.tagType.String() + " {" 504 for _, d := range l.data { 505 s += "\n " + l.tagType.String() + ": " + indent(d.String()) 506 } 507 return s + "\n}" 508 } 509 510 // Set sets the data at the given position. It does not append 511 func (l *ListData) Set(i int, data Data) error { 512 if i < 0 || i >= len(l.data) { 513 return ErrBadRange 514 } 515 if err := l.valid(data); err != nil { 516 return err 517 } 518 l.data[i] = data 519 return nil 520 } 521 522 // Get returns the data at the given positon 523 func (l *ListData) Get(i int) Data { 524 if i >= 0 && i < len(l.data) { 525 return l.data[i] 526 } 527 return nil 528 } 529 530 // Append adds data to the list 531 func (l *ListData) Append(data ...Data) error { 532 if err := l.valid(data...); err != nil { 533 return err 534 } 535 l.data = append(l.data, data...) 536 return nil 537 } 538 539 // Insert will add the given data at the specified position, moving other 540 // elements up. 541 func (l *ListData) Insert(i int, data ...Data) error { 542 if err := l.valid(data...); err != nil { 543 return err 544 } 545 l.data = append(l.data[:i], append(data, l.data[i:]...)...) 546 return nil 547 } 548 549 // Remove deletes the specified position and shifts remaing data down 550 func (l *ListData) Remove(i int) { 551 if i >= 0 && i < len(l.data) { 552 copy(l.data[i:], l.data[i+1:]) 553 l.data[len(l.data)-1] = nil 554 l.data = l.data[:len(l.data)-1] 555 } 556 } 557 558 // Len returns the length of the list 559 func (l *ListData) Len() int { 560 return len(l.data) 561 } 562 563 func (l *ListData) valid(data ...Data) error { 564 for _, d := range data { 565 if t := d.Type(); t != l.tagType { 566 return &WrongTag{l.tagType, t} 567 } 568 } 569 return nil 570 } 571 572 // Type returns the TagID of the data 573 func (ListData) Type() TagID { 574 return TagList 575 } 576 577 // Compound is an implementation of the Data interface 578 type Compound []Tag 579 580 // Copy simply returns a deep-copy the the data 581 func (c Compound) Copy() Data { 582 d := make(Compound, len(c)) 583 for i, t := range c { 584 d[i] = t.Copy() 585 } 586 return d 587 } 588 589 // Equal satisfies the equaler.Equaler interface, allowing for types to be 590 // checked for equality 591 func (c Compound) Equal(e interface{}) bool { 592 if m, ok := e.(Compound); ok { 593 if len(c) == len(m) { 594 for _, o := range c { 595 if p := m.Get(o.Name()); !p.Equal(o) { 596 return false 597 } 598 } 599 return true 600 } 601 } 602 return false 603 } 604 605 func (c Compound) String() string { 606 s := strconv.FormatInt(int64(len(c)), 10) + " entries {" 607 for _, d := range c { 608 s += "\n " + indent(d.String()) 609 } 610 return s + "\n}" 611 } 612 613 // Get returns the tag for the given name 614 func (c Compound) Get(name string) Tag { 615 for _, t := range c { 616 if t.Name() == name { 617 return t 618 } 619 } 620 return Tag{} 621 } 622 623 // Remove removes the tag corresponding to the given name 624 func (c *Compound) Remove(name string) { 625 for i, t := range *c { 626 if t.Name() == name { 627 copy((*c)[i:], (*c)[i+1:]) 628 (*c)[len((*c))-1] = Tag{data: end{}} 629 (*c) = (*c)[:len((*c))-1] 630 return 631 } 632 } 633 } 634 635 // Set adds the given tag to the compound, or, if the tags name is already 636 // present, overrides the old data 637 func (c *Compound) Set(tag Tag) { 638 if tag.TagID() == TagEnd { 639 return 640 } 641 name := tag.Name() 642 for i, t := range *c { 643 if t.Name() == name { 644 (*c)[i] = tag 645 return 646 } 647 } 648 *c = append(*c, tag) 649 } 650 651 // Type returns the TagID of the data 652 func (Compound) Type() TagID { 653 return TagCompound 654 } 655 656 // IntArray is an implementation of the Data interface 657 type IntArray []int32 658 659 // Copy simply returns a copy the the data 660 func (i IntArray) Copy() Data { 661 c := make(IntArray, len(i)) 662 copy(c, i) 663 return c 664 } 665 666 // Equal satisfies the equaler.Equaler interface, allowing for types to be 667 // checked for equality 668 func (i IntArray) Equal(e interface{}) bool { 669 if m, ok := e.(IntArray); ok { 670 if len(i) == len(m) { 671 for j, o := range i { 672 if o != m[j] { 673 return false 674 } 675 } 676 return true 677 } 678 } 679 return false 680 } 681 682 func (i IntArray) String() string { 683 var data []byte 684 for n, d := range i { 685 if n > 0 { 686 data = append(data, ',', ' ') 687 } 688 data = append(data, strconv.FormatInt(int64(d), 10)...) 689 } 690 return "[" + strconv.FormatInt(int64(len(i)), 10) + " bytes] [" + string(data) + "]" 691 } 692 693 // Type returns the TagID of the data 694 func (IntArray) Type() TagID { 695 return TagIntArray 696 } 697 698 // Bool is an implementation of the Data interface 699 type Bool bool 700 701 // Copy simply returns a copy the the data 702 func (b Bool) Copy() Data { 703 return b 704 } 705 706 // Equal satisfies the equaler.Equaler interface, allowing for types to be 707 // checked for equality 708 func (b Bool) Equal(e interface{}) bool { 709 if m, ok := e.(Bool); ok { 710 return b == m 711 } 712 return false 713 } 714 715 func (b Bool) String() string { 716 if b { 717 return "true" 718 } 719 return "false" 720 } 721 722 // Type returns the TagID of the data 723 func (Bool) Type() TagID { 724 return TagBool 725 } 726 727 // Uint8 is an implementation of the Data interface 728 type Uint8 uint8 729 730 // Copy simply returns a copy the the data 731 func (u Uint8) Copy() Data { 732 return u 733 } 734 735 // Equal satisfies the equaler.Equaler interface, allowing for types to be 736 // checked for equality 737 func (u Uint8) Equal(e interface{}) bool { 738 if m, ok := e.(Uint8); ok { 739 return u == m 740 } 741 return false 742 } 743 744 func (u Uint8) String() string { 745 return strconv.FormatUint(uint64(u), 10) 746 } 747 748 // Type returns the TagID of the data 749 func (Uint8) Type() TagID { 750 return TagUint8 751 } 752 753 // Uint16 is an implementation of the Data interface 754 type Uint16 uint16 755 756 // Copy simply returns a copy the the data 757 func (u Uint16) Copy() Data { 758 return u 759 } 760 761 // Equal satisfies the equaler.Equaler interface, allowing for types to be 762 // checked for equality 763 func (u Uint16) Equal(e interface{}) bool { 764 if m, ok := e.(Uint16); ok { 765 return u == m 766 } 767 return false 768 } 769 770 func (u Uint16) String() string { 771 return strconv.FormatUint(uint64(u), 10) 772 } 773 774 // Type returns the TagID of the data 775 func (Uint16) Type() TagID { 776 return TagUint16 777 } 778 779 // Uint32 is an implementation of the Data interface 780 type Uint32 uint32 781 782 // Copy simply returns a copy the the data 783 func (u Uint32) Copy() Data { 784 return u 785 } 786 787 // Equal satisfies the equaler.Equaler interface, allowing for types to be 788 // checked for equality 789 func (u Uint32) Equal(e interface{}) bool { 790 if m, ok := e.(Uint32); ok { 791 return u == m 792 } 793 return false 794 } 795 796 func (u Uint32) String() string { 797 return strconv.FormatUint(uint64(u), 10) 798 } 799 800 // Type returns the TagID of the data 801 func (Uint32) Type() TagID { 802 return TagUint32 803 } 804 805 // Uint64 is an implementation of the Data interface 806 type Uint64 uint64 807 808 // Copy simply returns a copy the the data 809 func (u Uint64) Copy() Data { 810 return u 811 } 812 813 // Equal satisfies the equaler.Equaler interface, allowing for types to be 814 // checked for equality 815 func (u Uint64) Equal(e interface{}) bool { 816 if m, ok := e.(Uint64); ok { 817 return u == m 818 } 819 return false 820 } 821 822 func (u Uint64) String() string { 823 return strconv.FormatUint(uint64(u), 10) 824 } 825 826 // Type returns the TagID of the data 827 func (Uint64) Type() TagID { 828 return TagUint64 829 } 830 831 // Complex64 is an implementation of the Data interface 832 type Complex64 complex64 833 834 // Copy simply returns a copy the the data 835 func (c Complex64) Copy() Data { 836 return c 837 } 838 839 // Equal satisfies the equaler.Equaler interface, allowing for types to be 840 // checked for equality 841 func (c Complex64) Equal(e interface{}) bool { 842 if m, ok := e.(Complex64); ok { 843 return c == m 844 } 845 return false 846 } 847 848 func (c Complex64) String() string { 849 var str string 850 if real(c) != 0 { 851 str = strconv.FormatFloat(float64(real(c)), 'g', -1, 32) 852 } 853 if imag(c) != 0 { 854 if len(str) != 0 { 855 str += "+" 856 } 857 str += strconv.FormatFloat(float64(imag(c)), 'g', -1, 32) + "i" 858 } 859 return str 860 } 861 862 // Type returns the TagID of the data 863 func (Complex64) Type() TagID { 864 return TagComplex64 865 } 866 867 // Complex128 is an implementation of the Data interface 868 type Complex128 complex128 869 870 // Copy simply returns a copy the the data 871 func (c Complex128) Copy() Data { 872 return c 873 } 874 875 // Equal satisfies the equaler.Equaler interface, allowing for types to be 876 // checked for equality 877 func (c Complex128) Equal(e interface{}) bool { 878 if m, ok := e.(Complex128); ok { 879 return c == m 880 } 881 return false 882 } 883 884 func (c Complex128) String() string { 885 var str string 886 if real(c) != 0 { 887 str = strconv.FormatFloat(real(c), 'g', -1, 64) 888 } 889 if imag(c) != 0 { 890 if len(str) != 0 { 891 str += "+" 892 } 893 str += strconv.FormatFloat(imag(c), 'g', -1, 64) + "i" 894 } 895 return str 896 } 897 898 // Type returns the TagID of the data 899 func (Complex128) Type() TagID { 900 return TagComplex128 901 } 902