Files
templates/python/set_devices/bin_compare.py

65 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Renderer-independent comparison of arbitrary binary files."""
from __future__ import annotations
from dataclasses import dataclass
import hashlib
def compare_sha256(image: bytes, readback: bytes):
"""Compare a complete physical readback against an immutable BIN snapshot."""
if not image or len(image) != len(readback):
raise ValueError('Для SHA-256 нужен полный прочитанный диапазон размером с BIN.')
expected = hashlib.sha256(image).hexdigest()
actual = hashlib.sha256(readback).hexdigest()
return expected == actual, expected, actual
@dataclass(frozen=True)
class Comparison:
left: bytes
right: bytes
offsets: tuple[int, ...]
changed_bits: int
@property
def changed_bytes(self) -> int:
return len(self.offsets)
@property
def size(self) -> int:
return max(len(self.left), len(self.right))
def compare(left: bytes, right: bytes) -> Comparison:
"""Count bit differences in overlap; unmatched bytes count as changed bytes."""
common = min(len(left), len(right))
offsets = tuple(i for i in range(common) if left[i] != right[i])
bits = sum(bin(left[i] ^ right[i]).count('1') for i in offsets)
return Comparison(left, right, offsets + tuple(range(common, max(len(left), len(right)))), bits)
@dataclass(frozen=True)
class MultiComparison:
images: tuple[bytes, ...]
offsets: tuple[int, ...]
pairs: tuple
@property
def size(self): return max(map(len, self.images))
@property
def changed_bytes(self): return len(self.offsets)
def compare_many(images):
"""Highlight offsets where any pair differs, including missing bytes."""
images = tuple(images)
if len(images) not in (1, 2, 3):
raise ValueError('Выберите от 1 до 3 BIN-файлов.')
if len(images) == 2:
return compare(*images)
pairs = tuple((a, b, compare(images[a], images[b]))
for a in range(len(images)) for b in range(a + 1, len(images)))
offsets = tuple(sorted({offset for _, _, result in pairs for offset in result.offsets}))
return MultiComparison(images, offsets, pairs)