DabDaddy6223

nbt.lua

Nov 11th, 2023
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.92 KB | None | 0 0
  1. --[[---------------------------------------------------------------------------
  2. -- Copyright (c) 2040 Dark Energy Processor
  3. --
  4. -- This software is provided 'as-is', without any express or implied
  5. -- warranty. In no event will the authors be held liable for any damages
  6. -- arising from the use of this software.
  7. --
  8. -- Permission is granted to anyone to use this software for any purpose,
  9. -- including commercial applications, and to alter it and redistribute it
  10. -- freely, subject to the following restrictions:
  11. --
  12. -- 1. The origin of this software must not be misrepresented; you must not
  13. -- claim that you wrote the original software. If you use this software
  14. -- in a product, an acknowledgment in the product documentation would be
  15. -- appreciated but is not required.
  16. -- 2. Altered source versions must be plainly marked as such, and must not
  17. -- be misrepresented as being the original software.
  18. -- 3. This notice may not be removed or altered from any source
  19. -- distribution.
  20. --]]---------------------------------------------------------------------------
  21.  
  22. -- Lua 5.1 or later is required
  23. assert(_VERSION >= "Lua 5.1", "At least Lua 5.1 is required for this library")
  24.  
  25. local nbt = {
  26. _VERSION = "1.0.1",
  27. _DESCRIPTION = "Named Binary Tag library for Lua",
  28. _URL = "https://github.com/MikuAuahDark/lua-nbt",
  29. _LICENSE = "zLib"
  30. }
  31.  
  32. -- Tag constants
  33. local TAG_END = 0 nbt.TAG_END = 0
  34. local TAG_BYTE = 1 nbt.TAG_BYTE = 1
  35. local TAG_SHORT = 2 nbt.TAG_SHORT = 2
  36. local TAG_INT = 3 nbt.TAG_INT = 3
  37. local TAG_LONG = 4 nbt.TAG_LONG = 4
  38. local TAG_FLOAT = 5 nbt.TAG_FLOAT = 5
  39. local TAG_DOUBLE = 6 nbt.TAG_DOUBLE = 6
  40. local TAG_BYTE_ARRAY = 7 nbt.TAG_BYTE_ARRAY = 7
  41. local TAG_STRING = 8 nbt.TAG_STRING = 8
  42. local TAG_LIST = 9 nbt.TAG_LIST = 9
  43. local TAG_COMPOUND = 10 nbt.TAG_COMPOUND = 10
  44. local TAG_INT_ARRAY = 11 nbt.TAG_INT_ARRAY = 11
  45. local TAG_LONG_ARRAY = 12 nbt.TAG_LONG_ARRAY = 12
  46.  
  47. -- Internal uses
  48. local isLuaJIT = pcall(require, "jit")
  49. local isLua53 = _VERSION >= "Lua 5.3" -- Should work for now
  50.  
  51. -- Internal functions
  52. local getLongInt, longIntTostring, toInteger, encodeLongInt, decodeLongInt
  53. local encodeShort, encodeInt, decodeShort, decodeInt
  54. local encodeFloat, encodeDouble, decodeFloat, decodeDouble
  55. if isLuaJIT then
  56. -- Use LuaJIT boxed 64-bit int
  57. local ffi = require("ffi")
  58. local i64 = ffi.new("union {int64_t a; uint8_t b[8]; double c;}")
  59. local i32f = ffi.new("union {float a; uint8_t b[4];}")
  60. local zeroLL = loadstring("return 0LL")()
  61.  
  62. function getLongInt(self)
  63. return self._value + zeroLL
  64. end
  65.  
  66. function longIntTostring(v)
  67. return tostring(v + zeroLL):sub(1, -2) -- remove additional "L"
  68. end
  69.  
  70. function toInteger(v)
  71. return v < 0 and math.ceil(v) or math.floor(v)
  72. end
  73.  
  74. if ffi.abi("be") then
  75. function encodeLongInt(v)
  76. i64.a = v
  77. return ffi.string(i64.b, 8)
  78. end
  79.  
  80. function decodeLongInt(str)
  81. ffi.copy(i64.b, str, 8)
  82. return i64.a
  83. end
  84.  
  85. function encodeDouble(v)
  86. i64.c = v
  87. return ffi.string(i64.b, 8)
  88. end
  89.  
  90. function decodeDouble(str)
  91. ffi.copy(i64.b, str, 8)
  92. return i64.c
  93. end
  94.  
  95. function encodeFloat(v)
  96. i32f.a = v
  97. return ffi.string(i32f.b, 4)
  98. end
  99.  
  100. function decodeFloat(str)
  101. ffi.copy(i32f.b, str, 4)
  102. return i32f.a
  103. end
  104. else
  105. function encodeLongInt(v)
  106. i64.a = v
  107. return string.char(
  108. i64.b[7],
  109. i64.b[6],
  110. i64.b[5],
  111. i64.b[4],
  112. i64.b[3],
  113. i64.b[2],
  114. i64.b[1],
  115. i64.b[0]
  116. )
  117. end
  118.  
  119. function decodeLongInt(str)
  120. local a, b, c, d, e, f, g, h = str:byte(1, 8)
  121. i64.b[0], i64.b[1], i64.b[2], i64.b[3] = h, g, f, e
  122. i64.b[4], i64.b[5], i64.b[6], i64.b[7] = d, c, b, a
  123. return i64.a
  124. end
  125.  
  126. function encodeDouble(v)
  127. i64.c = v
  128. return string.char(
  129. i64.b[7],
  130. i64.b[6],
  131. i64.b[5],
  132. i64.b[4],
  133. i64.b[3],
  134. i64.b[2],
  135. i64.b[1],
  136. i64.b[0]
  137. )
  138. end
  139.  
  140. function decodeDouble(str)
  141. local a, b, c, d, e, f, g, h = str:byte(1, 8)
  142. i64.b[0], i64.b[1], i64.b[2], i64.b[3] = h, g, f, e
  143. i64.b[4], i64.b[5], i64.b[6], i64.b[7] = d, c, b, a
  144. return i64.c
  145. end
  146.  
  147. function encodeFloat(v)
  148. i32f.a = v
  149. return string.char(
  150. i32f.b[3],
  151. i32f.b[2],
  152. i32f.b[1],
  153. i32f.b[0]
  154. )
  155. end
  156.  
  157. function decodeFloat(str)
  158. local a, b, c, d = str:byte(1, 4)
  159. i32f.b[0], i32f.b[1], i32f.b[2], i32f.b[3] = d, c, b, a
  160. return i32f.a
  161. end
  162. end
  163. elseif isLua53 then
  164. -- Use Lua 5.3 integer
  165. function toInteger(v)
  166. return math.tointeger(v < 0 and math.ceil(v) or math.floor(v))
  167. end
  168. function getLongInt(self)
  169. return toInteger(self._value)
  170. end
  171.  
  172. function longIntTostring(v)
  173. return string.format("%dL", v)
  174. end
  175.  
  176. function encodeLongInt(v)
  177. return string.pack(">i8", v)
  178. end
  179.  
  180. function decodeLongInt(str)
  181. return string.unpack(">i8", str)
  182. end
  183.  
  184. function encodeDouble(v)
  185. return string.pack(">d", v)
  186. end
  187.  
  188. function decodeDouble(str)
  189. return string.unpack(">d", str)
  190. end
  191.  
  192. function encodeFloat(v)
  193. return string.pack(">f", v)
  194. end
  195.  
  196. function decodeFloat(str)
  197. return string.unpack(">f", str)
  198. end
  199. else
  200. local log2 = math.log(2)
  201. local frexp = not(isLuaJIT) and math.frexp or function(x)
  202. -- Stolen't from cpml/utils
  203. if x == 0 then return 0, 0 end
  204. local e = math.floor(math.log(math.abs(x)) / log2 + 1)
  205. return x / 2 ^ e, e
  206. end
  207.  
  208. -- Default for Lua 5.1/5.2
  209. function getLongInt(self)
  210. return self._value < 0 and math.ceil(self._value) or math.floor(self._value)
  211. end
  212.  
  213. function longIntTostring(v)
  214. -- May imprecise but we have no choice
  215. return string.format("%.0fL", v)
  216. end
  217.  
  218. function toInteger(v)
  219. return v < 0 and math.ceil(v) or math.floor(v)
  220. end
  221.  
  222. function encodeLongInt(v)
  223. -- This was shamelessly stolen from lua-MessagePack
  224. return string.char(
  225. v < 0 and 255 or 0, -- only 53 bits from double
  226. math.floor(v / 0x1000000000000) % 0x100,
  227. math.floor(v / 0x10000000000) % 0x100,
  228. math.floor(v / 0x100000000) % 0x100,
  229. math.floor(v / 0x1000000) % 0x100,
  230. math.floor(v / 0x10000) % 0x100,
  231. math.floor(v / 0x100) % 0x100,
  232. v % 0x100
  233. )
  234. end
  235.  
  236. function decodeLongInt(str)
  237. -- This was shamelessly stolen from lua-MessagePack
  238. local a, b, c, d, e, f, g, h = str:byte(1, 8)
  239. if a > 128 then
  240. a, b, c, d = a - 255, b - 255, c - 255, d - 255
  241. e, f, g, h = e - 255, f - 255, g - 255, h - 255
  242. end
  243.  
  244. return ((((((a * 256 + b) * 256 + c) * 256 + d) * 256 + e) * 256 + f) * 256 + g) * 256 + h
  245. end
  246.  
  247. function encodeDouble(v)
  248. -- This was shamelessly stolen from lua-MessagePack
  249. local sign = v < 0 and 128 or 0
  250. local mant, expo = frexp(v)
  251.  
  252. if mant ~= mant then
  253. -- NaN
  254. return "\255\248\0\0\0\0\0\0"
  255. elseif mant == math.huge or expo > 1024 then
  256. if sign == 0 then
  257. -- +inf
  258. return "\127\240\0\0\0\0\0\0"
  259. else
  260. -- -inf
  261. return "\255\240\0\0\0\0\0\0"
  262. end
  263. elseif (mant == 0 and expo == 0) or expo < -1022 then
  264. -- zero
  265. return string.char(sign).."\0\0\0\0\0\0\0"
  266. else
  267. expo = expo + 1022
  268. mant = math.floor((math.abs(mant) * 2.0 - 1.0) * 4503599627370496)
  269. return string.char(
  270. sign + math.floor(expo / 16),
  271. (expo % 16) * 16 + math.floor(mant / 0x1000000000000),
  272. math.floor(mant / 0x10000000000) % 256,
  273. math.floor(mant / 4294967296) % 256,
  274. math.floor(mant / 16777216) % 256,
  275. math.floor(mant / 65536) % 256,
  276. math.floor(mant / 256) % 256,
  277. mant % 256
  278. )
  279. end
  280. end
  281.  
  282. function decodeDouble(str)
  283. -- This was shamelessly stolen from lua-MessagePack
  284. local a, b, c, d, e, f, g, h = str:byte(1, 8)
  285. local sign = a > 127 and -1 or 1
  286. local expo = (a % 128) * 16 + math.floor(b / 16)
  287. local mant = ((((((b % 16) * 256 + c) * 256 + d) * 256 + e) * 256 + f) * 256 + g) * 256 + h
  288. if mant == 0 and expo == 0 then
  289. return sign * 0.0
  290. elseif expo == 2047 then
  291. if mant == 0 then
  292. return sign * math.huge
  293. else
  294. return 0.0/0.0
  295. end
  296. else
  297. return sign * ((1.0 + mant / 4503599627370496.0) * 2 ^ (expo - 1023))
  298. end
  299. end
  300.  
  301. function encodeFloat(v)
  302. -- This was shamelessly stolen from lua-MessagePack
  303. local sign = v < 0 and 128 or 0
  304. local mant, expo = frexp(v)
  305.  
  306. if mant ~= mant then
  307. -- NaN
  308. return "\255\136\0\0"
  309. elseif mant == math.huge or expo > 128 then
  310. if sign then
  311. -- +inf
  312. return "\127\128\0\0"
  313. else
  314. -- -inf
  315. return "\255\128\0\0"
  316. end
  317. elseif (mant == 0 and expo == 0) or expo < -126 then
  318. -- zero
  319. return string.byte(sign).."\0\0\0"
  320. else
  321. expo = expo + 126
  322. mant = math.floor((math.abs(mant) * 2.0 - 1.0) * 8388608)
  323. return string.char(
  324. sign + math.floor(expo / 2),
  325. (expo % 2) * 128 + math.floor(mant / 65536),
  326. math.floor(mant / 256) % 256,
  327. mant % 256
  328. )
  329. end
  330. end
  331.  
  332. function decodeFloat(str)
  333. -- This was shamelessly stolen from lua-MessagePack
  334. local a, b, c, d = str:byte(1, 4)
  335. local sign = a > 127 and -1 or 1
  336. local expo = (a % 128) * 2 + math.floor(b / 128)
  337. local mant = ((b % 128) * 256 + c) * 256 + d
  338. if mant == 0 and expo == 0 then
  339. return sign * 0.0
  340. elseif expo == 255 then
  341. if mant == 0 then
  342. return sign * math.huge
  343. else
  344. return 0.0/0.0
  345. end
  346. else
  347. return sign * ((1.0 + mant / 8388608) * 2 ^ (expo - 127))
  348. end
  349. end
  350. end
  351.  
  352. local function isCorrectTypeID(typeID)
  353. return
  354. type(typeID) == "number" and (
  355. typeID == TAG_BYTE or
  356. typeID == TAG_SHORT or
  357. typeID == TAG_INT or
  358. typeID == TAG_LONG or
  359. typeID == TAG_FLOAT or
  360. typeID == TAG_DOUBLE or
  361. typeID == TAG_BYTE_ARRAY or
  362. typeID == TAG_STRING or
  363. typeID == TAG_LIST or
  364. typeID == TAG_COMPOUND or
  365. typeID == TAG_INT_ARRAY or
  366. typeID == TAG_LONG_ARRAY)
  367. end
  368.  
  369. if isLua53 then
  370. function encodeShort(v)
  371. return string.pack(">i2", v)
  372. end
  373.  
  374. function decodeShort(str)
  375. return string.unpack(">i2", str:sub(1, 2))
  376. end
  377.  
  378. function encodeInt(v)
  379. return string.pack(">i4", v)
  380. end
  381.  
  382. function decodeInt(str)
  383. return string.unpack(">i4", str:sub(1, 4))
  384. end
  385. else
  386. function encodeShort(v)
  387. v = v % 65536
  388. return string.char(math.floor(v / 256), math.floor(v) % 256)
  389. end
  390.  
  391. function decodeShort(str)
  392. local a, b = str:byte(1, 2)
  393. return a * 256 + b
  394. end
  395.  
  396. function encodeInt(v)
  397. v = v % 4294967296
  398. return string.char(
  399. math.floor(v / 16777216),
  400. math.floor(v / 65536) % 256,
  401. math.floor(v / 256) % 256,
  402. math.floor(v) % 256
  403. )
  404. end
  405.  
  406. function decodeInt(str)
  407. local a, b, c, d = str:byte(1, 4)
  408. return a * 16777216 + b * 65536 + c * 256 + d
  409. end
  410. end
  411.  
  412. local function limitString(v)
  413. v = v:gsub("%z", "\192\128") -- Java modified UTF-8
  414. return v:sub(1, math.min(#v, 32767))
  415. end
  416.  
  417. -- NBT TAG_* class
  418. local TagClass = {
  419. -- Names, no need to use separate table
  420. "TAG_Byte",
  421. "TAG_Short",
  422. "TAG_Int",
  423. "TAG_Long",
  424. "TAG_Float",
  425. "TAG_Double",
  426. "TAG_Byte_Array",
  427. "TAG_String",
  428. "TAG_List",
  429. "TAG_Compound",
  430. "TAG_Int_Array",
  431. "TAG_Long_Array"
  432. }
  433. TagClass.__index = TagClass
  434.  
  435. function TagClass.new(type, val, name)
  436. local t = setmetatable({
  437. -- No sanity check because this class is used internally
  438. _value = val,
  439. _name = name or "",
  440. _type = assert(tonumber(type), "invalid type id")
  441. }, TagClass)
  442. return t
  443. end
  444.  
  445. -- This actually pretty print and
  446. -- may result in very long string
  447. function TagClass:__tostring(indent, noname)
  448. indent = indent or 0
  449. local prefix
  450. local ind = string.rep(" ", indent)
  451.  
  452. if noname then
  453. prefix = string.format("%s%s(None): ", ind, TagClass[self._type])
  454. else
  455. prefix = string.format("%s%s(%q): ", ind, TagClass[self._type], self._name)
  456. end
  457.  
  458. if
  459. self._type == TAG_BYTE or
  460. self._type == TAG_SHORT or
  461. self._type == TAG_INT
  462. then
  463. return string.format("%s%d", prefix, self._value)
  464. elseif
  465. self._type == TAG_FLOAT or
  466. self._type == TAG_DOUBLE
  467. then
  468. return string.format("%s%.14g", prefix, self._value)
  469. elseif self._type == TAG_LONG then
  470. return string.format("%s%s", prefix, longIntTostring(self._value))
  471. elseif self._type == TAG_STRING then
  472. return string.format("%s%q", prefix, self._value)
  473. elseif
  474. self._type == TAG_LIST or
  475. self._type == TAG_COMPOUND
  476. then
  477. local isList = self._type == TAG_LIST
  478. local strb = {}
  479. local j = indent + 1
  480.  
  481. for i, v in ipairs(self._value) do
  482. strb[i] = v:__tostring(j, isList)
  483. end
  484.  
  485. local len = #strb
  486. return string.format(
  487. "%s%d entr%s\n%s{\n%s\n%s}", -- uh crazy string formats
  488. prefix, len,
  489. len == 1 and "y" or "ies",
  490. ind,
  491. table.concat(strb, "\n"),
  492. ind
  493. )
  494. elseif
  495. self._type == TAG_BYTE_ARRAY or
  496. self._type == TAG_INT_ARRAY
  497. then
  498. -- value is table in this case
  499. local strb = {}
  500.  
  501. for i, v in ipairs(self._value) do
  502. strb[i] = tostring(v)
  503. end
  504.  
  505. return string.format("%s[%s]", prefix, table.concat(strb, ", "))
  506. elseif self._type == TAG_LONG_ARRAY then
  507. -- same as above but have to call longIntTostring
  508. local strb = {}
  509.  
  510. for i, v in ipairs(self._value) do
  511. strb[i] = longIntTostring(v)
  512. end
  513.  
  514. return string.format("%s[%s]", prefix, table.concat(strb, ", "))
  515. end
  516. end
  517.  
  518. function TagClass:getTypeID()
  519. return self._type
  520. end
  521.  
  522. function TagClass:getName()
  523. return self._name
  524. end
  525.  
  526. function TagClass:getString()
  527. if
  528. self._type == TAG_BYTE_ARRAY or
  529. self._type == TAG_LIST or
  530. self._type == TAG_COMPOUND or
  531. self._type == TAG_INT_ARRAY or
  532. self._type == TAG_LONG_ARRAY
  533. then
  534. error("attempt to get string of array value")
  535. end
  536.  
  537. return tostring(self._value)
  538. end
  539.  
  540. function TagClass:getNumber()
  541. if
  542. self._type == TAG_BYTE or
  543. self._type == TAG_SHORT or
  544. self._type == TAG_INT or
  545. self._type == TAG_LONG or
  546. self._type == TAG_FLOAT or
  547. self._type == TAG_DOUBLE
  548. then
  549. return tonumber(self._value) + 0.0 -- Lua 5.3 to float
  550. elseif self._type == TAG_STRING then
  551. -- Try tonumber it
  552. local num = tonumber(self._value)
  553. if num then
  554. return num + 0.0 -- Lua 5.3 to float
  555. end
  556. end
  557.  
  558. error("attempt to get number of invalid type")
  559. end
  560.  
  561. function TagClass:getInteger()
  562. if
  563. self._type == TAG_BYTE or
  564. self._type == TAG_SHORT or
  565. self._type == TAG_INT or
  566. self._type == TAG_FLOAT or
  567. self._type == TAG_DOUBLE
  568. then
  569. return toInteger(self._value < 0 and math.ceil(self._value) or math.floor(self._value))
  570. elseif self._type == TAG_LONG then
  571. return getLongInt(self)
  572. elseif self._type == TAG_STRING then
  573. -- Try tonumber first
  574. local num = tonumber(self._value)
  575. if num then
  576. return toInteger(num < 0 and math.ceil(num) or math.floor(num))
  577. end
  578. end
  579.  
  580. error("attempt to get integer of invalid type")
  581. end
  582.  
  583. function TagClass:getValue()
  584. return self._value
  585. end
  586.  
  587. function TagClass:copy(shallow)
  588. if self._type == TAG_LIST or self._type == TAG_COMPOUND then
  589. if shallow then
  590. -- Only copy top element
  591. local new = {}
  592.  
  593. for k, v in pairs(self._value) do
  594. new[k] = v
  595. end
  596.  
  597. return TagClass.new(self._type, new, self._name)
  598. else
  599. -- Copy recursively
  600. local new = {}
  601.  
  602. for k, v in pairs(self._value) do
  603. new[k] = v:copy()
  604. end
  605.  
  606. return TagClass.new(self._type, new, self._name)
  607. end
  608. elseif
  609. self._type == TAG_BYTE_ARRAY or
  610. self._type == TAG_INT_ARRAY or
  611. self._type == TAG_LONG_ARRAY
  612. then
  613. -- Copy elements
  614. local new = {}
  615.  
  616. for i, v in ipairs(self._value) do
  617. new[i] = v
  618. end
  619.  
  620. return TagClass.new(self._type, new, self._name)
  621. else
  622. return TagClass.new(self._type, self._value, self._name)
  623. end
  624. end
  625.  
  626. function TagClass:encode(noprefix)
  627. local name
  628. if not(noprefix) then
  629. name = limitString(self._name)
  630. end
  631.  
  632. if self._type == TAG_BYTE then
  633. if noprefix then
  634. return string.char(self._value % 256)
  635. else
  636. -- May strip UTF-8 encoding
  637. return "\1"..encodeShort(#name)..name..string.char(self._value % 256)
  638. end
  639. elseif self._type == TAG_BYTE_ARRAY then
  640. local strb = {}
  641.  
  642. -- Convert all bytes to string
  643. for i, v in ipairs(self._value) do
  644. strb[i] = string.char(v % 256)
  645. end
  646.  
  647. if noprefix then
  648. return encodeInt(#strb)..table.concat(strb)
  649. else
  650. return "\7"..encodeShort(#name)..name..encodeInt(#strb)..table.concat(strb)
  651. end
  652. elseif self._type == TAG_SHORT then
  653. if noprefix then
  654. return encodeShort(self._value)
  655. else
  656. return "\2"..encodeShort(#name)..name..encodeShort(self._value)
  657. end
  658. elseif self._type == TAG_INT then
  659. if noprefix then
  660. return encodeInt(self._value)
  661. else
  662. return "\3"..encodeShort(#name)..name..encodeInt(self._value)
  663. end
  664. elseif self._type == TAG_INT_ARRAY then
  665. local strb = {}
  666.  
  667. -- Convert all values to int
  668. for i, v in ipairs(self._value) do
  669. strb[i] = encodeInt(v)
  670. end
  671.  
  672. if noprefix then
  673. return encodeInt(#strb)..table.concat(strb)
  674. else
  675. return "\11"..encodeShort(#name)..name..encodeInt(#strb)..table.concat(strb)
  676. end
  677. elseif self._type == TAG_LONG then
  678. if noprefix then
  679. return encodeLongInt(self._value)
  680. else
  681. return "\4"..encodeShort(#name)..name..encodeLongInt(self._value)
  682. end
  683. elseif self._type == TAG_LONG_ARRAY then
  684. local strb = {}
  685.  
  686. -- Convert all values to long
  687. for i, v in ipairs(self._value) do
  688. strb[i] = encodeLongInt(v)
  689. end
  690.  
  691. if noprefix then
  692. return encodeInt(#strb)..table.concat(strb)
  693. else
  694. return "\12"..encodeShort(#name)..name..encodeInt(#strb)..table.concat(strb)
  695. end
  696. elseif self._type == TAG_FLOAT then
  697. if noprefix then
  698. return encodeFloat(self._value)
  699. else
  700. return "\5"..encodeShort(#name)..name..encodeFloat(self._value)
  701. end
  702. elseif self._type == TAG_DOUBLE then
  703. if noprefix then
  704. return encodeDouble(self._value)
  705. else
  706. return "\6"..encodeShort(#name)..name..encodeDouble(self._value)
  707. end
  708. elseif self._type == TAG_STRING then
  709. local valueTrunc = limitString(self._value)
  710. if noprefix then
  711. return encodeShort(#valueTrunc)..valueTrunc
  712. else
  713. return "\8"..encodeShort(#name)..name..encodeShort(#valueTrunc)..valueTrunc
  714. end
  715. elseif self._type == TAG_LIST then
  716. -- Special case if length is 0
  717. if #self._value == 0 then
  718. if noprefix then
  719. return "\0\0\0\0\0"
  720. else
  721. return "\9"..encodeShort(#name)..name.."\0\0\0\0\0"
  722. end
  723. else
  724. local typeID = 0
  725. local strb = {}
  726.  
  727. for i, v in ipairs(self._value) do
  728. local id = v:getTypeID()
  729.  
  730. if typeID == 0 then
  731. typeID = id
  732. elseif typeID ~= id then
  733. error("TAG_List type inconsistent (old "..typeID.." new "..id..")")
  734. end
  735.  
  736. strb[i] = v:encode(true)
  737. end
  738.  
  739. if noprefix then
  740. return string.char(typeID)..encodeInt(#strb)..table.concat(strb)
  741. else
  742. return "\9"..encodeShort(#name)..name..string.char(typeID)..encodeInt(#strb)..table.concat(strb)
  743. end
  744. end
  745. elseif self._type == TAG_COMPOUND then
  746. local strb = {}
  747.  
  748. for i, v in ipairs(self._value) do
  749. strb[i] = v:encode()
  750. end
  751.  
  752. if noprefix then
  753. return table.concat(strb).."\0"
  754. else
  755. return "\10"..encodeShort(#name)..name..table.concat(strb).."\0"
  756. end
  757. else
  758. return ""
  759. end
  760. end
  761.  
  762. -- Public NBT functions
  763.  
  764. --- Create new `TAG_Byte` object.
  765. -- @tparam number v Byte value
  766. -- @tparam[opt] string name Tag name
  767. -- @return Tag class with `TAG_Byte` type.
  768. -- @warning Value will be converted integer and
  769. -- clamped to -128...127 if outside range
  770. function nbt.newByte(v, name)
  771. v = assert(tonumber(v), "invalid number passed")
  772. return TagClass.new(TAG_BYTE, toInteger(math.min(math.max(v, -128), 127)), name)
  773. end
  774.  
  775. --- Create new `TAG_Short` object.
  776. -- @tparam number v Short value
  777. -- @tparam[opt] string name Tag name
  778. -- @return Tag class with `TAG_Short` type.
  779. -- @warning Value will be converted integer and
  780. -- clamped to -32768...32767 if outside range
  781. function nbt.newShort(v, name)
  782. v = assert(tonumber(v), "invalid number passed")
  783. return TagClass.new(TAG_SHORT, toInteger(math.min(math.max(v, -32768), 32767)), name)
  784. end
  785.  
  786. --- Create new `TAG_Int` object.
  787. -- @tparam number v Int value
  788. -- @tparam[opt] string name Tag name
  789. -- @return Tag class with `TAG_Int` type.
  790. -- @warning Value will be converted integer and
  791. -- clamped to -2147483648...2147483647 if outside range
  792. function nbt.newInt(v, name)
  793. v = assert(tonumber(v), "invalid number passed")
  794. return TagClass.new(TAG_INT, toInteger(math.min(math.max(v, -2147483648), 2147483647)), name)
  795. end
  796.  
  797. if isLuaJIT then
  798. -- As much as I want to avoid FFI
  799. local ffi = require("ffi")
  800.  
  801. function nbt.newLong(v, name)
  802. v = ffi.cast("int64_t", v)
  803. return TagClass.new(TAG_LONG, v, name)
  804. end
  805.  
  806. function nbt.newLongArray(value, name)
  807. local list = {}
  808.  
  809. for i, v in ipairs(value) do
  810. if getmetatable(v) == TagClass then
  811. v = v:getInteger()
  812. elseif type(v) ~= "number" then
  813. v = tonumber(v)
  814. end
  815.  
  816. if v == nil then
  817. error("invalid value at #"..i)
  818. else
  819. v = ffi.cast("int64_t", v)
  820. end
  821.  
  822. list[i] = v
  823. end
  824.  
  825. return TagClass.new(TAG_LONG_ARRAY, list, name)
  826. end
  827. else
  828. function nbt.newLong(v, name)
  829. v = assert(tonumber(v), "invalid number passed")
  830. return TagClass.new(TAG_INT, toInteger(math.min(math.max(v, -9223372036854775808), 9223372036854775807)), name)
  831. end
  832.  
  833. function nbt.newLongArray(value, name)
  834. local list = {}
  835.  
  836. for i, v in ipairs(value) do
  837. if getmetatable(v) == TagClass then
  838. v = v:getInteger()
  839. elseif type(v) ~= "number" then
  840. v = tonumber(v)
  841. end
  842.  
  843. if v == nil then
  844. error("invalid value at #"..i)
  845. else
  846. v = toInteger(math.min(math.max(v, -9223372036854775808), 9223372036854775807))
  847. end
  848.  
  849. list[i] = v
  850. end
  851.  
  852. return TagClass.new(TAG_LONG_ARRAY, list, name)
  853. end
  854. end
  855.  
  856. --- Create new `TAG_Float` object.
  857. -- @tparam number v Float value
  858. -- @tparam[opt] string name Tag name
  859. -- @return Tag class with `TAG_Float` type.
  860. function nbt.newFloat(v, name)
  861. return TagClass.new(TAG_FLOAT, v, name)
  862. end
  863.  
  864. --- Create new `TAG_Double` object.
  865. -- @tparam number v Double float value
  866. -- @tparam[opt] string name Tag name
  867. -- @return Tag class with `TAG_Double` type.
  868. function nbt.newDouble(v, name)
  869. return TagClass.new(TAG_DOUBLE, v, name)
  870. end
  871.  
  872. --- Create new `TAG_String` object.
  873. -- @tparam string v String value
  874. -- @tparam[opt] string name Tag name
  875. -- @return Tag class with `TAG_String` type.
  876. function nbt.newString(v, name)
  877. return TagClass.new(TAG_STRING, tostring(v), name)
  878. end
  879.  
  880. --- Create new `TAG_Compound` object.
  881. -- @tparam table value List of key-value pairs in table
  882. -- @tparam[opt] string name description
  883. -- @return Tag class with `TAG_List` type.
  884. -- @warning If `TAG_*` class object is passed, this function will take
  885. -- the ownership of that object and modify it, so make sure to clone the
  886. -- object if needed.
  887. function nbt.newCompound(value, name)
  888. local compound = {}
  889.  
  890. for k, v in pairs(value) do
  891. if type(k) ~= "string" then
  892. error(string.format("invalid key %q", k))
  893. end
  894.  
  895. if getmetatable(v) == TagClass then
  896. v._name = k
  897. compound[#compound + 1] = v
  898. compound[k] = v
  899. else
  900. local datatype = type(v)
  901. -- We have to do some guessing here
  902. -- "cdata" must also be checked because LuaJIT boxed 64-bit int
  903. if datatype == "number" or datatype == "cdata" then
  904. -- if value is integer, do integer guessing
  905. if v % 1 == 0 then
  906. local y
  907.  
  908. if v >= -128 and v <= 127 then
  909. y = nbt.newByte(tonumber(v), k)
  910. elseif v >= -32768 and v <= 32767 then
  911. y = nbt.newShort(tonumber(v), k)
  912. elseif v >= -2147483648 and v <= 2147483647 then
  913. y = nbt.newInt(tonumber(v), k)
  914. else
  915. y = nbt.newLong(v, k)
  916. end
  917.  
  918. y._name = k
  919. compound[#compound + 1] = y
  920. compound[k] = y
  921. else
  922. -- assume double, default Lua
  923. local y = nbt.newDouble(v, k)
  924. compound[#compound + 1] = y
  925. compound[k] = y
  926. end
  927. elseif datatype == "string" then
  928. local y = nbt.newString(v, k)
  929. y._name = k
  930. compound[#compound + 1] = y
  931. compound[k] = y
  932. else
  933. -- Should've implement type checking but
  934. -- in Lua it's too complex and may slow
  935. error(string.format("invalid value for key %q", k))
  936. end
  937. end
  938. end
  939.  
  940. return TagClass.new(TAG_COMPOUND, compound, name)
  941. end
  942.  
  943. --- Create new `TAG_List` object.
  944. -- @tparam number typeID Valid NBT type ID (`nbt.TAG_*` constants) excluding `TAG_END`
  945. -- @tparam table value List of values in table
  946. -- @tparam[opt] string name description
  947. -- @return Tag class with `TAG_List` type.
  948. -- @warning If `TAG_*` class object is passed, this function will take
  949. -- the ownership of that object, so make sure to clone the object if needed.
  950. function nbt.newList(typeID, value, name)
  951. assert(isCorrectTypeID(typeID), "invalid type ID passed")
  952.  
  953. local constructorFunction
  954. local list = {}
  955.  
  956. if typeID == TAG_BYTE then
  957. constructorFunction = nbt.newByte
  958. elseif typeID == TAG_SHORT then
  959. constructorFunction = nbt.newShort
  960. elseif typeID == TAG_INT then
  961. constructorFunction = nbt.newInt
  962. elseif typeID == TAG_LONG then
  963. constructorFunction = nbt.newLong
  964. elseif typeID == TAG_STRING then
  965. constructorFunction = nbt.newString
  966. end
  967.  
  968. for i, v in ipairs(value) do
  969. if getmetatable(v) == TagClass then
  970. if v:getTypeID() == typeID then
  971. list[i] = v
  972. else
  973. error("type ID mismatch at table index #"..i)
  974. end
  975. elseif constructorFunction == nil then
  976. error("cannot type deduce value at index #"..i)
  977. end
  978.  
  979. list[i] = constructorFunction(v)
  980. end
  981.  
  982. return TagClass.new(TAG_LIST, list, name)
  983. end
  984.  
  985. --- Create new `TAG_Byte_Array` object.
  986. -- @tparam table value List of values in table
  987. -- @tparam[opt] string name description
  988. -- @return Tag class with `TAG_Byte_Array` type.
  989. function nbt.newByteArray(value, name)
  990. local list = {}
  991.  
  992. for i, v in ipairs(value) do
  993. if getmetatable(v) == TagClass then
  994. v = v:getInteger()
  995. elseif type(v) ~= "number" then
  996. v = tonumber(v)
  997. end
  998.  
  999. if v == nil then
  1000. error("invalid value at #"..i)
  1001. else
  1002. v = toInteger(math.min(math.max(v, -128), 127))
  1003. end
  1004.  
  1005. list[i] = v
  1006. end
  1007.  
  1008. return TagClass.new(TAG_BYTE_ARRAY, list, name)
  1009. end
  1010.  
  1011. --- Create new `TAG_Int_Array` object.
  1012. -- @tparam table value List of values in table
  1013. -- @tparam[opt] string name description
  1014. -- @return Tag class with `TAG_Int_Array` type.
  1015. function nbt.newIntArray(value, name)
  1016. local list = {}
  1017.  
  1018. for i, v in ipairs(value) do
  1019. if getmetatable(v) == TagClass then
  1020. v = v:getInteger()
  1021. elseif type(v) ~= "number" then
  1022. v = tonumber(v)
  1023. end
  1024.  
  1025. if v == nil then
  1026. error("invalid value at #"..i)
  1027. else
  1028. v = toInteger(math.min(math.max(v, -2147483648), 2147483647))
  1029. end
  1030.  
  1031. list[i] = v
  1032. end
  1033.  
  1034. return TagClass.new(TAG_INT_ARRAY, list, name)
  1035. end
  1036.  
  1037. -- Internal use
  1038. local IncrementalReader = {}
  1039. IncrementalReader.__index = IncrementalReader
  1040.  
  1041. function IncrementalReader.new(input)
  1042. local datatype = type(input)
  1043. if datatype == "string" then
  1044. return setmetatable({string = input, pos = 0}, IncrementalReader)
  1045. elseif datatype == "function" then
  1046. return setmetatable({buffer = input, string = "", pos = 0}, IncrementalReader)
  1047. end
  1048. end
  1049.  
  1050. function IncrementalReader:read(n)
  1051. if n <= 0 then return "" end
  1052.  
  1053. if self.string and #self.string < n then
  1054. if self.buffer then
  1055. local minsize = n - #self.string
  1056. local str, msg = self.buffer(minsize)
  1057.  
  1058. if not(str) then error(msg)
  1059. elseif #str == 0 then error("returned buffer is empty string")
  1060. elseif #str < minsize then error("returned buffer is less than minsize") end
  1061.  
  1062. self.string = self.string..str
  1063. else
  1064. error("unexpected eof at pos "..self.pos)
  1065. end
  1066. end
  1067.  
  1068. local v = self.string:sub(1, n)
  1069. self.string = self.string:sub(n + 1)
  1070. self.pos = self.pos + n
  1071. return v
  1072. end
  1073.  
  1074. function IncrementalReader:getPos()
  1075. return self.pos
  1076. end
  1077.  
  1078. local function deserializeNBTFull(reader, typeID, readName, createTag)
  1079. if not(typeID) then
  1080. typeID = deserializeNBTFull(reader, TAG_BYTE)
  1081. end
  1082.  
  1083. -- This must be done early
  1084. if typeID == TAG_END then
  1085. return nil, nil, TAG_END
  1086. end
  1087.  
  1088. if readName == true then
  1089. local namelen = decodeShort(reader:read(2))
  1090. readName = (reader:read(namelen):gsub("\192\128", "\0"))
  1091. else
  1092. readName = nil
  1093. end
  1094.  
  1095. if typeID == TAG_BYTE then
  1096. local b = reader:read(1):byte()
  1097. if b > 127 then
  1098. b = b - 256
  1099. end
  1100. return b, readName, TAG_BYTE
  1101. elseif typeID == TAG_SHORT then
  1102. return decodeShort(reader:read(2)), readName, TAG_SHORT
  1103. elseif typeID == TAG_INT then
  1104. return decodeInt(reader:read(4)), readName, TAG_INT
  1105. elseif typeID == TAG_LONG then
  1106. return decodeLongInt(reader:read(8)), readName, TAG_LONG
  1107. elseif typeID == TAG_FLOAT then
  1108. return decodeFloat(reader:read(4)), readName, TAG_FLOAT
  1109. elseif typeID == TAG_DOUBLE then
  1110. return decodeDouble(reader:read(8)), readName, TAG_DOUBLE
  1111. elseif typeID == TAG_BYTE_ARRAY then
  1112. local len = decodeInt(reader:read(4))
  1113. local ret = {}
  1114.  
  1115. for i = 1, len do
  1116. ret[i] = deserializeNBTFull(reader, TAG_BYTE)
  1117. end
  1118.  
  1119. return ret, readName, TAG_BYTE_ARRAY
  1120. elseif typeID == TAG_STRING then
  1121. local len = decodeShort(reader:read(2))
  1122. return (reader:read(len):gsub("\192\128", "\0")), readName, TAG_STRING
  1123. elseif typeID == TAG_LIST then
  1124. local targetTypeID = deserializeNBTFull(reader, TAG_BYTE)
  1125. local len = decodeInt(reader:read(4))
  1126. local ret = {}
  1127.  
  1128. if createTag then
  1129. for i = 1, len do
  1130. ret[i] = TagClass.new(targetTypeID, deserializeNBTFull(reader, targetTypeID, false, true))
  1131. end
  1132. else
  1133. for i = 1, len do
  1134. ret[i] = deserializeNBTFull(reader, targetTypeID)
  1135. end
  1136. end
  1137.  
  1138. return ret, readName, TAG_LIST
  1139. elseif typeID == TAG_COMPOUND then
  1140. local ret = {}
  1141.  
  1142. while true do
  1143. local value, name, targetTypeID = deserializeNBTFull(reader, nil, true, createTag)
  1144. if targetTypeID == TAG_END then
  1145. break
  1146. end
  1147.  
  1148. if createTag then
  1149. local x = TagClass.new(targetTypeID, value, name)
  1150. ret[name] = x
  1151. ret[#ret + 1] = x
  1152. else
  1153. ret[name] = value
  1154. ret[#ret + 1] = value
  1155. end
  1156. end
  1157.  
  1158. return ret, readName, TAG_COMPOUND
  1159. elseif typeID == TAG_INT_ARRAY then
  1160. local len = decodeInt(reader:read(4))
  1161. local ret = {}
  1162.  
  1163. for i = 1, len do
  1164. ret[i] = deserializeNBTFull(reader, TAG_INT)
  1165. end
  1166.  
  1167. return ret, readName, TAG_INT_ARRAY
  1168. elseif typeID == TAG_LONG_ARRAY then
  1169. local len = decodeInt(reader:read(4))
  1170. local ret = {}
  1171.  
  1172. for i = 1, len do
  1173. ret[i] = deserializeNBTFull(reader, TAG_LONG)
  1174. end
  1175.  
  1176. return ret, readName, TAG_LONG_ARRAY
  1177. else
  1178. error("unknown tag ID "..typeID.." at "..reader:getPos())
  1179. end
  1180. end
  1181.  
  1182. --- Decode NBT data.
  1183. -- This can either decode into Tag class or plain Lua table.
  1184. -- @tparam string|function input uncompressed NBT input data or function
  1185. -- which returns uncompressed NBT data
  1186. -- @tparam string preservemode "tag" (default) returns full Tag class
  1187. -- or "plain" returns only plain Lua table
  1188. function nbt.decode(input, preservemode)
  1189. if type(input) ~= "string" then
  1190. error("bad argument #1 to `decode` (string expected)")
  1191. end
  1192.  
  1193. preservemode = preservemode or "tag"
  1194. local preservetag
  1195.  
  1196. -- Check data output mode
  1197. if preservemode == "tag" then
  1198. preservetag = true
  1199. elseif preservemode == "plain" then
  1200. preservetag = false
  1201. else
  1202. error("bad argument #2 to 'decode' (invalid 'preservemode')")
  1203. end
  1204.  
  1205. local reader = IncrementalReader.new(input)
  1206. local result, name, typeID = deserializeNBTFull(reader, nil, true, preservetag)
  1207.  
  1208. if preservetag then
  1209. result = TagClass.new(typeID, result, name)
  1210. return result
  1211. else
  1212. return result, name
  1213. end
  1214.  
  1215. end
  1216.  
  1217. return nbt
Add Comment
Please, Sign In to add comment