polyfills.buffer.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* eslint-disable @typescript-eslint/no-unnecessary-condition */
  2. /* eslint-disable @typescript-eslint/init-declarations */
  3. /* eslint-disable prefer-spread */
  4. /* eslint-disable @typescript-eslint/no-invalid-this */
  5. /* eslint-disable @typescript-eslint/no-use-before-define */
  6. /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
  7. // Based on http://stackoverflow.com/a/22747272/680742, the browser with
  8. // the lowest limit is Chrome, with 0x10000 args.
  9. // We go 1 magnitude less, for safety
  10. const MAX_ARGUMENTS_LENGTH = 0x1000
  11. const base64 = require('base64-js')
  12. function blitBuffer (src, dst, offset, length) {
  13. let i
  14. for (i = 0; i < length; ++i) {
  15. if (i + offset >= dst.length || i >= src.length) {break}
  16. dst[i + offset] = src[i]
  17. }
  18. return i
  19. }
  20. export function utf8Write (string, offset, length) {
  21. return blitBuffer(utf8ToBytes(string, this.length - offset), this, offset, length)
  22. }
  23. export function base64Slice (start, end) {
  24. if (start === 0 && end === this.length) {
  25. return base64.fromByteArray(this)
  26. } else {
  27. return base64.fromByteArray(this.slice(start, end))
  28. }
  29. }
  30. function decodeCodePointsArray (codePoints) {
  31. const len = codePoints.length
  32. if (len <= MAX_ARGUMENTS_LENGTH) {
  33. return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
  34. }
  35. // Decode in chunks to avoid "call stack size exceeded".
  36. let res = ''
  37. let i = 0
  38. while (i < len) {
  39. res += String.fromCharCode.apply(
  40. String,
  41. codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
  42. )
  43. }
  44. return res
  45. }
  46. export function latin1Slice (start, end) {
  47. let ret = ''
  48. end = Math.min(this.length, end)
  49. for (let i = start; i < end; ++i) {
  50. ret += String.fromCharCode(this[i])
  51. }
  52. return ret
  53. }
  54. export function utf8Slice (this, start, end) {
  55. end = Math.min(this.length, end)
  56. const res: number[] = []
  57. let i = start
  58. while (i < end) {
  59. const firstByte = this[i]
  60. let codePoint: number|null = null
  61. let bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1
  62. if (i + bytesPerSequence <= end) {
  63. let secondByte, thirdByte, fourthByte, tempCodePoint
  64. switch (bytesPerSequence) {
  65. case 1:
  66. if (firstByte < 0x80) {
  67. codePoint = firstByte
  68. }
  69. break
  70. case 2:
  71. secondByte = this[i + 1]
  72. if ((secondByte & 0xC0) === 0x80) {
  73. tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F
  74. if (tempCodePoint > 0x7F) {
  75. codePoint = tempCodePoint
  76. }
  77. }
  78. break
  79. case 3:
  80. secondByte = this[i + 1]
  81. thirdByte = this[i + 2]
  82. if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
  83. tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F
  84. if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
  85. codePoint = tempCodePoint
  86. }
  87. }
  88. break
  89. case 4:
  90. secondByte = this[i + 1]
  91. thirdByte = this[i + 2]
  92. fourthByte = this[i + 3]
  93. if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
  94. tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F
  95. if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
  96. codePoint = tempCodePoint
  97. }
  98. }
  99. }
  100. }
  101. if (codePoint === null) {
  102. // we did not generate a valid codePoint so insert a
  103. // replacement char (U+FFFD) and advance only 1 byte
  104. codePoint = 0xFFFD
  105. bytesPerSequence = 1
  106. } else if (codePoint > 0xFFFF) {
  107. // encode to utf16 (surrogate pair dance)
  108. codePoint -= 0x10000
  109. res.push(codePoint >>> 10 & 0x3FF | 0xD800)
  110. codePoint = 0xDC00 | codePoint & 0x3FF
  111. }
  112. res.push(codePoint)
  113. i += bytesPerSequence
  114. }
  115. return decodeCodePointsArray(res)
  116. }
  117. function utf8ToBytes (string, units) {
  118. units = units || Infinity
  119. let codePoint
  120. const length = string.length
  121. let leadSurrogate = null
  122. const bytes: number[] = []
  123. for (let i = 0; i < length; ++i) {
  124. codePoint = string.charCodeAt(i)
  125. // is surrogate component
  126. if (codePoint > 0xD7FF && codePoint < 0xE000) {
  127. // last char was a lead
  128. if (!leadSurrogate) {
  129. // no lead yet
  130. if (codePoint > 0xDBFF) {
  131. // unexpected trail
  132. if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)}
  133. continue
  134. } else if (i + 1 === length) {
  135. // unpaired lead
  136. if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)}
  137. continue
  138. }
  139. // valid lead
  140. leadSurrogate = codePoint
  141. continue
  142. }
  143. // 2 leads in a row
  144. if (codePoint < 0xDC00) {
  145. if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)}
  146. leadSurrogate = codePoint
  147. continue
  148. }
  149. // valid surrogate pair
  150. codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
  151. } else if (leadSurrogate) {
  152. // valid bmp char, but last char was a lead
  153. if ((units -= 3) > -1) {bytes.push(0xEF, 0xBF, 0xBD)}
  154. }
  155. leadSurrogate = null
  156. // encode utf8
  157. if (codePoint < 0x80) {
  158. if ((units -= 1) < 0) {break}
  159. bytes.push(codePoint)
  160. } else if (codePoint < 0x800) {
  161. if ((units -= 2) < 0) {break}
  162. bytes.push(
  163. codePoint >> 0x6 | 0xC0,
  164. codePoint & 0x3F | 0x80
  165. )
  166. } else if (codePoint < 0x10000) {
  167. if ((units -= 3) < 0) {break}
  168. bytes.push(
  169. codePoint >> 0xC | 0xE0,
  170. codePoint >> 0x6 & 0x3F | 0x80,
  171. codePoint & 0x3F | 0x80
  172. )
  173. } else if (codePoint < 0x110000) {
  174. if ((units -= 4) < 0) {break}
  175. bytes.push(
  176. codePoint >> 0x12 | 0xF0,
  177. codePoint >> 0xC & 0x3F | 0x80,
  178. codePoint >> 0x6 & 0x3F | 0x80,
  179. codePoint & 0x3F | 0x80
  180. )
  181. } else {
  182. throw new Error('Invalid code point')
  183. }
  184. }
  185. return bytes
  186. }
  187. // Create lookup table for `toString('hex')`
  188. // See: https://github.com/feross/buffer/issues/219
  189. const hexSliceLookupTable = (function () {
  190. const alphabet = '0123456789abcdef'
  191. const table = new Array(256)
  192. for (let i = 0; i < 16; ++i) {
  193. const i16 = i * 16
  194. for (let j = 0; j < 16; ++j) {
  195. table[i16 + j] = alphabet[i] + alphabet[j]
  196. }
  197. }
  198. return table
  199. })()
  200. export function hexSlice (start, end) {
  201. const len = this.length
  202. if (!start || start < 0) {start = 0}
  203. if (!end || end < 0 || end > len) {end = len}
  204. let out = ''
  205. for (let i = start; i < end; ++i) {
  206. out += hexSliceLookupTable[this[i]]
  207. }
  208. return out
  209. }
  210. import { Buffer } from 'buffer'
  211. Buffer.prototype['latin1Slice'] = latin1Slice
  212. Buffer.prototype['utf8Slice'] = utf8Slice
  213. Buffer.prototype['base64Slice'] = base64Slice
  214. Buffer.prototype['utf8Write'] = utf8Write
  215. Buffer.prototype['hexSlice'] = hexSlice
  216. window['Buffer'] = Buffer