File: nbt.rb

package info (click to toggle)
ruby-bindata 2.4.14-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 600 kB
  • sloc: ruby: 8,566; makefile: 4
file content (178 lines) | stat: -rw-r--r-- 5,344 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
require 'bindata'

# An example reader for Minecraft's NBT format.
# http://www.minecraft.net/docs/NBT.txt
#
# This is an example of how to write a BinData
# declaration for a recursively defined file format.
module Nbt

  TAG_NAMES = {
     0 => "End",
     1 => "Byte",
     2 => "Short",
     3 => "Int",
     4 => "Long",
     5 => "Float",
     6 => "Double",
     7 => "Byte_Array",
     8 => "String",
     9 => "List",
    10 => "Compound"
  }

  # NBT.txt line 25
  class TagEnd < BinData::Primitive
    def get; ""; end
    def set(v); end

    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 31
  class TagByte < BinData::Int8
    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 34
  class TagShort < BinData::Int16be
    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 37
  class TagInt < BinData::Int32be
    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 40
  class TagLong < BinData::Int64be
    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 43
  class TagFloat < BinData::FloatBe
    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 46
  class TagDouble < BinData::DoubleBe
    def to_formatted_s(indent = 0); to_s; end
  end

  # NBT.txt line 49
  class TagByteArray < BinData::Record
    int32be :len,  value: -> { data.length }
    string  :data, read_length: :len

    def to_formatted_s(indent = 0)
      "[#{len} bytes]"
    end
  end

  # NBT.txt line 53
  class TagString < BinData::Primitive
    int16be :len,  value: -> { data.length }
    string  :data, read_length: :len

    def get
      self.data
    end

    def set(v)
      self.data = v
    end

    def to_formatted_s(indent = 0); to_s; end
  end

  ## Payload is the most important class to understand.
  ## This abstraction allows recursive formats.
  ## eg. lists can contain lists can contain lists.

  # Forward references used by Payload
  class TagCompound < BinData::Record; end
  class TagList < BinData::Record; end

  # NBT.txt line 10
  class Payload < BinData::Choice
    tag_end        0
    tag_byte       1
    tag_short      2
    tag_int        3
    tag_long       4
    tag_float      5
    tag_double     6
    tag_byte_array 7
    tag_string     8
    tag_list       9
    tag_compound   10
  end

  # NBT.txt line 6, 27
  class NamedTag < BinData::Record
    int8 :tag_id
    tag_string :name,    onlyif: :not_end_tag?
    payload    :payload, onlyif: :not_end_tag?, selection: :tag_id

    def not_end_tag?
      tag_id != 0
    end

    def to_formatted_s(indent = 0)
      "  " * indent +
      "TAG_#{TAG_NAMES[tag_id]}(\"#{name}\"): " +
      payload.to_formatted_s(indent) + "\n"
    end
  end

  # NBT.txt line 57
  class TagList < BinData::Record
    int8    :tag_id
    int32be :len,  value: -> { data.length }
    array   :data, initial_length: :len do
      payload selection: :tag_id
    end

    def to_formatted_s(indent = 0)
      pre = "  " * indent
      tag_type = "TAG_#{TAG_NAMES[tag_id]}"

      "#{len} entries of type #{tag_type}\n" +
      pre + "{\n" +
        data.collect { |el| "  #{pre}#{tag_type}: #{el.to_formatted_s(indent + 1)}\n" }.join("") +
      pre + "}"
    end
  end

  # NBT.txt line 63
  class TagCompound < BinData::Record
    array :data, read_until: -> { element.tag_id == 0 } do
      named_tag
    end

    def to_formatted_s(indent = 0)
      pre = "  " * indent
      "#{data.length - 1} entries\n" +
      pre + "{\n" +
        data[0..-2].collect { |el| el.to_formatted_s(indent + 1) }.join("") +
      pre + "}"
    end
  end

  # NBT.txt line 3
  class Nbt < NamedTag
    def self.read(io)
      require 'zlib'
      super(Zlib::GzipReader.new(io))
    end
  end
end

if $0 == __FILE__
  require 'stringio'

  bigtest_nbt = StringIO.new "\037\213\b\000\000\000\000\000\000\003\355T\317O\032A\024~\302\002\313\226\202\261\304\020c\314\253\265\204\245\333\315B\021\211\261\210\026,\232\r\032\330\2501\206\270+\303\202.\273fw\260\361\324K{lz\353?\323#\177C\317\275\366\277\240\303/{i\317\275\3602\311\367\346\275o\346{o&y\002\004TrO,\016x\313\261M\215x\364\343pb>\b{\035\307\245\223\030\017\202G\335\356\204\002b\265\242\252\307xv\\W\313\250U\017\e\310\326\036j\225\206\206\r\255~X{\217\203\317\203O\203o\317\003\020n[\216>\276\2458Ld\375\020\352\332t\246\#@\334f.i\341\265\323\273s\372v\v)\333\v\340\357\350=\0368[\357\021\bV\365\336]\337\v@\340^\267\372d\267\004\000\214ALs\306\bUL\323 .}\244\300\310\302\020\263\272\336X\vS\243\356D\216E\0030\261'S\214L\361\351\024\243S\214\205\341\331\237\343\263\362D\201\245|3\335\330\273\307\252u\023_(\034\b\327.\321Y?\257\035\e`!Y\337\372\361\005\376\301\316\374\235\275\000\274\361@\311\370\205B@F\376\236\353\352\017\223:h\207`\273\35327\243(\n\216\273\365\320ic\312N\333\351\354\346\346+;\275%\276dI\t=\252\273\224\375\030~\350\322\016\332o\025L\261h>+\341\233\234\204\231\274\204\005\teY\026E\000\377/(\256/\362\302\262\244.\035 wZ;\271\214\312\347)\337QA\311\026\265\305m\241*\255,\3051\177\272z\222\216^\235_\370\022\005#\e\321\366\267w\252\315\225r\274\236\337X]K\227\256\222\027\271D\320\200\310\372>\277\263\334T\313\aun\243\266vY\222\223\251\334QP\231k\3145\346\032\377W#\bB\313\351\e\326x\302\354\376\374z\373}x\323\204\337\324\362\244\373\b\006\000\000"

  nbt = Nbt::Nbt.read(bigtest_nbt)
  puts nbt.to_formatted_s
end