| ... | ... | @@ -249,6 +249,24 @@ fn Validity_Criteria( |
| 249 | 249 | var zwnj_state: enum { start, dual_joining, transparent1, zwnj, transparent2, right_joining } = .start; |
| 250 | 250 | var check_zwnj_state: ?bool = null; |
| 251 | 251 | |
| 252 | // 9. If CheckBidi, and if the domain name is a Bidi domain name, then the label must satisfy all six of the numbered conditions in RFC 5893 Section 2. |
| 253 | // 9.1. The first character must be a character with Bidi property L, R, or AL. If it has the R or AL property, it is an RTL label; if it has the L property, it is an LTR label. |
| 254 | // 9.2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. |
| 255 | // 9.3. In an RTL label, the end of the label must be a character with Bidi property R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM. |
| 256 | // 9.4. In an RTL label, if an EN is present, no AN may be present, and vice versa. |
| 257 | // 9.5. In an LTR label, only characters with the Bidi properties L, EN, ES, CS, ET, ON, BN, or NSM are allowed. |
| 258 | // 9.6. In an LTR label, the end of the label must be a character with Bidi property L or EN, followed by zero or more characters with Bidi property NSM. |
| 259 | var seen_en = false; |
| 260 | var seen_an = false; |
| 261 | var last_bidi_class: ucd.BidiClass = .NSM; |
| 262 | if (CheckBidi) { |
| 263 | switch (first_p[4]) { |
| 264 | .L => {}, |
| 265 | .R, .AL => {}, |
| 266 | else => return error.IDNAFailure, |
| 267 | } |
| 268 | } |
| 269 | |
| 252 | 270 | while (it.nextCodepointSlice()) |sl| { |
| 253 | 271 | const cp = std.unicode.utf8Decode(sl) catch unreachable; |
| 254 | 272 | const status, _, _ = mappingRow(cp); |
| ... | ... | @@ -293,10 +311,10 @@ fn Validity_Criteria( |
| 293 | 311 | |
| 294 | 312 | // 3. In addition, if UseSTD3ASCIIRules=true and the code point is an ASCII code point (U+0000..U+007F), then it must be a lowercase letter (a-z), a digit (0-9), or a hyphen-minus (U+002D). |
| 295 | 313 | // (Note: This excludes uppercase ASCII A-Z which are mapped in UTS #46 and disallowed in IDNA2008.) |
| 296 | | if (UseSTD3ASCIIRules and std.ascii.isAscii(sl[0])) { |
| 297 | | if (std.ascii.isLower(sl[0])) continue; |
| 298 | | if (std.ascii.isDigit(sl[0])) continue; |
| 299 | | if (sl[0] == '-') continue; |
| 314 | if (UseSTD3ASCIIRules and std.ascii.isAscii(sl[0])) blk: { |
| 315 | if (std.ascii.isLower(sl[0])) break :blk; |
| 316 | if (std.ascii.isDigit(sl[0])) break :blk; |
| 317 | if (sl[0] == '-') break :blk; |
| 300 | 318 | return error.IDNAFailure; |
| 301 | 319 | } |
| 302 | 320 | |
| ... | ... | @@ -380,61 +398,49 @@ fn Validity_Criteria( |
| 380 | 398 | } |
| 381 | 399 | point_2before = point_before; |
| 382 | 400 | point_before = p; |
| 401 | |
| 402 | if (CheckBidi) { |
| 403 | switch (first_p[4]) { |
| 404 | .L => { |
| 405 | switch (p[4]) { |
| 406 | .L, .EN, .ES, .CS, .ET, .ON, .BN => |cl| last_bidi_class = cl, |
| 407 | .NSM => {}, |
| 408 | else => return error.IDNAFailure, |
| 409 | } |
| 410 | }, |
| 411 | .R, .AL => { |
| 412 | switch (p[4]) { |
| 413 | .R, .AL, .AN, .EN, .ES, .CS, .ET, .ON, .BN => |cl| last_bidi_class = cl, |
| 414 | .NSM => {}, |
| 415 | else => return error.IDNAFailure, |
| 416 | } |
| 417 | if (p[4] == .EN and seen_an) return error.IDNAFailure; |
| 418 | if (p[4] == .EN) seen_en = true; |
| 419 | if (p[4] == .AN and seen_en) return error.IDNAFailure; |
| 420 | if (p[4] == .AN) seen_an = true; |
| 421 | }, |
| 422 | else => unreachable, |
| 423 | } |
| 424 | } |
| 383 | 425 | } |
| 384 | 426 | if (CheckJoiners) { |
| 385 | 427 | if (check_zwnj_state == true and zwnj_state != .right_joining) return error.IDNAFailure; |
| 386 | 428 | } |
| 387 | | |
| 388 | | // 9. If CheckBidi, and if the domain name is a Bidi domain name, then the label must satisfy all six of the numbered conditions in RFC 5893 Section 2. |
| 389 | 429 | if (CheckBidi) { |
| 390 | | // 1. The first character must be a character with Bidi property L, R, or AL. If it has the R or AL property, it is an RTL label; if it has the L property, it is an LTR label. |
| 391 | | // 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. |
| 392 | | // 3. In an RTL label, the end of the label must be a character with Bidi property R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM. |
| 393 | | // 4. In an RTL label, if an EN is present, no AN may be present, and vice versa. |
| 394 | | // 5. In an LTR label, only characters with the Bidi properties L, EN, ES, CS, ET, ON, BN, or NSM are allowed. |
| 395 | | // 6. In an LTR label, the end of the label must be a character with Bidi property L or EN, followed by zero or more characters with Bidi property NSM. |
| 396 | 430 | switch (first_p[4]) { |
| 397 | 431 | .L => { |
| 398 | | it.i = 0; |
| 399 | | var last_bidi_class: ucd.BidiClass = .NSM; |
| 400 | | while (it.nextCodepointSlice()) |sl| { |
| 401 | | const cp = std.unicode.utf8Decode(sl) catch unreachable; |
| 402 | | const point = ucd.unicode_data.find(cp); |
| 403 | | switch (point[4]) { |
| 404 | | .L, .EN, .ES, .CS, .ET, .ON, .BN => |cl| last_bidi_class = cl, |
| 405 | | .NSM => {}, |
| 406 | | else => return error.IDNAFailure, |
| 407 | | } |
| 408 | | } |
| 409 | 432 | switch (last_bidi_class) { |
| 410 | 433 | .L, .EN => {}, |
| 411 | 434 | else => return error.IDNAFailure, |
| 412 | 435 | } |
| 413 | 436 | }, |
| 414 | 437 | .R, .AL => { |
| 415 | | it.i = 0; |
| 416 | | var seen_en = false; |
| 417 | | var seen_an = false; |
| 418 | | var last_bidi_class: ucd.BidiClass = .NSM; |
| 419 | | while (it.nextCodepointSlice()) |sl| { |
| 420 | | const cp = std.unicode.utf8Decode(sl) catch unreachable; |
| 421 | | const point = ucd.unicode_data.find(cp); |
| 422 | | switch (point[4]) { |
| 423 | | .R, .AL, .AN, .EN, .ES, .CS, .ET, .ON, .BN => |cl| last_bidi_class = cl, |
| 424 | | .NSM => {}, |
| 425 | | else => return error.IDNAFailure, |
| 426 | | } |
| 427 | | if (point[4] == .EN and seen_an) return error.IDNAFailure; |
| 428 | | if (point[4] == .EN) seen_en = true; |
| 429 | | if (point[4] == .AN and seen_en) return error.IDNAFailure; |
| 430 | | if (point[4] == .AN) seen_an = true; |
| 431 | | } |
| 432 | 438 | switch (last_bidi_class) { |
| 433 | 439 | .R, .AL, .EN, .AN => {}, |
| 434 | 440 | else => return error.IDNAFailure, |
| 435 | 441 | } |
| 436 | 442 | }, |
| 437 | | else => return error.IDNAFailure, |
| 443 | else => unreachable, |
| 438 | 444 | } |
| 439 | 445 | } |
| 440 | 446 | } |