Skip to content

Fix ZDE in PackedBitVector #334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions UnityPy/helpers/PackedBitVector.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from typing import TYPE_CHECKING, List, Optional, Tuple
from typing import TYPE_CHECKING, Any, List, Optional, Tuple

if TYPE_CHECKING:
from ..classes.generated import PackedBitVector


def reshape(data: list, shape: Optional[Tuple[int, ...]] = None) -> list:
def reshape(data: list, shape: Optional[Tuple[int, ...]] = None) -> List[Any]:
if shape is None:
return data
if len(shape) == 1:
m = shape[0]
return [data[i : i + m] for i in range(0, len(data), m)]
elif len(shape) == 2:
m, n = shape
return [[[data[i + j : i + j + n] for j in range(0, m * n, n)]] for i in range(0, len(data), m * n)]
return [[data[i + j : i + j + n] for j in range(0, m * n, n)] for i in range(0, len(data), m * n)]
else:
raise ValueError("Invalid shape")

Expand All @@ -22,7 +22,7 @@ def unpack_ints(
start: int = 0,
count: Optional[int] = None,
shape: Optional[Tuple[int, ...]] = None,
) -> List[int]:
) -> List[Any]:
assert packed.m_BitSize is not None
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason why I change it to List[Any] is that the return type may also be List[List[int]] | List[List[List[int]]] after the reshape.

If you want, I can use @overload to optimize the type annotation, which is the best practice but may be too verbose.

@overload
def unpack_ints(
    packed: "PackedBitVector",
    start: int = 0,
    count: Optional[int] = None,
    *,
    shape: None = None,
) -> List[int]: ...

@overload
def unpack_ints(
    packed: "PackedBitVector",
    start: int = 0,
    count: Optional[int] = None,
    *,
    shape: Tuple[int] = None,
) -> List[List[int]]: ...

@overload
def unpack_ints(
    packed: "PackedBitVector",
    start: int = 0,
    count: Optional[int] = None,
    *,
    shape: Tuple[int, int] = None,
) -> List[List[List[int]]]: ...


m_BitSize = packed.m_BitSize
Expand Down Expand Up @@ -70,13 +70,19 @@ def unpack_floats(
start: int = 0,
count: Optional[int] = None,
shape: Optional[Tuple[int, ...]] = None,
) -> List[float]:
) -> List[Any]:
assert packed.m_BitSize is not None and packed.m_Range is not None and packed.m_Start is not None

# read as int and cast up to double to prevent loss of precision
quantized_f64 = unpack_ints(packed, start, count)
scale = packed.m_Range / ((1 << packed.m_BitSize) - 1)
quantized = [x * scale + packed.m_Start for x in quantized_f64]

# avoid zero division of scale
if packed.m_BitSize == 0:
quantized = [packed.m_Start] * len(quantized_f64)
else:
scale = packed.m_Range / ((1 << packed.m_BitSize) - 1)
quantized = [x * scale + packed.m_Start for x in quantized_f64]

return reshape(quantized, shape)


Expand Down
Loading