"""Logic for reading .a files.
Copied from //tools/binary_size/libsupersize/ar.py"""
import os
def _ResolveThinObjectPath(archive_path, subpath):
"""Given the .a path and .o subpath, returns the .o path."""
if subpath.startswith('obj/'):
return subpath
parent_path = os.path.dirname(archive_path)
return os.path.normpath(os.path.join(parent_path, subpath))
def _IterThinPaths(path):
"""Given the .a path, yields all nested .o paths."""
with open(path, 'rb') as f:
header = f.read(8)
is_thin = header == b'!<thin>\n'
if not is_thin and header != b'!<arch>\n':
raise Exception('Invalid .a: ' + path)
if not is_thin:
return
def read_payload(size):
ret = f.read(size)
if size & 1 != 0:
f.read(1)
return ret
while True:
entry = f.read(60)
if not entry:
return
entry_name = entry[:16].rstrip()
entry_size = int(entry[48:58].rstrip())
if entry_name in (b'', b'/', b'//', b'/SYM64/'):
payload = read_payload(entry_size)
if entry_name == b'//':
name_list = payload
continue
if entry_name[0:1] == b'/':
name_offset = int(entry_name[1:])
end_idx = name_list.index(b'\n', name_offset)
entry_name = name_list[name_offset:end_idx]
else:
entry_name = entry_name.rstrip()
yield entry_name.rstrip(b'/').decode('ascii')
def ExpandThinArchives(paths):
"""Expands all thin archives found in |paths| into .o paths.
Args:
paths: List of paths relative to |output_directory|.
output_directory: Output directory.
Returns:
* A new list of paths with all archives replaced by .o paths.
"""
expanded_paths = []
for path in paths:
if not path.endswith('.a'):
expanded_paths.append(path)
continue
with open(path, 'rb') as f:
header = f.read(8)
is_thin = header == b'!<thin>\n'
if is_thin:
for subpath in _IterThinPaths(path):
expanded_paths.append(_ResolveThinObjectPath(path, subpath))
elif header != b'!<arch>\n':
raise Exception('Invalid .a: ' + path)
return expanded_paths