PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
NBT.php
1 <?php
2 
3 /*
4  *
5  * ____ _ _ __ __ _ __ __ ____
6  * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7  * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8  * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9  * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * @author PocketMine Team
17  * @link http://www.pocketmine.net/
18  *
19  *
20 */
21 
25 namespace pocketmine\nbt;
26 
37 use pocketmine\nbt\tag\NamedTAG;
42 
43 #ifndef COMPILE
45 
46 #endif
47 
48 
49 #include <rules/NBT.h>
50 
54 class NBT{
55 
56  const LITTLE_ENDIAN = 0;
57  const BIG_ENDIAN = 1;
58  const TAG_End = 0;
59  const TAG_Byte = 1;
60  const TAG_Short = 2;
61  const TAG_Int = 3;
62  const TAG_Long = 4;
63  const TAG_Float = 5;
64  const TAG_Double = 6;
65  const TAG_ByteArray = 7;
66  const TAG_String = 8;
67  const TAG_Enum = 9;
68  const TAG_Compound = 10;
69  const TAG_IntArray = 11;
70 
71  public $buffer;
72  private $offset;
73  public $endianness;
74  private $data;
75 
76  public function get($len){
77  if($len < 0){
78  $this->offset = strlen($this->buffer) - 1;
79  return "";
80  }elseif($len === true){
81  return substr($this->buffer, $this->offset);
82  }
83 
84  return $len === 1 ? $this->buffer{$this->offset++} : substr($this->buffer, ($this->offset += $len) - $len, $len);
85  }
86 
87  public function put($v){
88  $this->buffer .= $v;
89  }
90 
91  public function feof(){
92  return !isset($this->buffer{$this->offset});
93  }
94 
95  public function __construct($endianness = self::LITTLE_ENDIAN){
96  $this->offset = 0;
97  $this->endianness = $endianness & 0x01;
98  }
99 
100  public function read($buffer, $doMultiple = false){
101  $this->offset = 0;
102  $this->buffer = $buffer;
103  $this->data = $this->readTag();
104  if($doMultiple and $this->offset < strlen($this->buffer)){
105  $this->data = [$this->data];
106  do{
107  $this->data[] = $this->readTag();
108  }while($this->offset < strlen($this->buffer));
109  }
110  $this->buffer = "";
111  }
112 
113  public function readCompressed($buffer, $compression = ZLIB_ENCODING_GZIP){
114  $this->read(zlib_decode($buffer));
115  }
116 
117  public function write(){
118  $this->offset = 0;
119  if($this->data instanceof Compound){
120  $this->writeTag($this->data);
121 
122  return $this->buffer;
123  }elseif(is_array($this->data)){
124  foreach($this->data as $tag){
125  $this->writeTag($tag);
126  }
127  return $this->buffer;
128  }
129 
130  return false;
131  }
132 
133  public function writeCompressed($compression = ZLIB_ENCODING_GZIP, $level = 7){
134  if(($write = $this->write()) !== false){
135  return zlib_encode($write, $compression, $level);
136  }
137 
138  return false;
139  }
140 
141  public function readTag(){
142  switch($this->getByte()){
143  case NBT::TAG_Byte:
144  $tag = new Byte($this->getString());
145  $tag->read($this);
146  break;
147  case NBT::TAG_Short:
148  $tag = new Short($this->getString());
149  $tag->read($this);
150  break;
151  case NBT::TAG_Int:
152  $tag = new Int($this->getString());
153  $tag->read($this);
154  break;
155  case NBT::TAG_Long:
156  $tag = new Long($this->getString());
157  $tag->read($this);
158  break;
159  case NBT::TAG_Float:
160  $tag = new Float($this->getString());
161  $tag->read($this);
162  break;
163  case NBT::TAG_Double:
164  $tag = new Double($this->getString());
165  $tag->read($this);
166  break;
167  case NBT::TAG_ByteArray:
168  $tag = new ByteArray($this->getString());
169  $tag->read($this);
170  break;
171  case NBT::TAG_String:
172  $tag = new String($this->getString());
173  $tag->read($this);
174  break;
175  case NBT::TAG_Enum:
176  $tag = new Enum($this->getString());
177  $tag->read($this);
178  break;
179  case NBT::TAG_Compound:
180  $tag = new Compound($this->getString());
181  $tag->read($this);
182  break;
183  case NBT::TAG_IntArray:
184  $tag = new IntArray($this->getString());
185  $tag->read($this);
186  break;
187 
188  case NBT::TAG_End: //No named tag
189  default:
190  $tag = new End;
191  break;
192  }
193  return $tag;
194  }
195 
196  public function writeTag(Tag $tag){
197  $this->putByte($tag->getType());
198  if($tag instanceof NamedTAG){
199  $this->putString($tag->getName());
200  }
201  $tag->write($this);
202  }
203 
204  public function getByte(){
205  return Binary::readByte($this->get(1));
206  }
207 
208  public function putByte($v){
209  $this->buffer .= Binary::writeByte($v);
210  }
211 
212  public function getShort(){
213  return $this->endianness === self::BIG_ENDIAN ? Binary::readShort($this->get(2)) : Binary::readLShort($this->get(2));
214  }
215 
216  public function putShort($v){
217  $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeShort($v) : Binary::writeLShort($v);
218  }
219 
220  public function getInt(){
221  return $this->endianness === self::BIG_ENDIAN ? Binary::readInt($this->get(4)) : Binary::readLInt($this->get(4));
222  }
223 
224  public function putInt($v){
225  $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeInt($v) : Binary::writeLInt($v);
226  }
227 
228  public function getLong(){
229  return $this->endianness === self::BIG_ENDIAN ? Binary::readLong($this->get(8)) : Binary::readLLong($this->get(8));
230  }
231 
232  public function putLong($v){
233  $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeLong($v) : Binary::writeLLong($v);
234  }
235 
236  public function getFloat(){
237  return $this->endianness === self::BIG_ENDIAN ? Binary::readFloat($this->get(4)) : Binary::readLFloat($this->get(4));
238  }
239 
240  public function putFloat($v){
241  $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeFloat($v) : Binary::writeLFloat($v);
242  }
243 
244  public function getDouble(){
245  return $this->endianness === self::BIG_ENDIAN ? Binary::readDouble($this->get(8)) : Binary::readLDouble($this->get(8));
246  }
247 
248  public function putDouble($v){
249  $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeDouble($v) : Binary::writeLDouble($v);
250  }
251 
252  public function getString(){
253  return $this->get($this->getShort());
254  }
255 
256  public function putString($v){
257  $this->putShort(strlen($v));
258  $this->buffer .= $v;
259  }
260 
261  public function getArray(){
262  $data = [];
263  $this->toArray($data, $this->data);
264  }
265 
266  private function toArray(array &$data, Tag $tag){
268  foreach($tag as $key => $value){
269  if($value instanceof Compound or $value instanceof Enum or $value instanceof IntArray){
270  $data[$key] = [];
271  $this->toArray($data[$key], $value);
272  }else{
273  $data[$key] = $value->getValue();
274  }
275  }
276  }
277 
278  private function fromArray(Tag $tag, array $data){
279  foreach($data as $key => $value){
280  if(is_array($value)){
281  $isNumeric = true;
282  $isIntArray = true;
283  foreach($value as $k => $v){
284  if(!is_numeric($k)){
285  $isNumeric = false;
286  break;
287  }elseif(!is_int($v)){
288  $isIntArray = false;
289  }
290  }
291  $tag{$key} = $isNumeric ? ($isIntArray ? new IntArray($key, []) : new Enum($key, [])) : new Compound($key, []);
292  $this->fromArray($tag->{$key}, $value);
293  }elseif(is_int($value)){
294  $tag{$key} = new Int($key, $value);
295  }elseif(is_float($value)){
296  $tag{$key} = new Float($key, $value);
297  }elseif(is_string($value)){
298  if(Utils::printable($value) !== $value){
299  $tag{$key} = new ByteArray($key, $value);
300  }else{
301  $tag{$key} = new String($key, $value);
302  }
303  }elseif(is_bool($value)){
304  $tag{$key} = new Byte($key, $value ? 1 : 0);
305  }
306  }
307  }
308 
309  public function setArray(array $data){
310  $this->data = new Compound(null, []);
311  $this->fromArray($this->data, $data);
312  }
313 
314  public function getData(){
315  return $this->data;
316  }
317 
318  public function setData(Compound $data){
319  $this->data = $data;
320  }
321 
322 }
static writeByte($c)
Definition: Binary.php:248
static readByte($c, $signed=true)
Definition: Binary.php:227
static printable($str)
Definition: Utils.php:202
static writeShort($value)
Definition: Binary.php:285
static writeLShort($value)
Definition: Binary.php:322
static readShort($str)
Definition: Binary.php:259
static readLShort($str)
Definition: Binary.php:296