wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
'use strict'
 
/**
 * Converts an attribute value into an escaped string as described in
 * https://www.rfc-editor.org/rfc/rfc4514#section-2.4.
 *
 * This function supports up to 4 byte unicode characters.
 *
 * @param {string} value
 * @returns {string} The escaped string.
 */
module.exports = function escapeValue (value) {
  if (typeof value !== 'string') {
    throw Error('value must be a string')
  }
 
  const toEscape = Buffer.from(value, 'utf8')
  const escaped = []
 
  // We will handle the reverse solidus ('\') on its own.
  const embeddedReservedChars = [
    0x22, // '"'
    0x2b, // '+'
    0x2c, // ','
    0x3b, // ';'
    0x3c, // '<'
    0x3e // '>'
  ]
  for (let i = 0; i < toEscape.byteLength;) {
    const charHex = toEscape[i]
 
    // Handle leading space or #.
    if (i === 0 && (charHex === 0x20 || charHex === 0x23)) {
      escaped.push(toEscapedHexString(charHex))
      i += 1
      continue
    }
    // Handle trailing space.
    if (i === toEscape.byteLength - 1 && charHex === 0x20) {
      escaped.push(toEscapedHexString(charHex))
      i += 1
      continue
    }
 
    if (embeddedReservedChars.includes(charHex) === true) {
      escaped.push(toEscapedHexString(charHex))
      i += 1
      continue
    }
 
    if (charHex >= 0xc0 && charHex <= 0xdf) {
      // Represents the first byte in a 2-byte UTF-8 character.
      escaped.push(toEscapedHexString(charHex))
      escaped.push(toEscapedHexString(toEscape[i + 1]))
      i += 2
      continue
    }
 
    if (charHex >= 0xe0 && charHex <= 0xef) {
      // Represents the first byte in a 3-byte UTF-8 character.
      escaped.push(toEscapedHexString(charHex))
      escaped.push(toEscapedHexString(toEscape[i + 1]))
      escaped.push(toEscapedHexString(toEscape[i + 2]))
      i += 3
      continue
    }
 
    if (charHex >= 0xf0 && charHex <= 0xf7) {
      // Represents the first byte in a 4-byte UTF-8 character.
      escaped.push(toEscapedHexString(charHex))
      escaped.push(toEscapedHexString(toEscape[i + 1]))
      escaped.push(toEscapedHexString(toEscape[i + 2]))
      escaped.push(toEscapedHexString(toEscape[i + 3]))
      i += 4
      continue
    }
 
    if (charHex <= 31) {
      // Represents an ASCII control character.
      escaped.push(toEscapedHexString(charHex))
      i += 1
      continue
    }
 
    escaped.push(String.fromCharCode(charHex))
    i += 1
    continue
  }
 
  return escaped.join('')
}
 
/**
 * Given a byte, convert it to an escaped hex string.
 *
 * @example
 * toEscapedHexString(0x20) // '\20'
 *
 * @param {number} char
 * @returns {string}
 */
function toEscapedHexString (char) {
  return '\\' + char.toString(16).padStart(2, '0')
}