///|
pub fn decode_rfc2231_value(value : String) -> String {
  let parts = split_char(value, '\'')
  if parts.length() >= 3 {
    percent_decode(parts[2])
  } else {
    percent_decode(remove_quotes(value))
  }
}

///|
pub fn percent_decode(input : String) -> String {
  let chars : Array[Char] = []
  for ch in input {
    chars.push(ch)
  }
  let mut out = ""
  let mut i = 0
  while i < chars.length() {
    if chars[i] == '%' && i + 2 < chars.length() {
      let hi = hex_value(chars[i + 1])
      let lo = hex_value(chars[i + 2])
      if hi >= 0 && lo >= 0 {
        out = out + Int::unsafe_to_char(hi * 16 + lo).to_string()
        i = i + 3
      } else {
        out = out + chars[i].to_string()
        i = i + 1
      }
    } else {
      out = out + chars[i].to_string()
      i = i + 1
    }
  }
  out
}

///|
pub fn filename_star_from_headers(headers : Array[Header]) -> String {
  let disp = header_value(headers, "Content-Disposition")
  for part in split_char(disp, ';') {
    match split_once(part, '=') {
      Some((key, value)) =>
        if lower_ascii(trim_ascii(key)) == "filename*" {
          return decode_rfc2231_value(value)
        }
      None => ()
    }
  }
  ""
}