Integra il parser esatto del .asm nella GUI (fase 4 e 5)

AsmRecordReader (spostato da scripts/CreoBom.cs nel progetto principale,
unica fonte di verita' condivisa con lo script via #:project) sostituisce
AssemblyComponentScanner in Form1.RisolviAlberoComponenti (fase "Trova
componenti referenziati") e AssiemeCompleto (fase "Verifica completezza"):
legge esattamente la sezione "members" del binario invece di contare
occorrenze testuali, eliminando i falsi positivi/negativi noti dell'euristica
(riferimenti fantasma, placement senza suffisso, ecc.).

Se un file non rispetta il formato validato (InvalidDataException, coperto
solo dagli 8 campioni usati per il reverse engineering) Form1 ripiega
sull'euristica di AssemblyComponentScanner, che resta quindi come fallback
e come fonte di verita' per gli script BomViaDb.cs/ExtractCreoStrings.cs.

Aggiunti test per AsmRecordReader (fixture binarie costruite a mano: lettura
membri, risoluzione ConfigName, conteggio disallineato, sezione assente).
Aggiornata la documentazione (CLAUDE.md, docs/architettura.md,
docs/formato-asm.md, docs/formato-asm-record.md) di conseguenza.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5 committed 2026-09-21 16:14:00 +02:00
1 parent 60dfd26e8b
commit cce377a091
8 files changed
+363 -163

No files matched your search

+13 -9
View File
@@ -7,7 +7,11 @@ l'euristica testuale ("codice che compare almeno due volte") descritta in
[`formato-asm.md`](formato-asm.md): quella era una statistica sui nomi, questa legge la
struttura effettiva dei record.
Implementazione: [`scripts/CreoBom.cs`](../scripts/CreoBom.cs).
Implementazione: lettura in [`PrepStep/AsmRecordReader.cs`](../PrepStep/AsmRecordReader.cs)
(condivisa con la GUI, `Form1.EstraiCodiciReferenziati` in fase "Trova componenti
referenziati"/"Verifica completezza" - con fallback su `AssemblyComponentScanner` per i file
che non rispettano il formato validato), resa in formato BOM e ricorsione sui sottoassiemi
in [`scripts/CreoBom.cs`](../scripts/CreoBom.cs) (via `#:project`).
**Stato della validazione.** Durante il reverse engineering, il livello 1 estratto da 3
assiemi con BOM Creo di riferimento coincideva **esattamente**: stesse voci, stesso nome
@@ -75,7 +79,7 @@ conteggio dei membri: con la lettura a 1 byte fisso i campioni grandi si
disallineavano. Non è confermata da una specifica; regge sui campioni
disponibili al momento del reverse engineering.
In `CreoBom.cs` è `CreoAsm.AsInt`, applicata al testo decodificato Latin1 (ogni `char`
In `CreoBom.cs` è `AsmRecordReader.AsInt`, applicata al testo decodificato Latin1 (ogni `char`
della stringa corrisponde 1:1 a un byte, quindi indicizzare la stringa o l'array di byte
originale dà lo stesso offset).
@@ -128,15 +132,15 @@ codici distinti: una parte montata 4 volte conta 4 e compare in 4 record con id
diversi. Il conteggio va usato come controllo di correttezza: se i record
trovati non sono esattamente `N`, la lettura si è disallineata e va segnalata
un'eccezione invece di restituire un risultato parziale silenzioso — vedi
`CreoAsm.LeggiMembri`, che lancia `InvalidDataException` in questo caso.
`AsmRecordReader.LeggiMembri`, che lancia `InvalidDataException` in questo caso.
La sezione termina a `\xf4\x04#\n#MdlStatus\n`.
### 3.1 Come lo legge `CreoAsm.LeggiMembri`
### 3.1 Come lo legge `AsmRecordReader.LeggiMembri`
Il parser non ricostruisce lo schema completo (servirebbe decodificare le
matrici). Si ancora invece al pattern `\xe3 <int> <int> <stringa>\0 <stringa>\0`
(`CreoAsm.MemberRegex`, una regex .NET sul testo Latin1 del file) e salta il
(`AsmRecordReader.MemberRegex`, una regex .NET sul testo Latin1 del file) e salta il
resto del record fino al `\xe3` successivo che soddisfa il pattern.
La doppia stringa terminata da `\0` rende i falsi positivi improbabili, e il
conteggio dichiarato `N` fa da rete di sicurezza.
@@ -172,14 +176,14 @@ Il collegamento sta in un record di **parametro** applicato al membro:
linea), poi è omesso.
- `\x82\x7b` — costante (= 635) identica su tutte le occorrenze di tutti i
campioni. Significato ignoto, presumibilmente attributi/flag del parametro.
`CreoAsm.ConfigNameRegex` la usa come ancora di fine record; se un campione
`AsmRecordReader.ConfigNameRegex` la usa come ancora di fine record; se un campione
futuro avesse un valore diverso, il match salterebbe silenziosamente (nessun
contatore di sicurezza analogo a quello di `members` copre questo caso).
`ConfigName` compare **esattamente** per i membri che sono istanze, e per
nessun altro. L'algoritmo è quindi: leggere `members`, costruire la mappa
`id membro → nome istanza` dai record `ConfigName`
(`CreoAsm.LeggiMembri`, dizionario `istanze`), e sostituire il nome dove la
(`AsmRecordReader.LeggiMembri`, dizionario `istanze`), e sostituire il nome dove la
mappa ha una voce. Il generico resta disponibile come `Membro.File`.
> **Avvertenza.** `ConfigName` sta in mezzo a parametri palesemente aziendali
@@ -218,7 +222,7 @@ primo record `objname` del file:
```
La **prima** occorrenza è il modello stesso; quelle successive sono altri
oggetti referenziati (disegni, modelli citati). `CreoAsm.NomeProprio` cerca
oggetti referenziati (disegni, modelli citati). `AsmRecordReader.NomeProprio` cerca
solo la prima occorrenza (`Regex.Match`, non `Matches`), verificato su tutti i
campioni disponibili durante il reverse engineering.
@@ -297,7 +301,7 @@ Elencato esplicitamente per non far passare per dimostrato ciò che non lo è:
situazione divergerebbe.
- **La costante `\x82\x7b`** nei record `ConfigName`.
- **I campi numerici dell'header** dopo `ASSEMBLY`.
- **Occorrenze multiple di `members`.** `CreoAsm.LeggiMembri` prende la prima.
- **Occorrenze multiple di `members`.** `AsmRecordReader.LeggiMembri` prende la prima.
Sui campioni disponibili funziona, ma non è stato verificato se le
rappresentazioni semplificate (simplified rep) generino sezioni `members`
aggiuntive.