Change details: the length cut never hides observed bytes (v2.7.5)
- a record whose FCP understates the layout (the reported case: record_len 2 while the READ RECORD carried P3=0x2C and returned 44 bytes) had its rows cut to two cells by the v2.7.3 length rule, hiding 42 newly-observed bytes while the summary still counted them - the filler now stops at the known length only while the data fits inside it; beyond that — and when the length is unknown or absent — the row ends at the data, so nothing observed is ever hidden and no bytes are invented - verified on the live payload (session 55, 5f3a/4f09 change 0): before = 2 cells, both changed; after = 16+16+12 cells with 2 changed and 42 newly observed, matching the summary line - tests: the regression case (a 2-byte record_len with a 44-byte read) and the unknown-length case, whose row now ends at the data; 527 Python + 76 Node tests - PWA_VERSION/pyproject/version.py 2.7.5, SW cache simtrace-analyser-v85
This commit is contained in:
1 parent
06c6e952a9
commit
1df52a34e5
6 files changed
+23
-8
No files matched your search
+8
-2
@@ -2183,6 +2183,12 @@ function hexImageRows(segments, ranges, observed, limit, size) {
|
|||||||
end = Math.max(end, seg.offset + Math.floor(hex.length / 2));
|
end = Math.max(end, seg.offset + Math.floor(hex.length / 2));
|
||||||
}
|
}
|
||||||
const covered = (list, pos) => (list || []).some(([p, n]) => pos >= p && pos < p + n);
|
const covered = (list, pos) => (list || []).some(([p, n]) => pos >= p && pos < p + n);
|
||||||
|
// The filler stops at the known file/record length (a short file must not
|
||||||
|
// look like it has missing data) — and never hides observed bytes: when
|
||||||
|
// the FCP understates the layout (a 2-byte record_len for a 44-byte
|
||||||
|
// record read) the data's own end is the limit. Without a known length
|
||||||
|
// the row also ends at the data instead of inventing bytes.
|
||||||
|
const stopAt = size && size >= end ? size : end;
|
||||||
const rows = [];
|
const rows = [];
|
||||||
const used = {changed: false, fresh: false, unknown: false};
|
const used = {changed: false, fresh: false, unknown: false};
|
||||||
let truncated = false;
|
let truncated = false;
|
||||||
@@ -2197,7 +2203,7 @@ function hexImageRows(segments, ranges, observed, limit, size) {
|
|||||||
// Never pad past the known file/record length: the filler would
|
// Never pad past the known file/record length: the filler would
|
||||||
// read as missing data when the file is simply short. '--'
|
// read as missing data when the file is simply short. '--'
|
||||||
// still marks bytes inside the file that were never observed.
|
// still marks bytes inside the file that were never observed.
|
||||||
if (size && pos >= size) break;
|
if (stopAt && pos >= stopAt) break;
|
||||||
const hex = bytes.get(pos);
|
const hex = bytes.get(pos);
|
||||||
if (hex === undefined) {
|
if (hex === undefined) {
|
||||||
cells.push({hex: '--', cls: 'hex-unknown'});
|
cells.push({hex: '--', cls: 'hex-unknown'});
|
||||||
@@ -3380,7 +3386,7 @@ function onSearchChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────────── Versioning ────────────────────
|
// ──────────────────── Versioning ────────────────────
|
||||||
const PWA_VERSION = '2.7.4';
|
const PWA_VERSION = '2.7.5';
|
||||||
const MIN_SERVER_VERSION = '2.3.0';
|
const MIN_SERVER_VERSION = '2.3.0';
|
||||||
|
|
||||||
function parseVersion(v) {
|
function parseVersion(v) {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simtrace-analyser-v84';
|
const CACHE = 'simtrace-analyser-v85';
|
||||||
|
|
||||||
const PRECACHE = [
|
const PRECACHE = [
|
||||||
'index.html',
|
'index.html',
|
||||||
|
|||||||
@@ -332,9 +332,18 @@ test('Files view: the hex rows stop at the known length (no filler)', () => {
|
|||||||
assert.equal(rec.rows[0].cells.length, 9);
|
assert.equal(rec.rows[0].cells.length, 9);
|
||||||
assert.equal(rec.rows[0].cells.filter(c => c.cls === 'hex-unknown').length, 5);
|
assert.equal(rec.rows[0].cells.filter(c => c.cls === 'hex-unknown').length, 5);
|
||||||
assert.deepEqual(rec.used, {changed: true, fresh: false, unknown: true});
|
assert.deepEqual(rec.used, {changed: true, fresh: false, unknown: true});
|
||||||
// Without a known length the old row padding stays (nothing better to do).
|
// Without a known length the row ends at the data — no invented bytes.
|
||||||
const noSize = hexImageRows([{offset: 0, hex: 'aabb'}], [], [], undefined, null);
|
const noSize = hexImageRows([{offset: 0, hex: 'aabb'}], [], [], undefined, null);
|
||||||
assert.equal(noSize.rows[0].cells.length, 16);
|
assert.equal(noSize.rows[0].cells.length, 2);
|
||||||
|
// A card whose FCP understates the layout (a 2-byte record_len for a
|
||||||
|
// 44-byte read) must still show every observed byte, not two per row.
|
||||||
|
const wide = hexImageRows(
|
||||||
|
[{offset: 0, hex: 'aa'.repeat(44)}], [[0, 2]], [[2, 42]], undefined, 2);
|
||||||
|
assert.deepEqual(wide.rows.map(r => r.cells.length), [16, 16, 12]);
|
||||||
|
assert.equal(wide.rows[0].cells[0].cls, 'hex-changed');
|
||||||
|
assert.equal(wide.rows[0].cells[2].cls, 'hex-new');
|
||||||
|
assert.equal(wide.used.changed, true);
|
||||||
|
assert.equal(wide.used.fresh, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Files view: the hex image respects the row limit', () => {
|
test('Files view: the hex image respects the row limit', () => {
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "simtrace-analyser"
|
name = "simtrace-analyser"
|
||||||
version = "2.7.4"
|
version = "2.7.5"
|
||||||
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
||||||
readme = {file = "README.md", content-type = "text/markdown"}
|
readme = {file = "README.md", content-type = "text/markdown"}
|
||||||
license = {text = "GPL-2.0-or-later"}
|
license = {text = "GPL-2.0-or-later"}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""Single source of truth for the SIMtrace Analyser version."""
|
"""Single source of truth for the SIMtrace Analyser version."""
|
||||||
|
|
||||||
__version__ = '2.7.4'
|
__version__ = '2.7.5'
|
||||||
@@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase):
|
|||||||
class TestVersion(unittest.TestCase):
|
class TestVersion(unittest.TestCase):
|
||||||
def test_package_version(self):
|
def test_package_version(self):
|
||||||
from simtrace2_pysniff import __version__
|
from simtrace2_pysniff import __version__
|
||||||
self.assertEqual(__version__, '2.7.4')
|
self.assertEqual(__version__, '2.7.5')
|
||||||
|
|
||||||
def test_status_includes_version(self):
|
def test_status_includes_version(self):
|
||||||
import os
|
import os
|
||||||
|
|||||||
Reference in new issue
Block a user