From 04c0573ee77cc955cf585a0d7a61163375eb57cd Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 7 Aug 2020 16:38:40 +0200 Subject: Fix T78278: Cannot import some binary PLY file generated by Rhinos3D 6.0 Issue was that in binary file reading, python only recognize `'\n'` character as line separator... PLY seems to allow (or at least, use) other OS-related variants of lines terminators, so we have to implement our own line iterator for those cases... --- io_mesh_ply/__init__.py | 4 ++-- io_mesh_ply/import_ply.py | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/io_mesh_ply/__init__.py b/io_mesh_ply/__init__.py index 1a69c346..a3f08ebd 100644 --- a/io_mesh_ply/__init__.py +++ b/io_mesh_ply/__init__.py @@ -20,8 +20,8 @@ bl_info = { "name": "Stanford PLY format", - "author": "Bruce Merry, Campbell Barton", - "version": (2, 0, 0), + "author": "Bruce Merry, Campbell Barton", "Bastien Montagne" + "version": (2, 1, 0), "blender": (2, 90, 0), "location": "File > Import/Export", "description": "Import-Export PLY mesh data with UVs and vertex colors", diff --git a/io_mesh_ply/import_ply.py b/io_mesh_ply/import_ply.py index c118aa3c..d9d12d67 100644 --- a/io_mesh_ply/import_ply.py +++ b/io_mesh_ply/import_ply.py @@ -152,14 +152,45 @@ def read(filepath): invalid_ply = (None, None, None) with open(filepath, 'rb') as plyf: - signature = plyf.readline() + signature = plyf.peek(5) - if not signature.startswith(b'ply'): + if not signature.startswith(b'ply') or not len(signature) >= 5: print("Signature line was invalid") return invalid_ply + custom_line_sep = None + if signature[3] != ord(b'\n'): + if signature[3] != ord(b'\r'): + print("Unknown line separator") + return invalid_ply + if signature[4] == ord(b'\n'): + custom_line_sep = b"\r\n" + else: + custom_line_sep = b"\r" + + # Work around binary file reading only accepting "\n" as line separator. + plyf_header_line_iterator = lambda plyf: plyf + if custom_line_sep is not None: + def _plyf_header_line_iterator(plyf): + buff = plyf.peek(2**16) + while len(buff) != 0: + read_bytes = 0 + buff = buff.split(custom_line_sep) + for line in buff[:-1]: + read_bytes += len(line) + len(custom_line_sep) + if line.startswith(b'end_header'): + # Since reader code might (will) break iteration at this point, + # we have to ensure file is read up to here, yield, amd return... + plyf.read(read_bytes) + yield line + return + yield line + plyf.read(read_bytes) + buff = buff[-1] + plyf.peek(2**16) + plyf_header_line_iterator = _plyf_header_line_iterator + valid_header = False - for line in plyf: + for line in plyf_header_line_iterator(plyf): tokens = re.split(br'[ \r\n]+', line) if len(tokens) == 0: -- cgit v1.2.3