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.
This commit is contained in:
parent
601835cd31
commit
96f565b380
Notes:
blender-bot
2023-02-14 06:04:16 +01:00
Referenced by issue #54477, .blend file can't be exported
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue