Skip to content

Commit

Permalink
Truncate arrays if they are longer in recomp
Browse files Browse the repository at this point in the history
  • Loading branch information
disinvite committed Jan 25, 2025
1 parent 985b988 commit 9bebcda
Showing 1 changed file with 44 additions and 33 deletions.
77 changes: 44 additions & 33 deletions reccmp/isledecomp/compare/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,16 +311,6 @@ def _match_array_elements(self):
dataset: dict[int, dict[str, str]] = {}
orig_by_recomp: dict[int, int] = {}

# Helper function
def _add_match_in_array(
name: str, type_id: str, orig_addr: int, recomp_addr: int
):
# pylint: disable=unused-argument
# TODO: Previously used scalar_type_pointer(type_id) to set whether this is a pointer
if recomp_addr not in dataset:
dataset[recomp_addr] = {"name": name}
orig_by_recomp[recomp_addr] = orig_addr

# Indexed by recomp addr. Need to preload this data because it is not stored alongside the db rows.
cvdump_lookup = {x.addr: x for x in self.cvdump_analysis.nodes}

Expand All @@ -335,29 +325,50 @@ def _add_match_in_array(

data_type = self.cv.types.keys[node.data_type.key.lower()]

if data_type["type"] == "LF_ARRAY":
array_element_type = self.cv.types.get(data_type["array_type"])

assert node.data_type.members is not None

for array_element in node.data_type.members:
orig_element_base_addr = match.orig_addr + array_element.offset
recomp_element_base_addr = match.recomp_addr + array_element.offset
if array_element_type.members is None:
_add_match_in_array(
f"{match.name}{array_element.name}",
array_element_type.key,
orig_element_base_addr,
recomp_element_base_addr,
)
else:
for member in array_element_type.members:
_add_match_in_array(
f"{match.name}{array_element.name}.{member.name}",
array_element_type.key,
orig_element_base_addr + member.offset,
recomp_element_base_addr + member.offset,
)
if data_type["type"] != "LF_ARRAY":
continue

# Check whether another orig variable appears before the end of the array in recomp.
# If this happens we can still add all the recomp offsets, but do not attach the orig address
# where it would extend into the next variable.
upper_bound = match.orig_addr + match.size
if (next_orig := self._db.get_next_orig_addr(match.orig_addr)) is not None:
if next_orig < upper_bound:
logger.warning(
"Array variable %s at 0x%x is larger in recomp",
match.name,
match.orig_addr,
)
upper_bound = next_orig

array_element_type = self.cv.types.get(data_type["array_type"])

assert node.data_type.members is not None

for array_element in node.data_type.members:
orig_element_base_addr = match.orig_addr + array_element.offset
recomp_element_base_addr = match.recomp_addr + array_element.offset

if array_element_type.members is None:
# If array of scalars
name = f"{match.name}{array_element.name}"
orig_addr = orig_element_base_addr
recomp_addr = recomp_element_base_addr

dataset[recomp_addr] = {"name": name}
if orig_addr < upper_bound:
orig_by_recomp[recomp_addr] = orig_addr

else:
# Else: multidimensional array or array of structs
for member in array_element_type.members:
name = f"{match.name}{array_element.name}.{member.name}"
orig_addr = orig_element_base_addr + member.offset
recomp_addr = recomp_element_base_addr + member.offset

dataset[recomp_addr] = {"name": name}
if orig_addr < upper_bound:
orig_by_recomp[recomp_addr] = orig_addr

# Upsert here to update the starting address of variables already in the db.
self._db.bulk_recomp_insert(
Expand Down

0 comments on commit 9bebcda

Please sign in to comment.