Use tuples for multi-part lookups
Also use real ints instead of extracting from strings.
This commit is contained in:
@@ -416,18 +416,25 @@ class BlendFileBlock:
|
|||||||
use_nil=True, use_str=True,
|
use_nil=True, use_str=True,
|
||||||
base_index=0,
|
base_index=0,
|
||||||
):
|
):
|
||||||
path_full = path_root + b"." + path if path_root else path
|
if path_root:
|
||||||
|
path_full = (
|
||||||
|
(path_root if type(path_root) is tuple else (path_root, )) +
|
||||||
|
(path if type(path) is tuple else (path, )))
|
||||||
|
else:
|
||||||
|
path_full = path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield (path_full, self.get(path_full, default, sdna_index_refine, use_nil, use_str, base_index))
|
yield (path_full, self.get(path_full, default, sdna_index_refine, use_nil, use_str, base_index))
|
||||||
except NotImplementedError as err:
|
except NotImplementedError as ex:
|
||||||
msg, dna_name, dna_type = err.args
|
msg, dna_name, dna_type = ex.args
|
||||||
struct_index = self.file.sdna_index_from_id.get(dna_type.dna_type_id, None)
|
struct_index = self.file.sdna_index_from_id.get(dna_type.dna_type_id, None)
|
||||||
if struct_index is None:
|
if struct_index is None:
|
||||||
yield (path_full, "<%s>" % dna_type.dna_type_id.decode('ascii'))
|
yield (path_full, "<%s>" % dna_type.dna_type_id.decode('ascii'))
|
||||||
else:
|
else:
|
||||||
struct = self.file.structs[struct_index]
|
struct = self.file.structs[struct_index]
|
||||||
for f in struct.fields:
|
for f in struct.fields:
|
||||||
yield from self.get_recursive_iter(f.dna_name.name_only, path_full, default, None, use_nil, use_str, 0)
|
yield from self.get_recursive_iter(
|
||||||
|
f.dna_name.name_only, path_full, default, None, use_nil, use_str, 0)
|
||||||
|
|
||||||
def items_recursive_iter(self):
|
def items_recursive_iter(self):
|
||||||
for k in self.keys():
|
for k in self.keys():
|
||||||
@@ -442,7 +449,8 @@ class BlendFileBlock:
|
|||||||
# algo either. But for now does the job!
|
# algo either. But for now does the job!
|
||||||
import zlib
|
import zlib
|
||||||
def _is_pointer(self, k):
|
def _is_pointer(self, k):
|
||||||
return self.file.structs[self.sdna_index].field_from_path(self.file.header, self.file.handle, k).dna_name.is_pointer
|
return self.file.structs[self.sdna_index].field_from_path(
|
||||||
|
self.file.header, self.file.handle, k).dna_name.is_pointer
|
||||||
|
|
||||||
hsh = 1
|
hsh = 1
|
||||||
for k, v in self.items_recursive_iter():
|
for k, v in self.items_recursive_iter():
|
||||||
@@ -485,7 +493,6 @@ class BlendFileBlock:
|
|||||||
|
|
||||||
assert(self.file.structs[sdna_index_refine].field_from_path(
|
assert(self.file.structs[sdna_index_refine].field_from_path(
|
||||||
self.file.header, self.file.handle, path).dna_name.is_pointer)
|
self.file.header, self.file.handle, path).dna_name.is_pointer)
|
||||||
|
|
||||||
if result != 0:
|
if result != 0:
|
||||||
# possible (but unlikely)
|
# possible (but unlikely)
|
||||||
# that this fails and returns None
|
# that this fails and returns None
|
||||||
@@ -688,19 +695,28 @@ class DNAStruct:
|
|||||||
self.user_data = None
|
self.user_data = None
|
||||||
|
|
||||||
def field_from_path(self, header, handle, path):
|
def field_from_path(self, header, handle, path):
|
||||||
assert(type(path) == bytes)
|
"""
|
||||||
# support 'id.name'
|
Support lookups as bytes or a tuple of bytes and optional index.
|
||||||
name, _, name_tail = path.partition(b'.')
|
|
||||||
|
|
||||||
# support 'mtex[1].tex'
|
C style 'id.name' --> (b'id', b'name')
|
||||||
# note, multi-dimensional arrays not supported
|
C style 'array[4]' --> ('array', 4)
|
||||||
# FIXME: 'mtex[1]' works, but not 'mtex[1].tex', why is this???
|
"""
|
||||||
if name.endswith(b']'):
|
if type(path) is tuple:
|
||||||
name, _, index = name[:-1].partition(b'[')
|
name = path[0]
|
||||||
index = int(index)
|
if len(path) >= 2 and type(path[1]) is not bytes:
|
||||||
|
name_tail = path[2:]
|
||||||
|
index = path[1]
|
||||||
|
assert(type(index) is int)
|
||||||
|
else:
|
||||||
|
name_tail = path[1:]
|
||||||
|
index = 0
|
||||||
else:
|
else:
|
||||||
|
name = path
|
||||||
|
name_tail = None
|
||||||
index = 0
|
index = 0
|
||||||
|
|
||||||
|
assert(type(name) is bytes)
|
||||||
|
|
||||||
field = self.field_from_name.get(name)
|
field = self.field_from_name.get(name)
|
||||||
|
|
||||||
if field is not None:
|
if field is not None:
|
||||||
@@ -712,7 +728,7 @@ class DNAStruct:
|
|||||||
index_offset = field.dna_type.size * index
|
index_offset = field.dna_type.size * index
|
||||||
assert(index_offset < field.dna_size)
|
assert(index_offset < field.dna_size)
|
||||||
handle.seek(index_offset, os.SEEK_CUR)
|
handle.seek(index_offset, os.SEEK_CUR)
|
||||||
if name_tail == b'':
|
if not name_tail: # None or ()
|
||||||
return field
|
return field
|
||||||
else:
|
else:
|
||||||
return field.dna_type.field_from_path(header, handle, name_tail)
|
return field.dna_type.field_from_path(header, handle, name_tail)
|
||||||
@@ -721,14 +737,13 @@ class DNAStruct:
|
|||||||
default=...,
|
default=...,
|
||||||
use_nil=True, use_str=True,
|
use_nil=True, use_str=True,
|
||||||
):
|
):
|
||||||
assert(type(path) == bytes)
|
|
||||||
|
|
||||||
field = self.field_from_path(header, handle, path)
|
field = self.field_from_path(header, handle, path)
|
||||||
if field is None:
|
if field is None:
|
||||||
if default is not ...:
|
if default is not ...:
|
||||||
return default
|
return default
|
||||||
else:
|
else:
|
||||||
raise KeyError("%r not found in %r (%r)" % (path, [f.dna_name.name_only for f in self.fields], self.dna_type_id))
|
raise KeyError("%r not found in %r (%r)" %
|
||||||
|
(path, [f.dna_name.name_only for f in self.fields], self.dna_type_id))
|
||||||
|
|
||||||
dna_type = field.dna_type
|
dna_type = field.dna_type
|
||||||
dna_name = field.dna_name
|
dna_name = field.dna_name
|
||||||
@@ -764,7 +779,7 @@ class DNAStruct:
|
|||||||
return DNA_IO.read_bytes(handle, dna_name.array_size)
|
return DNA_IO.read_bytes(handle, dna_name.array_size)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("%r exists but isn't pointer, can't resolve field %r" %
|
raise NotImplementedError("%r exists but isn't pointer, can't resolve field %r" %
|
||||||
(path, dna_name.name_only))
|
(path, dna_name.name_only), dna_name, dna_type)
|
||||||
|
|
||||||
def field_set(self, header, handle, path, value):
|
def field_set(self, header, handle, path, value):
|
||||||
assert(type(path) == bytes)
|
assert(type(path) == bytes)
|
||||||
|
@@ -307,7 +307,7 @@ class FilePath:
|
|||||||
expand_codes_idlib.setdefault(block[b'lib'], set()).add(block[b'name'])
|
expand_codes_idlib.setdefault(block[b'lib'], set()).add(block[b'name'])
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
id_name = block[b'id.name']
|
id_name = block[b'id', b'name']
|
||||||
|
|
||||||
# if we touched this already, don't touch again
|
# if we touched this already, don't touch again
|
||||||
# (else we may modify the same path multiple times)
|
# (else we may modify the same path multiple times)
|
||||||
@@ -374,7 +374,7 @@ class FilePath:
|
|||||||
else:
|
else:
|
||||||
def iter_blocks_id(code):
|
def iter_blocks_id(code):
|
||||||
for block in blend.find_blocks_from_code(code):
|
for block in blend.find_blocks_from_code(code):
|
||||||
if block[b'id.name'] in block_codes:
|
if block[b'id', b'name'] in block_codes:
|
||||||
yield from block_expand(block, code)
|
yield from block_expand(block, code)
|
||||||
|
|
||||||
if block_codes_idlib is not None:
|
if block_codes_idlib is not None:
|
||||||
@@ -517,8 +517,10 @@ class FilePath:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _from_block_OB(block, basedir, extra_info, level):
|
def _from_block_OB(block, basedir, extra_info, level):
|
||||||
# 'ob->modifiers[...].filepath'
|
# 'ob->modifiers[...].filepath'
|
||||||
for block_mod in bf_utils.iter_ListBase(block.get_pointer(b'modifiers.first'), next_item=b'modifier.next'):
|
for block_mod in bf_utils.iter_ListBase(
|
||||||
item_md_type = block_mod[b'modifier.type']
|
block.get_pointer((b'modifiers', b'first')),
|
||||||
|
next_item=(b'modifier', b'next')):
|
||||||
|
item_md_type = block_mod[b'modifier', b'type']
|
||||||
if item_md_type == C_defs.eModifierType_MeshCache:
|
if item_md_type == C_defs.eModifierType_MeshCache:
|
||||||
yield FPElem_block_path(basedir, level, (block_mod, b'filepath')), extra_info
|
yield FPElem_block_path(basedir, level, (block_mod, b'filepath')), extra_info
|
||||||
|
|
||||||
@@ -558,9 +560,9 @@ class FilePath:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _from_block_ME(block, basedir, extra_info, level):
|
def _from_block_ME(block, basedir, extra_info, level):
|
||||||
block_external = block.get_pointer(b'ldata.external', None)
|
block_external = block.get_pointer((b'ldata', b'external'), None)
|
||||||
if block_external is None:
|
if block_external is None:
|
||||||
block_external = block.get_pointer(b'fdata.external', None)
|
block_external = block.get_pointer((b'fdata', b'external'), None)
|
||||||
|
|
||||||
if block_external is not None:
|
if block_external is not None:
|
||||||
yield FPElem_block_path(basedir, level, (block_external, b'filename')), extra_info
|
yield FPElem_block_path(basedir, level, (block_external, b'filename')), extra_info
|
||||||
@@ -585,7 +587,7 @@ class FilePath:
|
|||||||
pass
|
pass
|
||||||
elif item_type == C_defs.SEQ_TYPE_META:
|
elif item_type == C_defs.SEQ_TYPE_META:
|
||||||
yield from seqbase(bf_utils.iter_ListBase(
|
yield from seqbase(bf_utils.iter_ListBase(
|
||||||
item.get_pointer(b'seqbase.first', sdna_index_refine=sdna_index_Sequence)))
|
item.get_pointer((b'seqbase', b'first'), sdna_index_refine=sdna_index_Sequence)))
|
||||||
else:
|
else:
|
||||||
item_strip = item.get_pointer(b'strip', sdna_index_refine=sdna_index_Sequence)
|
item_strip = item.get_pointer(b'strip', sdna_index_refine=sdna_index_Sequence)
|
||||||
if item_strip is None: # unlikely!
|
if item_strip is None: # unlikely!
|
||||||
@@ -599,7 +601,7 @@ class FilePath:
|
|||||||
yield FPElem_sequence_single(
|
yield FPElem_sequence_single(
|
||||||
basedir, level, (item_strip, b'dir', item_stripdata, b'name')), extra_info
|
basedir, level, (item_strip, b'dir', item_stripdata, b'name')), extra_info
|
||||||
|
|
||||||
yield from seqbase(bf_utils.iter_ListBase(block_ed.get_pointer(b'seqbase.first')))
|
yield from seqbase(bf_utils.iter_ListBase(block_ed.get_pointer((b'seqbase', b'first'))))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _from_block_LI(block, basedir, extra_info, level):
|
def _from_block_LI(block, basedir, extra_info, level):
|
||||||
@@ -668,8 +670,7 @@ class ExpandID:
|
|||||||
array_len = field.dna_size // block.file.header.pointer_size
|
array_len = field.dna_size // block.file.header.pointer_size
|
||||||
|
|
||||||
for i in range(array_len):
|
for i in range(array_len):
|
||||||
path = ('mtex[%d]' % i).encode('ascii')
|
item = block.get_pointer((b'mtex', i))
|
||||||
item = block.get_pointer(path)
|
|
||||||
if item:
|
if item:
|
||||||
yield item.get_pointer(b'tex')
|
yield item.get_pointer(b'tex')
|
||||||
yield item.get_pointer(b'object')
|
yield item.get_pointer(b'object')
|
||||||
@@ -679,7 +680,7 @@ class ExpandID:
|
|||||||
assert(block.dna_type.dna_type_id == b'bNodeTree')
|
assert(block.dna_type.dna_type_id == b'bNodeTree')
|
||||||
|
|
||||||
sdna_index_bNode = block.file.sdna_index_from_id[b'bNode']
|
sdna_index_bNode = block.file.sdna_index_from_id[b'bNode']
|
||||||
for item in bf_utils.iter_ListBase(block.get_pointer(b'nodes.first')):
|
for item in bf_utils.iter_ListBase(block.get_pointer((b'nodes', b'first'))):
|
||||||
item_type = item.get(b'type', sdna_index_refine=sdna_index_bNode)
|
item_type = item.get(b'type', sdna_index_refine=sdna_index_bNode)
|
||||||
|
|
||||||
if item_type != 221: # CMP_NODE_R_LAYERS
|
if item_type != 221: # CMP_NODE_R_LAYERS
|
||||||
@@ -725,7 +726,7 @@ class ExpandID:
|
|||||||
if block_pose is not None:
|
if block_pose is not None:
|
||||||
assert(block_pose.dna_type.dna_type_id == b'bPose')
|
assert(block_pose.dna_type.dna_type_id == b'bPose')
|
||||||
sdna_index_bPoseChannel = block_pose.file.sdna_index_from_id[b'bPoseChannel']
|
sdna_index_bPoseChannel = block_pose.file.sdna_index_from_id[b'bPoseChannel']
|
||||||
for item in bf_utils.iter_ListBase(block_pose.get_pointer(b'chanbase.first')):
|
for item in bf_utils.iter_ListBase(block_pose.get_pointer((b'chanbase', b'first'))):
|
||||||
item_custom = item.get_pointer(b'custom', sdna_index_refine=sdna_index_bPoseChannel)
|
item_custom = item.get_pointer(b'custom', sdna_index_refine=sdna_index_bPoseChannel)
|
||||||
if item_custom is not None:
|
if item_custom is not None:
|
||||||
yield item_custom
|
yield item_custom
|
||||||
@@ -733,7 +734,8 @@ class ExpandID:
|
|||||||
# 'ob->particlesystem[...].part'
|
# 'ob->particlesystem[...].part'
|
||||||
sdna_index_ParticleSystem = block.file.sdna_index_from_id.get(b'ParticleSystem')
|
sdna_index_ParticleSystem = block.file.sdna_index_from_id.get(b'ParticleSystem')
|
||||||
if sdna_index_ParticleSystem is not None:
|
if sdna_index_ParticleSystem is not None:
|
||||||
for item in bf_utils.iter_ListBase(block.get_pointer(b'particlesystem.first')):
|
for item in bf_utils.iter_ListBase(
|
||||||
|
block.get_pointer((b'particlesystem', b'first'))):
|
||||||
item_part = item.get_pointer(b'part', sdna_index_refine=sdna_index_ParticleSystem)
|
item_part = item.get_pointer(b'part', sdna_index_refine=sdna_index_ParticleSystem)
|
||||||
if item_part is not None:
|
if item_part is not None:
|
||||||
yield item_part
|
yield item_part
|
||||||
@@ -820,7 +822,7 @@ class ExpandID:
|
|||||||
yield block.get_pointer(b'clip', None)
|
yield block.get_pointer(b'clip', None)
|
||||||
|
|
||||||
sdna_index_Base = block.file.sdna_index_from_id[b'Base']
|
sdna_index_Base = block.file.sdna_index_from_id[b'Base']
|
||||||
for item in bf_utils.iter_ListBase(block.get_pointer(b'base.first')):
|
for item in bf_utils.iter_ListBase(block.get_pointer((b'base', b'first'))):
|
||||||
yield item.get_pointer(b'object', sdna_index_refine=sdna_index_Base)
|
yield item.get_pointer(b'object', sdna_index_refine=sdna_index_Base)
|
||||||
|
|
||||||
block_ed = block.get_pointer(b'ed')
|
block_ed = block.get_pointer(b'ed')
|
||||||
@@ -834,7 +836,8 @@ class ExpandID:
|
|||||||
if item_type >= C_defs.SEQ_TYPE_EFFECT:
|
if item_type >= C_defs.SEQ_TYPE_EFFECT:
|
||||||
pass
|
pass
|
||||||
elif item_type == C_defs.SEQ_TYPE_META:
|
elif item_type == C_defs.SEQ_TYPE_META:
|
||||||
yield from seqbase(bf_utils.iter_ListBase(item.get_pointer(b'seqbase.first', sdna_index_refine=sdna_index_Sequence)))
|
yield from seqbase(bf_utils.iter_ListBase(
|
||||||
|
item.get_pointer((b'seqbase' b'first'), sdna_index_refine=sdna_index_Sequence)))
|
||||||
else:
|
else:
|
||||||
if item_type == C_defs.SEQ_TYPE_SCENE:
|
if item_type == C_defs.SEQ_TYPE_SCENE:
|
||||||
yield item.get_pointer(b'scene')
|
yield item.get_pointer(b'scene')
|
||||||
@@ -845,12 +848,13 @@ class ExpandID:
|
|||||||
elif item_type == C_defs.SEQ_TYPE_SOUND_RAM:
|
elif item_type == C_defs.SEQ_TYPE_SOUND_RAM:
|
||||||
yield item.get_pointer(b'sound')
|
yield item.get_pointer(b'sound')
|
||||||
|
|
||||||
yield from seqbase(bf_utils.iter_ListBase(block_ed.get_pointer(b'seqbase.first')))
|
yield from seqbase(bf_utils.iter_ListBase(
|
||||||
|
block_ed.get_pointer((b'seqbase', b'first'))))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expand_GR(block): # 'Group'
|
def expand_GR(block): # 'Group'
|
||||||
sdna_index_GroupObject = block.file.sdna_index_from_id[b'GroupObject']
|
sdna_index_GroupObject = block.file.sdna_index_from_id[b'GroupObject']
|
||||||
for item in bf_utils.iter_ListBase(block.get_pointer(b'gobject.first')):
|
for item in bf_utils.iter_ListBase(block.get_pointer((b'gobject', b'first'))):
|
||||||
yield item.get_pointer(b'ob', sdna_index_refine=sdna_index_GroupObject)
|
yield item.get_pointer(b'ob', sdna_index_refine=sdna_index_GroupObject)
|
||||||
|
|
||||||
# expand_GR --> {b'GR': expand_GR, ...}
|
# expand_GR --> {b'GR': expand_GR, ...}
|
||||||
|
Reference in New Issue
Block a user