///|
// A linear resource preflight, not an XML validator. The mature reader still
// validates all syntax. Bound its quadratic duplicate-attribute lookup before
// it starts; never inspect markup-looking text inside comments, CDATA or PIs.
fn check_xml_attribute_budget(text : String) -> Unit raise InputError {
  let mut mode = 0
  let mut attributes = 0
  let mut i = 0
  while i < text.length() {
    let ch = text[i].to_int()
    let next = if i + 1 < text.length() { text[i + 1].to_int() } else { -1 }
    let third = if i + 2 < text.length() { text[i + 2].to_int() } else { -1 }
    match mode {
      0 =>
        if ch == 60 {
          if next == 63 {
            mode = 6
            i = i + 1
          } else if next == 33 {
            if third == 45 && i + 3 < text.length() && text[i + 3] == 45 {
              mode = 4
              i = i + 3
            } else if i + 9 <= text.length() && text[i:i + 9] == "
        match ch {
          62 => mode = 0
          39 => mode = 2
          34 => mode = 3
          61 => {
            attributes = attributes + 1
            if attributes > 1024 {
              raise Rejected(
                "limit_exceeded", "XML element exceeds 1024 attributes",
              )
            }
          }
          _ => ()
        }
      2 => if ch == 39 { mode = 1 }
      3 => if ch == 34 { mode = 1 }
      4 =>
        if ch == 45 && next == 45 && third == 62 {
          mode = 0
          i = i + 2
        }
      5 =>
        if ch == 93 && next == 93 && third == 62 {
          mode = 0
          i = i + 2
        }
      _ =>
        if ch == 63 && next == 62 {
          mode = 0
          i = i + 1
        }
    }
    i = i + 1
  }
}