///|
fn index_mappings(table : SymbolIndex) -> Map[Bytes, Array[Int32]] {
  let result : Map[Bytes, Array[Int32]] = Map([])
  for symbol in table.symbols {
    match result.get(symbol.name) {
      Some(targets) => targets.push(symbol.member_index)
      None => result[symbol.name] = [symbol.member_index]
    }
  }
  result
}

///|
fn coff_symbol_index(
  archive : Archive,
  headers : Map[Int32, Int32],
  max_symbols : Int32,
  max_names : Int32,
) -> SymbolIndex raise InvalidArchive {
  let entry = archive.records[1]
  let data = archive.data
  let start = entry.data_offset
  let end = start + entry.size
  let members = symbol_number(
    data,
    start,
    4,
    true,
    end,
    archive.records.length(),
  )
  if members > (entry.size - 8) / 4 {
    reject("AR009", start, "COFF member offsets exceed the linker record")
  }
  let targets : Array[Int32] = []
  let mut previous = -1
  for n = 0; n < members; n = n + 1 {
    let field = start + 4 + n * 4
    let offset = symbol_number(data, field, 4, true, end, data.length())
    if offset <= previous {
      reject("AR009", field, "COFF member offsets must be strictly increasing")
    }
    targets.push(symbol_target(archive, headers, offset, field))
    previous = offset
  }
  let count_field = start + 4 + members * 4
  let count = symbol_number(
    data,
    count_field,
    4,
    true,
    end,
    (end - count_field - 4) / 2,
  )
  if count > max_symbols {
    reject("AR008", count_field, "symbol count limit exceeded")
  }
  let mut cursor = count_field + 4 + count * 2
  let mut name_bytes = 0
  let symbols : Array[Symbol] = []
  for n = 0; n < count; n = n + 1 {
    let field = count_field + 4 + n * 2
    let ordinal = symbol_number(data, field, 2, true, end, members)
    if ordinal == 0 {
      reject("AR009", field, "COFF member ordinals are one-based")
    }
    let name_offset = cursor
    while cursor < end && data[cursor] != b'\x00' {
      cursor += 1
    }
    if cursor == end || cursor == name_offset {
      reject("AR009", name_offset, "missing or unterminated COFF symbol name")
    }
    let length = cursor - name_offset
    if length > max_names - name_bytes {
      reject("AR008", name_offset, "expanded symbol-name byte limit exceeded")
    }
    name_bytes += length
    let name = data[name_offset:cursor].to_owned()
    if !symbols.is_empty() &&
      symbols[symbols.length() - 1].name.lexical_compare(name) > 0 {
      reject("AR009", name_offset, "COFF symbol names must be sorted")
    }
    symbols.push({
      name,
      member_index: targets[ordinal - 1],
      name_offset,
      offset_field_offset: field,
    })
    cursor += 1
  }
  symbol_padding(data, cursor, end, 1)
  { record_index: 1, format: "coff", symbols, }
}