///|
priv struct PatchRanges {
  control_start : Int32
  control_end : Int32
  diff_end : Int32
  extra_end : Int32
  new_size : Int64
}

///|
fn parse_header(
  data : Bytes,
  limits : Limits,
) -> Result[PatchRanges, BsdiffError] {
  match limits.validate() {
    Err(e) => return Err(e)
    Ok(_) => ()
  }
  let total = data.length().to_int64()
  if total > limits.max_patch_bytes {
    return Err(
      format_error(
        ResourceLimitExceeded,
        Header,
        None,
        None,
        Some("max_patch_bytes"),
        Some(total),
        Some(limits.max_patch_bytes),
      ),
    )
  }
  if data.length() < 32 {
    return Err(
      format_error(
        TruncatedData,
        Header,
        None,
        Some(total),
        None,
        None,
        Some(32L),
      ),
    )
  }
  let magic = b"BSDIFF40"
  for i in 0..<8 {
    if data[i] != magic[i] {
      return Err(
        format_error(
          UnsupportedFormat,
          Header,
          None,
          Some(i.to_int64()),
          Some("magic"),
          None,
          None,
        ),
      )
    }
  }
  let control = match decode_int(data, 8, Header) {
    Ok(x) => x
    Err(e) => return Err(e)
  }
  let diff = match decode_int(data, 16, Header) {
    Ok(x) => x
    Err(e) => return Err(e)
  }
  let output = match decode_int(data, 24, Header) {
    Ok(x) => x
    Err(e) => return Err(e)
  }
  for
    (name, value, offset) in [
      ("control_length", control, 8L),
      ("diff_length", diff, 16L),
      ("new_size", output, 24L),
    ] {
    if value < 0L {
      return Err(
        format_error(
          InvalidField,
          Header,
          None,
          Some(offset),
          Some(name),
          Some(value),
          None,
        ),
      )
    }
  }
  let max = 9223372036854775807L
  if control > max - 32L {
    return Err(
      format_error(
        IntegerOverflow,
        Header,
        Some("control"),
        Some(8L),
        Some("control_length"),
        Some(control),
        None,
      ),
    )
  }
  let control_end = 32L + control
  if diff > max - control_end {
    return Err(
      format_error(
        IntegerOverflow,
        Header,
        Some("diff"),
        Some(16L),
        Some("diff_length"),
        Some(diff),
        None,
      ),
    )
  }
  let diff_end = control_end + diff
  if control_end > total {
    return Err(
      format_error(
        TruncatedData,
        Header,
        Some("control"),
        Some(8L),
        Some("control_length"),
        Some(control),
        Some(total),
      ),
    )
  }
  if diff_end > total {
    return Err(
      format_error(
        TruncatedData,
        Header,
        Some("diff"),
        Some(16L),
        Some("diff_length"),
        Some(diff),
        Some(total),
      ),
    )
  }
  if output > limits.max_output_bytes {
    return Err(
      format_error(
        ResourceLimitExceeded,
        Header,
        None,
        Some(24L),
        Some("max_output_bytes"),
        Some(output),
        Some(limits.max_output_bytes),
      ),
    )
  }
  Ok({
    control_start: 32,
    control_end: control_end.to_int(),
    diff_end: diff_end.to_int(),
    extra_end: data.length(),
    new_size: output,
  })
}