///|
/// Parse the content octets of an INTEGER value into a signed `Int`, rejecting
/// integers wider than `max_bytes`.
pub fn parse_integer(content : Bytes, max_bytes : Int) -> Result[Int, BerError] {
  result_of_ber(fn() raise BerError {
    let n = content.length()
    if n == 0 {
      raise Truncated
    }
    if n > max_bytes || n * 8 >= 64 {
      raise IntegerTooLarge
    }
    let mut value = 0
    for i in 0.. Result[Bool, BerError] {
  result_of_ber(fn() raise BerError {
    if content.length() == 0 {
      raise Truncated
    }
    let mut any = false
    for b in content {
      if b != 0 {
        any = true
      }
    }
    any
  })
}

///|
/// Decode a BER INTEGER value, checking the tag is INTEGER and the width
/// respects `limits`.
pub fn decode_integer(
  value : BerValue,
  limits : BerLimits,
) -> Result[Int, BerError] {
  if value.tag.class != Universal || value.tag.number != tag_integer {
    return Err(InvalidTag)
  }
  parse_integer(value.content, limits.max_integer_bytes)
}

///|
/// Decode a BER BOOLEAN value.
pub fn decode_boolean(value : BerValue) -> Result[Bool, BerError] {
  if value.tag.class != Universal || value.tag.number != tag_boolean {
    return Err(InvalidTag)
  }
  parse_boolean(value.content)
}

///|
/// Parse the content octets of an OID into its dotted-decimal form (X.690 8.19).
pub fn parse_oid(content : Bytes) -> Result[String, BerError] {
  result_of_ber(fn() raise BerError {
    let n = content.length()
    if n == 0 {
      raise InvalidOid
    }
    let arcs : Array[Int] = []
    let mut current = 0
    let mut complete = true
    for b in content {
      let v = b.to_int()
      current = current * 128 + (v & 0x7F)
      if (v & 0x80) == 0 {
        arcs.push(current)
        current = 0
        complete = true
      } else {
        complete = false
      }
    }
    if !complete {
      raise InvalidOid
    }
    if arcs.is_empty() {
      raise InvalidOid
    }
    let first_combined = arcs[0]
    let first = if first_combined < 40 {
      0
    } else if first_combined < 80 {
      1
    } else {
      2
    }
    let second = first_combined - first * 40
    let sb = StringBuilder()
    sb.write_string("\{first}.\{second}")
    for i in 1.. Result[String, BerError] {
  if value.tag.class != Universal || value.tag.number != tag_oid {
    return Err(InvalidTag)
  }
  parse_oid(value.content)
}