pw_tokenizer: Handle .a files with an extra \n
Some .a files have an additional '\n' character after the first entry.
To handle this, ignore the first character of the file header if it is
\n.
Change-Id: I28ce63a79e0757018fdaa960491166038faa9ad0
diff --git a/pw_tokenizer/py/elf_reader_test.py b/pw_tokenizer/py/elf_reader_test.py
index e576598..a65587f 100755
--- a/pw_tokenizer/py/elf_reader_test.py
+++ b/pw_tokenizer/py/elf_reader_test.py
@@ -214,6 +214,23 @@
io.BytesIO(b'!<arch>blah blahblah')):
pass
+ def test_extra_newline_after_entry_is_ignored(self):
+ archive = io.BytesIO(elf_reader.ARCHIVE_MAGIC +
+ _archive_file(self._elf_data) + b'\n' +
+ _archive_file(self._elf_data))
+
+ for size in elf_reader.files_in_archive(archive):
+ self.assertEqual(self._elf_data, archive.read(size))
+
+ def test_two_extra_newlines_parsing_fails(self):
+ archive = io.BytesIO(elf_reader.ARCHIVE_MAGIC +
+ _archive_file(self._elf_data) + b'\n\n' +
+ _archive_file(self._elf_data))
+
+ with self.assertRaises(elf_reader.FileDecodeError):
+ for size in elf_reader.files_in_archive(archive):
+ self.assertEqual(self._elf_data, archive.read(size))
+
def test_iterate_over_archive_with_invalid_size(self):
data = elf_reader.ARCHIVE_MAGIC + _archive_file(b'$' * 3210)
file = io.BytesIO(data)
diff --git a/pw_tokenizer/py/pw_tokenizer/elf_reader.py b/pw_tokenizer/py/pw_tokenizer/elf_reader.py
index 079e808..76f51e3 100755
--- a/pw_tokenizer/py/pw_tokenizer/elf_reader.py
+++ b/pw_tokenizer/py/pw_tokenizer/elf_reader.py
@@ -38,7 +38,8 @@
actual = fd.read(len(expected))
if expected != actual:
raise FileDecodeError(
- f'Invalid {what}: expected {expected!r}, found {actual!r}')
+ f'Invalid {what}: expected {expected!r}, found {actual!r} in file '
+ f'{getattr(fd, "name", "(unknown")}')
def files_in_archive(fd: BinaryIO) -> Iterable[int]:
@@ -47,6 +48,11 @@
_check_next_bytes(fd, ARCHIVE_MAGIC, 'archive magic number')
while True:
+ # In some archives, the first file ends with an additional \n. If that
+ # is present, skip it.
+ if fd.read(1) != b'\n':
+ fd.seek(-1, 1)
+
# Each file in an archive is prefixed with an ASCII header:
#
# 16 B - file identifier (text)