From 96f565b380a8552e91151b9879746a1992283a35 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 3 Apr 2018 15:50:49 +0200 Subject: Fix T54477: Broken utf8 strings in old .blend files Back in the days (2.4x and before), it was rather easy to get some invalid utf-8 strings in Blender. This is totally breaking modern code, so this commit adds a simple 'check & fix strings' operator, available from the main File menu. --- release/scripts/startup/bl_operators/file.py | 54 ++++++++++++++++++++++++++++ release/scripts/startup/bl_ui/space_info.py | 1 + 2 files changed, 55 insertions(+) (limited to 'release') diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py index 1b51906a032..4ab8d59f263 100644 --- a/release/scripts/startup/bl_operators/file.py +++ b/release/scripts/startup/bl_operators/file.py @@ -249,7 +249,61 @@ class WM_OT_previews_batch_clear(Operator): return {'FINISHED'} +class WM_OT_blend_strings_utf8_validate(Operator): + """Check and fix all strings in current .blend file to be valid UTF-8 Unicode (needed for some old, 2.4x area files)""" + bl_idname = "wm.blend_strings_utf8_validate" + bl_label = "Validate .blend strings" + bl_options = {'REGISTER'} + + def validate_strings(self, item, done_items): + if item is None: + return False + + if item in done_items: + return False + done_items.add(item) + + if getattr(item, 'library', None) is not None: + return False # No point in checking library data, we cannot fix it anyway... + + changed = False + for prop in item.bl_rna.properties: + if prop.identifier in {'bl_rna', 'rna_type'}: + continue # Or we'd recurse 'till Hell freezes. + if prop.is_readonly: + continue + if prop.type == 'STRING': + val_bytes = item.path_resolve(prop.identifier, False).as_bytes() + val_utf8 = val_bytes.decode('utf-8', 'replace') + val_bytes_valid = val_utf8.encode('utf-8') + if val_bytes_valid != val_bytes: + print("found bad utf8 encoded string %r, fixing to %r (%r)..." + "" % (val_bytes, val_bytes_valid, val_utf8)) + setattr(item, prop.identifier, val_utf8) + changed = True + elif prop.type == 'POINTER': + it = getattr(item, prop.identifier) + changed |= self.validate_strings(it, done_items) + elif prop.type == 'COLLECTION': + for it in getattr(item, prop.identifier): + changed |= self.validate_strings(it, done_items) + return changed + + def execute(self, context): + changed = False + done_items = set() + for prop in bpy.data.bl_rna.properties: + if prop.type == 'COLLECTION': + for it in getattr(bpy.data, prop.identifier): + changed |= self.validate_strings(it, done_items) + if changed: + self.report({'WARNING'}, + "Some strings were fixed, don't forget to save the .blend file to keep those changes") + return {'FINISHED'} + + classes = ( WM_OT_previews_batch_clear, WM_OT_previews_batch_generate, + WM_OT_blend_strings_utf8_validate, ) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index a7b518dfd2e..180e48af386 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -154,6 +154,7 @@ class INFO_MT_file(Menu): layout.separator() layout.menu("INFO_MT_file_external_data", icon='EXTERNAL_DATA') + layout.operator("wm.blend_strings_utf8_validate", icon='FILE_BLEND') layout.separator() -- cgit v1.2.3