value-text.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. const {
  2. normalizeTextValue
  3. } = require('../../utils/base-utils.js')
  4. const {
  5. bytesToAutoText,
  6. trimTrailingNullBytes
  7. } = require('../../utils/binary-utils.js')
  8. const {
  9. MAX_TEXT_BYTE_LENGTH
  10. } = require('./constants.js')
  11. const {
  12. getDataType
  13. } = require('./value-types.js')
  14. function encodeAsciiBytes(text, byteLimit = 32) {
  15. const bytes = []
  16. const stringValue = normalizeTextValue(text)
  17. for (let index = 0; index < stringValue.length; index += 1) {
  18. const code = stringValue.charCodeAt(index)
  19. if (code > 0x7F) {
  20. throw new Error('ASCII 文本只能包含 0x00 - 0x7F 字符')
  21. }
  22. bytes.push(code)
  23. if (bytes.length > byteLimit) break
  24. }
  25. if (bytes.length > byteLimit) {
  26. throw new Error(`长文本最长 ${byteLimit} 字节`)
  27. }
  28. return bytes
  29. }
  30. function encodeUtf8Bytes(text, byteLimit = 32) {
  31. const bytes = []
  32. const encoded = encodeURIComponent(normalizeTextValue(text))
  33. for (let index = 0; index < encoded.length; index += 1) {
  34. const char = encoded[index]
  35. if (char === '%') {
  36. const byte = parseInt(encoded.slice(index + 1, index + 3), 16)
  37. if (!Number.isFinite(byte)) break
  38. bytes.push(byte & 0xFF)
  39. index += 2
  40. } else {
  41. bytes.push(char.charCodeAt(0) & 0xFF)
  42. }
  43. if (bytes.length > byteLimit) break
  44. }
  45. if (bytes.length > byteLimit) {
  46. throw new Error(`长文本最长 ${byteLimit} 字节`)
  47. }
  48. return bytes
  49. }
  50. function decodeAsciiBytes(bytes = []) {
  51. return String.fromCharCode.apply(null, trimTrailingNullBytes(bytes).map((byte) => byte & 0xFF))
  52. }
  53. function decodeUtf8Bytes(bytes = []) {
  54. const trimmed = trimTrailingNullBytes(bytes)
  55. if (!trimmed.length) return ''
  56. let encoded = ''
  57. trimmed.forEach((byte) => {
  58. encoded += `%${(byte & 0xFF).toString(16).padStart(2, '0').toUpperCase()}`
  59. })
  60. try {
  61. return decodeURIComponent(encoded)
  62. } catch (error) {
  63. return decodeAsciiBytes(trimmed)
  64. }
  65. }
  66. function encodeTextBytes(text, dataType, byteLimit = MAX_TEXT_BYTE_LENGTH) {
  67. const normalizedType = getDataType(dataType).key
  68. if (normalizedType === 'ascii') return encodeAsciiBytes(text, byteLimit)
  69. return encodeUtf8Bytes(text, byteLimit)
  70. }
  71. function decodeTextBytes(bytes, dataType) {
  72. const normalizedType = getDataType(dataType).key
  73. if (normalizedType === 'text') return bytesToAutoText(bytes)
  74. return normalizedType === 'ascii'
  75. ? decodeAsciiBytes(bytes)
  76. : decodeUtf8Bytes(bytes)
  77. }
  78. module.exports = {
  79. decodeAsciiBytes,
  80. decodeTextBytes,
  81. decodeUtf8Bytes,
  82. encodeAsciiBytes,
  83. encodeTextBytes,
  84. encodeUtf8Bytes
  85. }