///|
// Scan once, retaining only referenced names. A large unused table must not
// allocate a map entry and byte buffer for every name it happens to contain.
fn gnu_names(
data : Bytes,
start : Int,
size : Int,
wanted : Map[Int, Unit],
) -> Map[Int, Bytes] raise InvalidArchive {
let names : Map[Int, Bytes] = Map([])
let mut cursor = start
let end = start + size
while cursor < end {
// GNU ar may include one final newline in the table's declared size.
if cursor == end - 1 && data[cursor] == b'\n' {
break
}
let mut stop = cursor
while stop + 1 < end && !(data[stop] == b'/' && data[stop + 1] == b'\n') {
stop += 1
}
if stop + 1 >= end {
reject("AR006", cursor, "unterminated GNU long name")
}
if stop == cursor {
reject("AR006", cursor, "empty GNU long name")
}
for i = cursor; i < stop; i = i + 1 {
if data[i] == b'\x00' {
reject("AR006", i, "NUL inside GNU long name")
}
}
if wanted.get(cursor - start) is Some(_) {
names[cursor - start] = data[cursor:stop].to_owned()
}
cursor = stop + 2
}
names
}
///|
fn member_kind(name : Bytes) -> MemberKind {
if name == b"//" {
NameTable
} else if name == b"/" ||
name == b"/SYM64/" ||
name == b"__.SYMDEF" ||
name == b"__.SYMDEF SORTED" ||
name == b"__.SYMDEF_64" ||
name == b"__.SYMDEF_64 SORTED" {
SymbolTable
} else {
Regular
}
}
///|
fn embedded_name_size(
data : Bytes,
start : Int,
width : Int,
) -> Int raise InvalidArchive {
if width == 0 {
reject("AR006", start, "missing BSD name length")
}
for i = start; i < start + width; i = i + 1 {
if data[i] < b'0' || data[i] > b'9' {
reject("AR006", i, "invalid BSD name length")
}
}
number_field(data, start, width, 10, false, 2147483647L).unwrap().to_int()
}
///|
fn bsd_name(
data : Bytes,
start : Int,
width : Int,
) -> Bytes raise InvalidArchive {
let mut end = start + width
while end > start && data[end - 1] == b'\x00' {
end -= 1
}
if end == start {
reject("AR006", start, "empty BSD name")
}
for i = start; i < end; i = i + 1 {
if data[i] == b'\x00' {
reject("AR006", i, "NUL inside BSD name")
}
}
data[start:end].to_owned()
}