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
|