unpack.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  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. if (currentUnpackr.allowArraysInMapKeys && Array.isArray(property) && property.flat().every(item => ['string', 'number', 'boolean', 'bigint'].includes(typeof item))) {
  953. return property.flat().toString();
  954. }
  955. throw new Error(`Invalid property type for record: ${typeof property}`);
  956. }
  957. // the registration of the record definition extension (as "r")
  958. const recordDefinition = (id, highByte) => {
  959. let structure = read().map(asSafeString) // ensure that all keys are strings and
  960. // that the array is mutable
  961. let firstByte = id
  962. if (highByte !== undefined) {
  963. id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id)
  964. structure.highByte = highByte
  965. }
  966. let existingStructure = currentStructures[id]
  967. // If it is a shared structure, we need to restore any changes after reading.
  968. // Also in sequential mode, we may get incomplete reads and thus errors, and we need to restore
  969. // to the state prior to an incomplete read in order to properly resume.
  970. if (existingStructure && (existingStructure.isShared || sequentialMode)) {
  971. (currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure
  972. }
  973. currentStructures[id] = structure
  974. structure.read = createStructureReader(structure, firstByte)
  975. return structure.read()
  976. }
  977. currentExtensions[0] = () => {} // notepack defines extension 0 to mean undefined, so use that as the default here
  978. currentExtensions[0].noBuffer = true
  979. currentExtensions[0x42] = data => {
  980. let headLength = (data.byteLength % 8) || 8
  981. let head = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0])
  982. for (let i = 1; i < headLength; i++) {
  983. head <<= BigInt(8)
  984. head += BigInt(data[i])
  985. }
  986. if (data.byteLength !== headLength) {
  987. let view = new DataView(data.buffer, data.byteOffset, data.byteLength)
  988. let decode = (start, end) => {
  989. let length = end - start
  990. if (length <= 40) {
  991. let out = view.getBigUint64(start)
  992. for (let i = start + 8; i < end; i += 8) {
  993. out <<= BigInt(64n)
  994. out |= view.getBigUint64(i)
  995. }
  996. return out
  997. }
  998. // if (length === 8) return view.getBigUint64(start)
  999. let middle = start + (length >> 4 << 3)
  1000. let left = decode(start, middle)
  1001. let right = decode(middle, end)
  1002. return (left << BigInt((end - middle) * 8)) | right
  1003. }
  1004. head = (head << BigInt((view.byteLength - headLength) * 8)) | decode(headLength, view.byteLength)
  1005. }
  1006. return head
  1007. }
  1008. let errors = {
  1009. Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError: typeof AggregateError === 'function' ? AggregateError : null,
  1010. }
  1011. currentExtensions[0x65] = () => {
  1012. let data = read()
  1013. if (!errors[data[0]]) {
  1014. let error = Error(data[1], { cause: data[2] })
  1015. error.name = data[0]
  1016. return error
  1017. }
  1018. return errors[data[0]](data[1], { cause: data[2] })
  1019. }
  1020. currentExtensions[0x69] = (data) => {
  1021. // id extension (for structured clones)
  1022. if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
  1023. let id = dataView.getUint32(position - 4)
  1024. if (!referenceMap)
  1025. referenceMap = new Map()
  1026. let token = src[position]
  1027. let target
  1028. // TODO: handle any other types that can cycle and make the code more robust if there are other extensions
  1029. if (token >= 0x90 && token < 0xa0 || token == 0xdc || token == 0xdd)
  1030. target = []
  1031. else if (token >= 0x80 && token < 0x90 || token == 0xde || token == 0xdf)
  1032. target = new Map()
  1033. else if ((token >= 0xc7 && token <= 0xc9 || token >= 0xd4 && token <= 0xd8) && src[position + 1] === 0x73)
  1034. target = new Set()
  1035. else
  1036. target = {}
  1037. let refEntry = { target } // a placeholder object
  1038. referenceMap.set(id, refEntry)
  1039. let targetProperties = read() // read the next value as the target object to id
  1040. if (!refEntry.used) {
  1041. // no cycle, can just use the returned read object
  1042. return refEntry.target = targetProperties // replace the placeholder with the real one
  1043. } else {
  1044. // there is a cycle, so we have to assign properties to original target
  1045. Object.assign(target, targetProperties)
  1046. }
  1047. // copy over map/set entries if we're able to
  1048. if (target instanceof Map)
  1049. for (let [k, v] of targetProperties.entries()) target.set(k, v)
  1050. if (target instanceof Set)
  1051. for (let i of Array.from(targetProperties)) target.add(i)
  1052. return target
  1053. }
  1054. currentExtensions[0x70] = (data) => {
  1055. // pointer extension (for structured clones)
  1056. if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
  1057. let id = dataView.getUint32(position - 4)
  1058. let refEntry = referenceMap.get(id)
  1059. refEntry.used = true
  1060. return refEntry.target
  1061. }
  1062. currentExtensions[0x73] = () => new Set(read())
  1063. export const typedArrays = ['Int8','Uint8','Uint8Clamped','Int16','Uint16','Int32','Uint32','Float32','Float64','BigInt64','BigUint64'].map(type => type + 'Array')
  1064. let glbl = typeof globalThis === 'object' ? globalThis : window;
  1065. currentExtensions[0x74] = (data) => {
  1066. let typeCode = data[0]
  1067. // we always have to slice to get a new ArrayBuffer that is aligned
  1068. let buffer = Uint8Array.prototype.slice.call(data, 1).buffer
  1069. let typedArrayName = typedArrays[typeCode]
  1070. if (!typedArrayName) {
  1071. if (typeCode === 16) return buffer
  1072. if (typeCode === 17) return new DataView(buffer)
  1073. throw new Error('Could not find typed array for code ' + typeCode)
  1074. }
  1075. return new glbl[typedArrayName](buffer)
  1076. }
  1077. currentExtensions[0x78] = () => {
  1078. let data = read()
  1079. return new RegExp(data[0], data[1])
  1080. }
  1081. const TEMP_BUNDLE = []
  1082. currentExtensions[0x62] = (data) => {
  1083. let dataSize = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
  1084. let dataPosition = position
  1085. position += dataSize - data.length
  1086. bundledStrings = TEMP_BUNDLE
  1087. bundledStrings = [readOnlyJSString(), readOnlyJSString()]
  1088. bundledStrings.position0 = 0
  1089. bundledStrings.position1 = 0
  1090. bundledStrings.postBundlePosition = position
  1091. position = dataPosition
  1092. return read()
  1093. }
  1094. currentExtensions[0xff] = (data) => {
  1095. // 32-bit date extension
  1096. if (data.length == 4)
  1097. return new Date((data[0] * 0x1000000 + (data[1] << 16) + (data[2] << 8) + data[3]) * 1000)
  1098. else if (data.length == 8)
  1099. return new Date(
  1100. ((data[0] << 22) + (data[1] << 14) + (data[2] << 6) + (data[3] >> 2)) / 1000000 +
  1101. ((data[3] & 0x3) * 0x100000000 + data[4] * 0x1000000 + (data[5] << 16) + (data[6] << 8) + data[7]) * 1000)
  1102. else if (data.length == 12)
  1103. return new Date(
  1104. ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
  1105. (((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
  1106. else
  1107. return new Date('invalid')
  1108. }
  1109. // registration of bulk record definition?
  1110. // currentExtensions[0x52] = () =>
  1111. function saveState(callback) {
  1112. if (onSaveState)
  1113. onSaveState();
  1114. let savedSrcEnd = srcEnd
  1115. let savedPosition = position
  1116. let savedStringPosition = stringPosition
  1117. let savedSrcStringStart = srcStringStart
  1118. let savedSrcStringEnd = srcStringEnd
  1119. let savedSrcString = srcString
  1120. let savedStrings = strings
  1121. let savedReferenceMap = referenceMap
  1122. let savedBundledStrings = bundledStrings
  1123. // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
  1124. let savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed
  1125. let savedStructures = currentStructures
  1126. let savedStructuresContents = currentStructures.slice(0, currentStructures.length)
  1127. let savedPackr = currentUnpackr
  1128. let savedSequentialMode = sequentialMode
  1129. let value = callback()
  1130. srcEnd = savedSrcEnd
  1131. position = savedPosition
  1132. stringPosition = savedStringPosition
  1133. srcStringStart = savedSrcStringStart
  1134. srcStringEnd = savedSrcStringEnd
  1135. srcString = savedSrcString
  1136. strings = savedStrings
  1137. referenceMap = savedReferenceMap
  1138. bundledStrings = savedBundledStrings
  1139. src = savedSrc
  1140. sequentialMode = savedSequentialMode
  1141. currentStructures = savedStructures
  1142. currentStructures.splice(0, currentStructures.length, ...savedStructuresContents)
  1143. currentUnpackr = savedPackr
  1144. dataView = new DataView(src.buffer, src.byteOffset, src.byteLength)
  1145. return value
  1146. }
  1147. export function clearSource() {
  1148. src = null
  1149. referenceMap = null
  1150. currentStructures = null
  1151. }
  1152. export function addExtension(extension) {
  1153. if (extension.unpack)
  1154. currentExtensions[extension.type] = extension.unpack
  1155. else
  1156. currentExtensions[extension.type] = extension
  1157. }
  1158. export const mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding
  1159. for (let i = 0; i < 256; i++) {
  1160. mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))
  1161. }
  1162. export const Decoder = Unpackr
  1163. var defaultUnpackr = new Unpackr({ useRecords: false })
  1164. export const unpack = defaultUnpackr.unpack
  1165. export const unpackMultiple = defaultUnpackr.unpackMultiple
  1166. export const decode = defaultUnpackr.unpack
  1167. export const FLOAT32_OPTIONS = {
  1168. NEVER: 0,
  1169. ALWAYS: 1,
  1170. DECIMAL_ROUND: 3,
  1171. DECIMAL_FIT: 4
  1172. }
  1173. let f32Array = new Float32Array(1)
  1174. let u8Array = new Uint8Array(f32Array.buffer, 0, 4)
  1175. export function roundFloat32(float32Number) {
  1176. f32Array[0] = float32Number
  1177. let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
  1178. return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
  1179. }
  1180. export function setReadStruct(updatedReadStruct, loadedStructs, saveState) {
  1181. readStruct = updatedReadStruct;
  1182. onLoadedStructures = loadedStructs;
  1183. onSaveState = saveState;
  1184. }