forked from pdinklag/MinecraftStats
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nbt.php
139 lines (112 loc) · 2.95 KB
/
nbt.php
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
<?php
define('NBT_END', 0);
define('NBT_BYTE', 1);
define('NBT_SHORT', 2);
define('NBT_INT', 3);
define('NBT_LONG', 4);
define('NBT_FLOAT', 5);
define('NBT_DOUBLE', 6);
define('NBT_BYTE_ARRAY', 7);
define('NBT_STRING', 8);
define('NBT_LIST', 9);
define('NBT_COMPOUND', 10);
define('NBT_INT_ARRAY', 11);
function nbt_readTag($f) {
return unpack('C', fread($f, 1))[1];
}
function nbt_readString($f) {
$len = unpack('n', fread($f, 2))[1];
if($len > 0) {
return utf8_decode(fread($f, $len));
} else {
return '';
}
}
function nbt_readCompound($f) {
$compound = [];
$next = nbt_readTag($f);
while($next != NBT_END) {
$name = nbt_readString($f);
$compound[$name] = nbt_readDynamic($f, $next);
$next = nbt_readTag($f);
}
return $compound;
}
function nbt_readList($f) {
$list = [];
$tag = nbt_readTag($f);
$len = unpack('N', fread($f, 4))[1];
for($i = 0; $i < $len; $i++) {
$list[$i] = nbt_readDynamic($f, $tag);
}
return $list;
}
function signedInt16($s) {
if($s >= 0x8000) {
return -1 - ($s & 0x7FFF);
} else {
return $s;
}
}
function signedInt32($i) {
if($i >= 0x80000000) {
return -1 - ($i & 0x7FFFFFFF);
} else {
return $i;
}
}
function signedInt64($l) {
if($l >= 0x8000000000000000) {
return -1 - ($l & 0x7FFFFFFFFFFFFFFF);
} else {
return $l;
}
}
function nbt_readDynamic($f, $tag) {
switch($tag) {
case NBT_BYTE:
return unpack('c', fread($f, 1))[1];
case NBT_SHORT:
return signedInt16(unpack('n', fread($f, 2))[1]);
case NBT_INT:
return signedInt32(unpack('N', fread($f, 4))[1]);
case NBT_LONG:
$l = (unpack('N', fread($f, 4))[1] * 0x100000000) + (int)unpack('N', fread($f, 4))[1];
return signedInt64($l);
case NBT_FLOAT:
return unpack('f', strrev(fread($f, 4)))[1];
case NBT_DOUBLE:
return unpack('d', strrev(fread($f, 8)))[1];
case NBT_BYTE_ARRAY:
$len = unpack('N', fread($f, 4))[1];
fread($f, $len); //discard
return '(BYTE_ARRAY)';
case NBT_STRING:
return nbt_readString($f);
case NBT_LIST:
return nbt_readList($f);
case NBT_COMPOUND:
return nbt_readCompound($f);
case NBT_INT_ARRAY:
$len = unpack('N', fread($f, 4))[1];
fread($f, 4 * $len); //discard
return '(INT_ARRAY)';
}
}
/* NBT reader */
function nbtdecode($nbt) {
$f = fopen('php://memory', 'r+');
fwrite($f, $nbt);
rewind($f);
$result = FALSE;
$tag = nbt_readTag($f);
if($tag == NBT_COMPOUND) {
nbt_readString($f); //discard name
$result = nbt_readCompound($f);
} else {
die('top level needs to be a compound');
}
fclose($f);
return $result;
}
?>