| 221 | // Used to act as a friendly class to stringifying stuff |
| 222 | // not meant to be exposed to users, could inject invalid values |
| 223 | #parse() { |
| 224 | if (this.#processed) return; // already parsed |
| 225 | const paramsMap = this.#data; |
| 226 | let position = 0; |
| 227 | const str = this.#string; |
| 228 | const endOfSource = SafeStringPrototypeSearch( |
| 229 | StringPrototypeSlice(str, position), |
| 230 | START_ENDING_WHITESPACE, |
| 231 | ) + position; |
| 232 | while (position < endOfSource) { |
| 233 | // Skip any whitespace before parameter |
| 234 | position += SafeStringPrototypeSearch( |
| 235 | StringPrototypeSlice(str, position), |
| 236 | END_BEGINNING_WHITESPACE, |
| 237 | ); |
| 238 | // Read until ';' or '=' |
| 239 | const afterParameterName = SafeStringPrototypeSearch( |
| 240 | StringPrototypeSlice(str, position), |
| 241 | EQUALS_SEMICOLON_OR_END, |
| 242 | ) + position; |
| 243 | const parameterString = toASCIILower( |
| 244 | StringPrototypeSlice(str, position, afterParameterName), |
| 245 | ); |
| 246 | position = afterParameterName; |
| 247 | // If we found a terminating character |
| 248 | if (position < endOfSource) { |
| 249 | // Safe to use because we never do special actions for surrogate pairs |
| 250 | const char = StringPrototypeCharAt(str, position); |
| 251 | // Skip the terminating character |
| 252 | position += 1; |
| 253 | // Ignore parameters without values |
| 254 | if (char === ';') { |
| 255 | continue; |
| 256 | } |
| 257 | } |
| 258 | // If we are at end of the string, it cannot have a value |
| 259 | if (position >= endOfSource) break; |
| 260 | // Safe to use because we never do special actions for surrogate pairs |
| 261 | const char = StringPrototypeCharAt(str, position); |
| 262 | let parameterValue = null; |
| 263 | if (char === '"') { |
| 264 | // Handle quoted-string form of values |
| 265 | // skip '"' |
| 266 | position += 1; |
| 267 | // Find matching closing '"' or end of string |
| 268 | // use $1 to see if we terminated on unmatched '\' |
| 269 | // use $2 to see if we terminated on a matching '"' |
| 270 | // so we can skip the last char in either case |
| 271 | const insideMatch = RegExpPrototypeExec( |
| 272 | QUOTED_VALUE_PATTERN, |
| 273 | StringPrototypeSlice(str, position)); |
| 274 | position += insideMatch[0].length; |
| 275 | // Skip including last character if an unmatched '\' or '"' during |
| 276 | // unescape |
| 277 | const inside = insideMatch[1] || insideMatch[2] ? |
| 278 | StringPrototypeSlice(insideMatch[0], 0, -1) : |
| 279 | insideMatch[0]; |
| 280 | // Unescape '\' quoted characters |