unpack.js 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  1. var decoder
  2. try {
  3. decoder = new TextDecoder()
  4. } catch(error) {}
  5. var src
  6. var srcEnd
  7. var position = 0
  8. var alreadySet
  9. const EMPTY_ARRAY = []
  10. var strings = EMPTY_ARRAY
  11. var stringPosition = 0
  12. var currentUnpackr = {}
  13. var currentStructures
  14. var srcString
  15. var srcStringStart = 0
  16. var srcStringEnd = 0
  17. var bundledStrings
  18. var referenceMap
  19. var currentExtensions = []
  20. var dataView
  21. var defaultOptions = {
  22. useRecords: false,
  23. mapsAsObjects: true
  24. }
  25. export class C1Type {}
  26. export const C1 = new C1Type()
  27. C1.name = 'MessagePack 0xC1'
  28. var sequentialMode = false
  29. var inlineObjectReadThreshold = 2
  30. var readStruct, onLoadedStructures, onSaveState
  31. var BlockedFunction // we use search and replace to change the next call to BlockedFunction to avoid CSP issues for
  32. // no-eval build
  33. try {
  34. new Function('')
  35. } catch(error) {
  36. // if eval variants are not supported, do not create inline object readers ever
  37. inlineObjectReadThreshold = Infinity
  38. }
  39. export class Unpackr {
  40. constructor(options) {
  41. if (options) {
  42. if (options.useRecords === false && options.mapsAsObjects === undefined)
  43. options.mapsAsObjects = true
  44. if (options.sequential && options.trusted !== false) {
  45. options.trusted = true;
  46. if (!options.structures && options.useRecords != false) {
  47. options.structures = []
  48. if (!options.maxSharedStructures)
  49. options.maxSharedStructures = 0
  50. }
  51. }
  52. if (options.structures)
  53. options.structures.sharedLength = options.structures.length
  54. else if (options.getStructures) {
  55. (options.structures = []).uninitialized = true // this is what we use to denote an uninitialized structures
  56. options.structures.sharedLength = 0
  57. }
  58. if (options.int64AsNumber) {
  59. options.int64AsType = 'number'
  60. }
  61. }
  62. Object.assign(this, options)
  63. }
  64. unpack(source, options) {
  65. if (src) {
  66. // re-entrant execution, save the state and restore it after we do this unpack
  67. return saveState(() => {
  68. clearSource()
  69. return this ? this.unpack(source, options) : Unpackr.prototype.unpack.call(defaultOptions, source, options)
  70. })
  71. }
  72. if (!source.buffer && source.constructor === ArrayBuffer)
  73. source = typeof Buffer !== 'undefined' ? Buffer.from(source) : new Uint8Array(source);
  74. if (typeof options === 'object') {
  75. srcEnd = options.end || source.length
  76. position = options.start || 0
  77. } else {
  78. position = 0
  79. srcEnd = options > -1 ? options : source.length
  80. }
  81. stringPosition = 0
  82. srcStringEnd = 0
  83. srcString = null
  84. strings = EMPTY_ARRAY
  85. bundledStrings = null
  86. src = source
  87. // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
  88. // technique for getting data from a database where it can be copied into an existing buffer instead of creating
  89. // new ones
  90. try {
  91. dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))
  92. } catch(error) {
  93. // if it doesn't have a buffer, maybe it is the wrong type of object
  94. src = null
  95. if (source instanceof Uint8Array)
  96. throw error
  97. throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
  98. }
  99. if (this instanceof Unpackr) {
  100. currentUnpackr = this
  101. if (this.structures) {
  102. currentStructures = this.structures
  103. return checkedRead(options)
  104. } else if (!currentStructures || currentStructures.length > 0) {
  105. currentStructures = []
  106. }
  107. } else {
  108. currentUnpackr = defaultOptions
  109. if (!currentStructures || currentStructures.length > 0)
  110. currentStructures = []
  111. }
  112. return checkedRead(options)
  113. }
  114. unpackMultiple(source, forEach) {
  115. let values, lastPosition = 0
  116. try {
  117. sequentialMode = true
  118. let size = source.length
  119. let value = this ? this.unpack(source, size) : defaultUnpackr.unpack(source, size)
  120. if (forEach) {
  121. if (forEach(value, lastPosition, position) === false) return;
  122. while(position < size) {
  123. lastPosition = position
  124. if (forEach(checkedRead(), lastPosition, position) === false) {
  125. return
  126. }
  127. }
  128. }
  129. else {
  130. values = [ value ]
  131. while(position < size) {
  132. lastPosition = position
  133. values.push(checkedRead())
  134. }
  135. return values
  136. }
  137. } catch(error) {
  138. error.lastPosition = lastPosition
  139. error.values = values
  140. throw error
  141. } finally {
  142. sequentialMode = false
  143. clearSource()
  144. }
  145. }
  146. _mergeStructures(loadedStructures, existingStructures) {
  147. if (onLoadedStructures)
  148. loadedStructures = onLoadedStructures.call(this, loadedStructures);
  149. loadedStructures = loadedStructures || []
  150. if (Object.isFrozen(loadedStructures))
  151. loadedStructures = loadedStructures.map(structure => structure.slice(0))
  152. for (let i = 0, l = loadedStructures.length; i < l; i++) {
  153. let structure = loadedStructures[i]
  154. if (structure) {
  155. structure.isShared = true
  156. if (i >= 32)
  157. structure.highByte = (i - 32) >> 5
  158. }
  159. }
  160. loadedStructures.sharedLength = loadedStructures.length
  161. for (let id in existingStructures || []) {
  162. if (id >= 0) {
  163. let structure = loadedStructures[id]
  164. let existing = existingStructures[id]
  165. if (existing) {
  166. if (structure)
  167. (loadedStructures.restoreStructures || (loadedStructures.restoreStructures = []))[id] = structure
  168. loadedStructures[id] = existing
  169. }
  170. }
  171. }
  172. return this.structures = loadedStructures
  173. }
  174. decode(source, options) {
  175. return this.unpack(source, options)
  176. }
  177. }
  178. export function getPosition() {
  179. return position
  180. }
  181. export function checkedRead(options) {
  182. try {
  183. if (!currentUnpackr.trusted && !sequentialMode) {
  184. let sharedLength = currentStructures.sharedLength || 0
  185. if (sharedLength < currentStructures.length)
  186. currentStructures.length = sharedLength
  187. }
  188. let result
  189. if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && src[position] >= 0x20 && readStruct) {
  190. result = readStruct(src, position, srcEnd, currentUnpackr)
  191. src = null // dispose of this so that recursive unpack calls don't save state
  192. if (!(options && options.lazy) && result)
  193. result = result.toJSON()
  194. position = srcEnd
  195. } else
  196. result = read()
  197. if (bundledStrings) { // bundled strings to skip past
  198. position = bundledStrings.postBundlePosition
  199. bundledStrings = null
  200. }
  201. if (sequentialMode)
  202. // we only need to restore the structures if there was an error, but if we completed a read,
  203. // we can clear this out and keep the structures we read
  204. currentStructures.restoreStructures = null
  205. if (position == srcEnd) {
  206. // finished reading this source, cleanup references
  207. if (currentStructures && currentStructures.restoreStructures)
  208. restoreStructures()
  209. currentStructures = null
  210. src = null
  211. if (referenceMap)
  212. referenceMap = null
  213. } else if (position > srcEnd) {
  214. // over read
  215. throw new Error('Unexpected end of MessagePack data')
  216. } else if (!sequentialMode) {
  217. let jsonView;
  218. try {
  219. jsonView = JSON.stringify(result, (_, value) => typeof value === "bigint" ? `${value}n` : value).slice(0, 100)
  220. } catch(error) {
  221. jsonView = '(JSON view not available ' + error + ')'
  222. }
  223. throw new Error('Data read, but end of buffer not reached ' + jsonView)
  224. }
  225. // else more to read, but we are reading sequentially, so don't clear source yet
  226. return result
  227. } catch(error) {
  228. if (currentStructures && currentStructures.restoreStructures)
  229. restoreStructures()
  230. clearSource()
  231. if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer') || position > srcEnd) {
  232. error.incomplete = true
  233. }
  234. throw error
  235. }
  236. }
  237. function restoreStructures() {
  238. for (let id in currentStructures.restoreStructures) {
  239. currentStructures[id] = currentStructures.restoreStructures[id]
  240. }
  241. currentStructures.restoreStructures = null
  242. }
  243. export function read() {
  244. let token = src[position++]
  245. if (token < 0xa0) {
  246. if (token < 0x80) {
  247. if (token < 0x40)
  248. return token
  249. else {
  250. let structure = currentStructures[token & 0x3f] ||
  251. currentUnpackr.getStructures && loadStructures()[token & 0x3f]
  252. if (structure) {
  253. if (!structure.read) {
  254. structure.read = createStructureReader(structure, token & 0x3f)
  255. }
  256. return structure.read()
  257. } else
  258. return token
  259. }
  260. } else if (token < 0x90) {
  261. // map
  262. token -= 0x80
  263. if (currentUnpackr.mapsAsObjects) {
  264. let object = {}
  265. for (let i = 0; i < token; i++) {
  266. let key = readKey()
  267. if (key === '__proto__')
  268. key = '__proto_'
  269. object[key] = read()
  270. }
  271. return object
  272. } else {
  273. let map = new Map()
  274. for (let i = 0; i < token; i++) {
  275. map.set(read(), read())
  276. }
  277. return map
  278. }
  279. } else {
  280. token -= 0x90
  281. let array = new Array(token)
  282. for (let i = 0; i < token; i++) {
  283. array[i] = read()
  284. }
  285. if (currentUnpackr.freezeData)
  286. return Object.freeze(array)
  287. return array
  288. }
  289. } else if (token < 0xc0) {
  290. // fixstr
  291. let length = token - 0xa0
  292. if (srcStringEnd >= position) {
  293. return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)
  294. }
  295. if (srcStringEnd == 0 && srcEnd < 140) {
  296. // for small blocks, avoiding the overhead of the extract call is helpful
  297. let string = length < 16 ? shortStringInJS(length) : longStringInJS(length)
  298. if (string != null)
  299. return string
  300. }
  301. return readFixedString(length)
  302. } else {
  303. let value
  304. switch (token) {
  305. case 0xc0: return null
  306. case 0xc1:
  307. if (bundledStrings) {
  308. value = read() // followed by the length of the string in characters (not bytes!)
  309. if (value > 0)
  310. return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
  311. else
  312. return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 -= value)
  313. }
  314. return C1; // "never-used", return special object to denote that
  315. case 0xc2: return false
  316. case 0xc3: return true
  317. case 0xc4:
  318. // bin 8
  319. value = src[position++]
  320. if (value === undefined)
  321. throw new Error('Unexpected end of buffer')
  322. return readBin(value)
  323. case 0xc5:
  324. // bin 16
  325. value = dataView.getUint16(position)
  326. position += 2
  327. return readBin(value)
  328. case 0xc6:
  329. // bin 32
  330. value = dataView.getUint32(position)
  331. position += 4
  332. return readBin(value)
  333. case 0xc7:
  334. // ext 8
  335. return readExt(src[position++])
  336. case 0xc8:
  337. // ext 16
  338. value = dataView.getUint16(position)
  339. position += 2
  340. return readExt(value)
  341. case 0xc9:
  342. // ext 32
  343. value = dataView.getUint32(position)
  344. position += 4
  345. return readExt(value)
  346. case 0xca:
  347. value = dataView.getFloat32(position)
  348. if (currentUnpackr.useFloat32 > 2) {
  349. // this does rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
  350. let multiplier = mult10[((src[position] & 0x7f) << 1) | (src[position + 1] >> 7)]
  351. position += 4
  352. return ((multiplier * value + (value > 0 ? 0.5 : -0.5)) >> 0) / multiplier
  353. }
  354. position += 4
  355. return value
  356. case 0xcb:
  357. value = dataView.getFloat64(position)
  358. position += 8
  359. return value
  360. // uint handlers
  361. case 0xcc:
  362. return src[position++]
  363. case 0xcd:
  364. value = dataView.getUint16(position)
  365. position += 2
  366. return value
  367. case 0xce:
  368. value = dataView.getUint32(position)
  369. position += 4
  370. return value
  371. case 0xcf:
  372. if (currentUnpackr.int64AsType === 'number') {
  373. value = dataView.getUint32(position) * 0x100000000
  374. value += dataView.getUint32(position + 4)
  375. } else if (currentUnpackr.int64AsType === 'string') {
  376. value = dataView.getBigUint64(position).toString()
  377. } else if (currentUnpackr.int64AsType === 'auto') {
  378. value = dataView.getBigUint64(position)
  379. if (value<=BigInt(2)<<BigInt(52)) value=Number(value)
  380. } else
  381. value = dataView.getBigUint64(position)
  382. position += 8
  383. return value
  384. // int handlers
  385. case 0xd0:
  386. return dataView.getInt8(position++)
  387. case 0xd1:
  388. value = dataView.getInt16(position)
  389. position += 2
  390. return value
  391. case 0xd2:
  392. value = dataView.getInt32(position)
  393. position += 4
  394. return value
  395. case 0xd3:
  396. if (currentUnpackr.int64AsType === 'number') {
  397. value = dataView.getInt32(position) * 0x100000000
  398. value += dataView.getUint32(position + 4)
  399. } else if (currentUnpackr.int64AsType === 'string') {
  400. value = dataView.getBigInt64(position).toString()
  401. } else if (currentUnpackr.int64AsType === 'auto') {
  402. value = dataView.getBigInt64(position)
  403. if (value>=BigInt(-2)<<BigInt(52)&&value<=BigInt(2)<<BigInt(52)) value=Number(value)
  404. } else
  405. value = dataView.getBigInt64(position)
  406. position += 8
  407. return value
  408. case 0xd4:
  409. // fixext 1
  410. value = src[position++]
  411. if (value == 0x72) {
  412. return recordDefinition(src[position++] & 0x3f)
  413. } else {
  414. let extension = currentExtensions[value]
  415. if (extension) {
  416. if (extension.read) {
  417. position++ // skip filler byte
  418. return extension.read(read())
  419. } else if (extension.noBuffer) {
  420. position++ // skip filler byte
  421. return extension()
  422. } else
  423. return extension(src.subarray(position, ++position))
  424. } else
  425. throw new Error('Unknown extension ' + value)
  426. }
  427. case 0xd5:
  428. // fixext 2
  429. value = src[position]
  430. if (value == 0x72) {
  431. position++
  432. return recordDefinition(src[position++] & 0x3f, src[position++])
  433. } else
  434. return readExt(2)
  435. case 0xd6:
  436. // fixext 4
  437. return readExt(4)
  438. case 0xd7:
  439. // fixext 8
  440. return readExt(8)
  441. case 0xd8:
  442. // fixext 16
  443. return readExt(16)
  444. case 0xd9:
  445. // str 8
  446. value = src[position++]
  447. if (srcStringEnd >= position) {
  448. return srcString.slice(position - srcStringStart, (position += value) - srcStringStart)
  449. }
  450. return readString8(value)
  451. case 0xda:
  452. // str 16
  453. value = dataView.getUint16(position)
  454. position += 2
  455. if (srcStringEnd >= position) {
  456. return srcString.slice(position - srcStringStart, (position += value) - srcStringStart)
  457. }
  458. return readString16(value)
  459. case 0xdb:
  460. // str 32
  461. value = dataView.getUint32(position)
  462. position += 4
  463. if (srcStringEnd >= position) {
  464. return srcString.slice(position - srcStringStart, (position += value) - srcStringStart)
  465. }
  466. return readString32(value)
  467. case 0xdc:
  468. // array 16
  469. value = dataView.getUint16(position)
  470. position += 2
  471. return readArray(value)
  472. case 0xdd:
  473. // array 32
  474. value = dataView.getUint32(position)
  475. position += 4
  476. return readArray(value)
  477. case 0xde:
  478. // map 16
  479. value = dataView.getUint16(position)
  480. position += 2
  481. return readMap(value)
  482. case 0xdf:
  483. // map 32
  484. value = dataView.getUint32(position)
  485. position += 4
  486. return readMap(value)
  487. default: // negative int
  488. if (token >= 0xe0)
  489. return token - 0x100
  490. if (token === undefined) {
  491. let error = new Error('Unexpected end of MessagePack data')
  492. error.incomplete = true
  493. throw error
  494. }
  495. throw new Error('Unknown MessagePack token ' + token)
  496. }
  497. }
  498. }
  499. const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/
  500. function createStructureReader(structure, firstId) {
  501. function readObject() {
  502. // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
  503. if (readObject.count++ > inlineObjectReadThreshold) {
  504. let readObject = structure.read = (new Function('r', 'return function(){return ' + (currentUnpackr.freezeData ? 'Object.freeze' : '') +
  505. '({' + structure.map(key => key === '__proto__' ? '__proto_:r()' : validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '})}'))(read)
  506. if (structure.highByte === 0)
  507. structure.read = createSecondByteReader(firstId, structure.read)
  508. return readObject() // second byte is already read, if there is one so immediately read object
  509. }
  510. let object = {}
  511. for (let i = 0, l = structure.length; i < l; i++) {
  512. let key = structure[i]
  513. if (key === '__proto__')
  514. key = '__proto_'
  515. object[key] = read()
  516. }
  517. if (currentUnpackr.freezeData)
  518. return Object.freeze(object);
  519. return object
  520. }
  521. readObject.count = 0
  522. if (structure.highByte === 0) {
  523. return createSecondByteReader(firstId, readObject)
  524. }
  525. return readObject
  526. }
  527. const createSecondByteReader = (firstId, read0) => {
  528. return function() {
  529. let highByte = src[position++]
  530. if (highByte === 0)
  531. return read0()
  532. let id = firstId < 32 ? -(firstId + (highByte << 5)) : firstId + (highByte << 5)
  533. let structure = currentStructures[id] || loadStructures()[id]
  534. if (!structure) {
  535. throw new Error('Record id is not defined for ' + id)
  536. }
  537. if (!structure.read)
  538. structure.read = createStructureReader(structure, firstId)
  539. return structure.read()
  540. }
  541. }
  542. export function loadStructures() {
  543. let loadedStructures = saveState(() => {
  544. // save the state in case getStructures modifies our buffer
  545. src = null
  546. return currentUnpackr.getStructures()
  547. })
  548. return currentStructures = currentUnpackr._mergeStructures(loadedStructures, currentStructures)
  549. }
  550. var readFixedString = readStringJS
  551. var readString8 = readStringJS
  552. var readString16 = readStringJS
  553. var readString32 = readStringJS
  554. export let isNativeAccelerationEnabled = false
  555. export function setExtractor(extractStrings) {
  556. isNativeAccelerationEnabled = true
  557. readFixedString = readString(1)
  558. readString8 = readString(2)
  559. readString16 = readString(3)
  560. readString32 = readString(5)
  561. function readString(headerLength) {
  562. return function readString(length) {
  563. let string = strings[stringPosition++]
  564. if (string == null) {
  565. if (bundledStrings)
  566. return readStringJS(length)
  567. let byteOffset = src.byteOffset
  568. let extraction = extractStrings(position - headerLength + byteOffset, srcEnd + byteOffset, src.buffer)
  569. if (typeof extraction == 'string') {
  570. string = extraction
  571. strings = EMPTY_ARRAY
  572. } else {
  573. strings = extraction
  574. stringPosition = 1
  575. srcStringEnd = 1 // even if a utf-8 string was decoded, must indicate we are in the midst of extracted strings and can't skip strings
  576. string = strings[0]
  577. if (string === undefined)
  578. throw new Error('Unexpected end of buffer')
  579. }
  580. }
  581. let srcStringLength = string.length
  582. if (srcStringLength <= length) {
  583. position += length
  584. return string
  585. }
  586. srcString = string
  587. srcStringStart = position
  588. srcStringEnd = position + srcStringLength
  589. position += length
  590. return string.slice(0, length) // we know we just want the beginning
  591. }
  592. }
  593. }
  594. function readStringJS(length) {
  595. let result
  596. if (length < 16) {
  597. if (result = shortStringInJS(length))
  598. return result
  599. }
  600. if (length > 64 && decoder)
  601. return decoder.decode(src.subarray(position, position += length))
  602. const end = position + length
  603. const units = []
  604. result = ''
  605. while (position < end) {
  606. const byte1 = src[position++]
  607. if ((byte1 & 0x80) === 0) {
  608. // 1 byte
  609. units.push(byte1)
  610. } else if ((byte1 & 0xe0) === 0xc0) {
  611. // 2 bytes
  612. const byte2 = src[position++] & 0x3f
  613. units.push(((byte1 & 0x1f) << 6) | byte2)
  614. } else if ((byte1 & 0xf0) === 0xe0) {
  615. // 3 bytes
  616. const byte2 = src[position++] & 0x3f
  617. const byte3 = src[position++] & 0x3f
  618. units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3)
  619. } else if ((byte1 & 0xf8) === 0xf0) {
  620. // 4 bytes
  621. const byte2 = src[position++] & 0x3f
  622. const byte3 = src[position++] & 0x3f
  623. const byte4 = src[position++] & 0x3f
  624. let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4
  625. if (unit > 0xffff) {
  626. unit -= 0x10000
  627. units.push(((unit >>> 10) & 0x3ff) | 0xd800)
  628. unit = 0xdc00 | (unit & 0x3ff)
  629. }
  630. units.push(unit)
  631. } else {
  632. units.push(byte1)
  633. }
  634. if (units.length >= 0x1000) {
  635. result += fromCharCode.apply(String, units)
  636. units.length = 0
  637. }
  638. }
  639. if (units.length > 0) {
  640. result += fromCharCode.apply(String, units)
  641. }
  642. return result
  643. }
  644. export function readString(source, start, length) {
  645. let existingSrc = src;
  646. src = source;
  647. position = start;
  648. try {
  649. return readStringJS(length);
  650. } finally {
  651. src = existingSrc;
  652. }
  653. }
  654. function readArray(length) {
  655. let array = new Array(length)
  656. for (let i = 0; i < length; i++) {
  657. array[i] = read()
  658. }
  659. if (currentUnpackr.freezeData)
  660. return Object.freeze(array)
  661. return array
  662. }
  663. function readMap(length) {
  664. if (currentUnpackr.mapsAsObjects) {
  665. let object = {}
  666. for (let i = 0; i < length; i++) {
  667. let key = readKey()
  668. if (key === '__proto__')
  669. key = '__proto_';
  670. object[key] = read()
  671. }
  672. return object
  673. } else {
  674. let map = new Map()
  675. for (let i = 0; i < length; i++) {
  676. map.set(read(), read())
  677. }
  678. return map
  679. }
  680. }
  681. var fromCharCode = String.fromCharCode
  682. function longStringInJS(length) {
  683. let start = position
  684. let bytes = new Array(length)
  685. for (let i = 0; i < length; i++) {
  686. const byte = src[position++];
  687. if ((byte & 0x80) > 0) {
  688. position = start
  689. return
  690. }
  691. bytes[i] = byte
  692. }
  693. return fromCharCode.apply(String, bytes)
  694. }
  695. function shortStringInJS(length) {
  696. if (length < 4) {
  697. if (length < 2) {
  698. if (length === 0)
  699. return ''
  700. else {
  701. let a = src[position++]
  702. if ((a & 0x80) > 1) {
  703. position -= 1
  704. return
  705. }
  706. return fromCharCode(a)
  707. }
  708. } else {
  709. let a = src[position++]
  710. let b = src[position++]
  711. if ((a & 0x80) > 0 || (b & 0x80) > 0) {
  712. position -= 2
  713. return
  714. }
  715. if (length < 3)
  716. return fromCharCode(a, b)
  717. let c = src[position++]
  718. if ((c & 0x80) > 0) {
  719. position -= 3
  720. return
  721. }
  722. return fromCharCode(a, b, c)
  723. }
  724. } else {
  725. let a = src[position++]
  726. let b = src[position++]
  727. let c = src[position++]
  728. let d = src[position++]
  729. if ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) {
  730. position -= 4
  731. return
  732. }
  733. if (length < 6) {
  734. if (length === 4)
  735. return fromCharCode(a, b, c, d)
  736. else {
  737. let e = src[position++]
  738. if ((e & 0x80) > 0) {
  739. position -= 5
  740. return
  741. }
  742. return fromCharCode(a, b, c, d, e)
  743. }
  744. } else if (length < 8) {
  745. let e = src[position++]
  746. let f = src[position++]
  747. if ((e & 0x80) > 0 || (f & 0x80) > 0) {
  748. position -= 6
  749. return
  750. }
  751. if (length < 7)
  752. return fromCharCode(a, b, c, d, e, f)
  753. let g = src[position++]
  754. if ((g & 0x80) > 0) {
  755. position -= 7
  756. return
  757. }
  758. return fromCharCode(a, b, c, d, e, f, g)
  759. } else {
  760. let e = src[position++]
  761. let f = src[position++]
  762. let g = src[position++]
  763. let h = src[position++]
  764. if ((e & 0x80) > 0 || (f & 0x80) > 0 || (g & 0x80) > 0 || (h & 0x80) > 0) {
  765. position -= 8
  766. return
  767. }
  768. if (length < 10) {
  769. if (length === 8)
  770. return fromCharCode(a, b, c, d, e, f, g, h)
  771. else {
  772. let i = src[position++]
  773. if ((i & 0x80) > 0) {
  774. position -= 9
  775. return
  776. }
  777. return fromCharCode(a, b, c, d, e, f, g, h, i)
  778. }
  779. } else if (length < 12) {
  780. let i = src[position++]
  781. let j = src[position++]
  782. if ((i & 0x80) > 0 || (j & 0x80) > 0) {
  783. position -= 10
  784. return
  785. }
  786. if (length < 11)
  787. return fromCharCode(a, b, c, d, e, f, g, h, i, j)
  788. let k = src[position++]
  789. if ((k & 0x80) > 0) {
  790. position -= 11
  791. return
  792. }
  793. return fromCharCode(a, b, c, d, e, f, g, h, i, j, k)
  794. } else {
  795. let i = src[position++]
  796. let j = src[position++]
  797. let k = src[position++]
  798. let l = src[position++]
  799. if ((i & 0x80) > 0 || (j & 0x80) > 0 || (k & 0x80) > 0 || (l & 0x80) > 0) {
  800. position -= 12
  801. return
  802. }
  803. if (length < 14) {
  804. if (length === 12)
  805. return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l)
  806. else {
  807. let m = src[position++]
  808. if ((m & 0x80) > 0) {
  809. position -= 13
  810. return
  811. }
  812. return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m)
  813. }
  814. } else {
  815. let m = src[position++]
  816. let n = src[position++]
  817. if ((m & 0x80) > 0 || (n & 0x80) > 0) {
  818. position -= 14
  819. return
  820. }
  821. if (length < 15)
  822. return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n)
  823. let o = src[position++]
  824. if ((o & 0x80) > 0) {
  825. position -= 15
  826. return
  827. }
  828. return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
  829. }
  830. }
  831. }
  832. }
  833. }
  834. function readOnlyJSString() {
  835. let token = src[position++]
  836. let length
  837. if (token < 0xc0) {
  838. // fixstr
  839. length = token - 0xa0
  840. } else {
  841. switch(token) {
  842. case 0xd9:
  843. // str 8
  844. length = src[position++]
  845. break
  846. case 0xda:
  847. // str 16
  848. length = dataView.getUint16(position)
  849. position += 2
  850. break
  851. case 0xdb:
  852. // str 32
  853. length = dataView.getUint32(position)
  854. position += 4
  855. break
  856. default:
  857. throw new Error('Expected string')
  858. }
  859. }
  860. return readStringJS(length)
  861. }
  862. function readBin(length) {
  863. return currentUnpackr.copyBuffers ?
  864. // specifically use the copying slice (not the node one)
  865. Uint8Array.prototype.slice.call(src, position, position += length) :
  866. src.subarray(position, position += length)
  867. }
  868. function readExt(length) {
  869. let type = src[position++]
  870. if (currentExtensions[type]) {
  871. let end
  872. return currentExtensions[type](src.subarray(position, end = (position += length)), (readPosition) => {
  873. position = readPosition;
  874. try {
  875. return read();
  876. } finally {
  877. position = end;
  878. }
  879. })
  880. }
  881. else
  882. throw new Error('Unknown extension type ' + type)
  883. }
  884. var keyCache = new Array(4096)
  885. function readKey() {
  886. let length = src[position++]
  887. if (length >= 0xa0 && length < 0xc0) {
  888. // fixstr, potentially use key cache
  889. length = length - 0xa0
  890. if (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)
  891. return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)
  892. else if (!(srcStringEnd == 0 && srcEnd < 180))
  893. return readFixedString(length)
  894. } else { // not cacheable, go back and do a standard read
  895. position--
  896. return asSafeString(read())
  897. }
  898. let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff
  899. let entry = keyCache[key]
  900. let checkPosition = position
  901. let end = position + length - 3
  902. let chunk
  903. let i = 0
  904. if (entry && entry.bytes == length) {
  905. while (checkPosition < end) {
  906. chunk = dataView.getUint32(checkPosition)
  907. if (chunk != entry[i++]) {
  908. checkPosition = 0x70000000
  909. break
  910. }
  911. checkPosition += 4
  912. }
  913. end += 3
  914. while (checkPosition < end) {
  915. chunk = src[checkPosition++]
  916. if (chunk != entry[i++]) {
  917. checkPosition = 0x70000000
  918. break
  919. }
  920. }
  921. if (checkPosition === end) {
  922. position = checkPosition
  923. return entry.string
  924. }
  925. end -= 3
  926. checkPosition = position
  927. }
  928. entry = []
  929. keyCache[key] = entry
  930. entry.bytes = length
  931. while (checkPosition < end) {
  932. chunk = dataView.getUint32(checkPosition)
  933. entry.push(chunk)
  934. checkPosition += 4
  935. }
  936. end += 3
  937. while (checkPosition < end) {
  938. chunk = src[checkPosition++]
  939. entry.push(chunk)
  940. }
  941. // for small blocks, avoiding the overhead of the extract call is helpful
  942. let string = length < 16 ? shortStringInJS(length) : longStringInJS(length)
  943. if (string != null)
  944. return entry.string = string
  945. return entry.string = readFixedString(length)
  946. }
  947. function asSafeString(property) {
  948. // protect against expensive (DoS) string conversions
  949. if (typeof property === 'string') return property;
  950. if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
  951. if (property == null) return property + '';
  952. throw new Error('Invalid property type for record', typeof property);
  953. }
  954. // the registration of the record definition extension (as "r")
  955. const recordDefinition = (id, highByte) => {
  956. let structure = read().map(asSafeString) // ensure that all keys are strings and
  957. // that the array is mutable
  958. let firstByte = id
  959. if (highByte !== undefined) {
  960. id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id)
  961. structure.highByte = highByte
  962. }
  963. let existingStructure = currentStructures[id]
  964. // If it is a shared structure, we need to restore any changes after reading.
  965. // Also in sequential mode, we may get incomplete reads and thus errors, and we need to restore
  966. // to the state prior to an incomplete read in order to properly resume.
  967. if (existingStructure && (existingStructure.isShared || sequentialMode)) {
  968. (currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure
  969. }
  970. currentStructures[id] = structure
  971. structure.read = createStructureReader(structure, firstByte)
  972. return structure.read()
  973. }
  974. currentExtensions[0] = () => {} // notepack defines extension 0 to mean undefined, so use that as the default here
  975. currentExtensions[0].noBuffer = true
  976. currentExtensions[0x42] = (data) => {
  977. // decode bigint
  978. let length = data.length;
  979. let value = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
  980. for (let i = 1; i < length; i++) {
  981. value <<= BigInt(8);
  982. value += BigInt(data[i]);
  983. }
  984. return value;
  985. }
  986. let errors = { Error, TypeError, ReferenceError };
  987. currentExtensions[0x65] = () => {
  988. let data = read()
  989. return (errors[data[0]] || Error)(data[1], { cause: data[2] })
  990. }
  991. currentExtensions[0x69] = (data) => {
  992. // id extension (for structured clones)
  993. if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
  994. let id = dataView.getUint32(position - 4)
  995. if (!referenceMap)
  996. referenceMap = new Map()
  997. let token = src[position]
  998. let target
  999. // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
  1000. // ahead past references to record structure definitions
  1001. if (token >= 0x90 && token < 0xa0 || token == 0xdc || token == 0xdd)
  1002. target = []
  1003. else
  1004. target = {}
  1005. let refEntry = { target } // a placeholder object
  1006. referenceMap.set(id, refEntry)
  1007. let targetProperties = read() // read the next value as the target object to id
  1008. if (refEntry.used) // there is a cycle, so we have to assign properties to original target
  1009. return Object.assign(target, targetProperties)
  1010. refEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one
  1011. return targetProperties // no cycle, can just use the returned read object
  1012. }
  1013. currentExtensions[0x70] = (data) => {
  1014. // pointer extension (for structured clones)
  1015. if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
  1016. let id = dataView.getUint32(position - 4)
  1017. let refEntry = referenceMap.get(id)
  1018. refEntry.used = true
  1019. return refEntry.target
  1020. }
  1021. currentExtensions[0x73] = () => new Set(read())
  1022. export const typedArrays = ['Int8','Uint8','Uint8Clamped','Int16','Uint16','Int32','Uint32','Float32','Float64','BigInt64','BigUint64'].map(type => type + 'Array')
  1023. let glbl = typeof globalThis === 'object' ? globalThis : window;
  1024. currentExtensions[0x74] = (data) => {
  1025. let typeCode = data[0]
  1026. let typedArrayName = typedArrays[typeCode]
  1027. if (!typedArrayName) {
  1028. if (typeCode === 16) {
  1029. let ab = new ArrayBuffer(data.length - 1)
  1030. let u8 = new Uint8Array(ab)
  1031. u8.set(data.subarray(1))
  1032. return ab;
  1033. }
  1034. throw new Error('Could not find typed array for code ' + typeCode)
  1035. }
  1036. // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
  1037. return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
  1038. }
  1039. currentExtensions[0x78] = () => {
  1040. let data = read()
  1041. return new RegExp(data[0], data[1])
  1042. }
  1043. const TEMP_BUNDLE = []
  1044. currentExtensions[0x62] = (data) => {
  1045. let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
  1046. let dataPosition = position
  1047. position += dataSize - data.length
  1048. bundledStrings = TEMP_BUNDLE
  1049. bundledStrings = [readOnlyJSString(), readOnlyJSString()]
  1050. bundledStrings.position0 = 0
  1051. bundledStrings.position1 = 0
  1052. bundledStrings.postBundlePosition = position
  1053. position = dataPosition
  1054. return read()
  1055. }
  1056. currentExtensions[0xff] = (data) => {
  1057. // 32-bit date extension
  1058. if (data.length == 4)
  1059. return new Date((data[0] * 0x1000000 + (data[1] << 16) + (data[2] << 8) + data[3]) * 1000)
  1060. else if (data.length == 8)
  1061. return new Date(
  1062. ((data[0] << 22) + (data[1] << 14) + (data[2] << 6) + (data[3] >> 2)) / 1000000 +
  1063. ((data[3] & 0x3) * 0x100000000 + data[4] * 0x1000000 + (data[5] << 16) + (data[6] << 8) + data[7]) * 1000)
  1064. else if (data.length == 12)// TODO: Implement support for negative
  1065. return new Date(
  1066. ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
  1067. (((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
  1068. else
  1069. return new Date('invalid')
  1070. } // notepack defines extension 0 to mean undefined, so use that as the default here
  1071. // registration of bulk record definition?
  1072. // currentExtensions[0x52] = () =>
  1073. function saveState(callback) {
  1074. if (onSaveState)
  1075. onSaveState();
  1076. let savedSrcEnd = srcEnd
  1077. let savedPosition = position
  1078. let savedStringPosition = stringPosition
  1079. let savedSrcStringStart = srcStringStart
  1080. let savedSrcStringEnd = srcStringEnd
  1081. let savedSrcString = srcString
  1082. let savedStrings = strings
  1083. let savedReferenceMap = referenceMap
  1084. let savedBundledStrings = bundledStrings
  1085. // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
  1086. let savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed
  1087. let savedStructures = currentStructures
  1088. let savedStructuresContents = currentStructures.slice(0, currentStructures.length)
  1089. let savedPackr = currentUnpackr
  1090. let savedSequentialMode = sequentialMode
  1091. let value = callback()
  1092. srcEnd = savedSrcEnd
  1093. position = savedPosition
  1094. stringPosition = savedStringPosition
  1095. srcStringStart = savedSrcStringStart
  1096. srcStringEnd = savedSrcStringEnd
  1097. srcString = savedSrcString
  1098. strings = savedStrings
  1099. referenceMap = savedReferenceMap
  1100. bundledStrings = savedBundledStrings
  1101. src = savedSrc
  1102. sequentialMode = savedSequentialMode
  1103. currentStructures = savedStructures
  1104. currentStructures.splice(0, currentStructures.length, ...savedStructuresContents)
  1105. currentUnpackr = savedPackr
  1106. dataView = new DataView(src.buffer, src.byteOffset, src.byteLength)
  1107. return value
  1108. }
  1109. export function clearSource() {
  1110. src = null
  1111. referenceMap = null
  1112. currentStructures = null
  1113. }
  1114. export function addExtension(extension) {
  1115. if (extension.unpack)
  1116. currentExtensions[extension.type] = extension.unpack
  1117. else
  1118. currentExtensions[extension.type] = extension
  1119. }
  1120. export const mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding
  1121. for (let i = 0; i < 256; i++) {
  1122. mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))
  1123. }
  1124. export const Decoder = Unpackr
  1125. var defaultUnpackr = new Unpackr({ useRecords: false })
  1126. export const unpack = defaultUnpackr.unpack
  1127. export const unpackMultiple = defaultUnpackr.unpackMultiple
  1128. export const decode = defaultUnpackr.unpack
  1129. export const FLOAT32_OPTIONS = {
  1130. NEVER: 0,
  1131. ALWAYS: 1,
  1132. DECIMAL_ROUND: 3,
  1133. DECIMAL_FIT: 4
  1134. }
  1135. let f32Array = new Float32Array(1)
  1136. let u8Array = new Uint8Array(f32Array.buffer, 0, 4)
  1137. export function roundFloat32(float32Number) {
  1138. f32Array[0] = float32Number
  1139. let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
  1140. return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
  1141. }
  1142. export function setReadStruct(updatedReadStruct, loadedStructs, saveState) {
  1143. readStruct = updatedReadStruct;
  1144. onLoadedStructures = loadedStructs;
  1145. onSaveState = saveState;
  1146. }