- Batch the DB lookup per file instead of per code in scripts/ExtractCreoStrings.cs: files_ultima_versione is an unmaterialized view, so each query rescanned the whole files table (~230ms) - batching cuts a multi-minute BFS to seconds. - Widen the code regex to accept a revision letter and a "_..." suffix together (e.g. "9284200366A_C01"), and purely numeric "_NNNN" suffixes (e.g. dimensional variants like "2702220182_8188"), not just letter+digits. - Require bare digit-only candidates to also appear inside a real "Componente ID N (...)"/"Component id N (...)" placement, filtering out incidental references to a containing assembly's own code. - scripts/ExtractCreoStrings.cs now reports only the direct references of the given .asm (one level, matching Creo's own tree for that file) instead of recursing into sub-assemblies. - Port the regex and placement-check refinements to the production AssemblyComponentScanner.cs used by the app's "Trova componenti referenziati" and "Verifica completezza" phases. - Document the new false-positive categories (parent/container self-reference, suppressed/removed components with residual placement, placement missing suffix/bracket detail) in docs/formato-asm.md, generalized beyond the specific assemblies used to find them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
200 lines
10 KiB
Markdown
200 lines
10 KiB
Markdown
# Come leggere un .asm Creo per dedurne i componenti
|
|
|
|
Il file `.asm` di Pro/ENGINEER-Creo è un formato binario proprietario, non
|
|
documentato pubblicamente. Non esiste un parser strutturale completo in questo
|
|
progetto: l'estrazione dei componenti si basa su un'euristica testuale,
|
|
validata a mano confrontando l'output con l'albero reale mostrato da Creo.
|
|
Questo documento riassume cosa si è osservato e i suoi limiti.
|
|
|
|
## Struttura osservata
|
|
|
|
Il file contiene, frammentate tra dati binari, molte coppie testuali del tipo
|
|
|
|
```
|
|
<nome_campo>\x00<valore>\x00
|
|
```
|
|
|
|
in encoding a 1 byte per carattere (Latin1/ASCII), es.:
|
|
|
|
```
|
|
6d 6f 64 65 6c 5f 6e 61 6d 65 00 39 30 34 34 32 30 37 30 36 31 5f 43 30 31 23 41 46 30 00
|
|
m o d e l _ n a m e \0 9 0 4 4 2 0 7 0 6 1 _ C 0 1 # A F 0 \0
|
|
```
|
|
|
|
I codici dei componenti (propri e sotto-componenti) compaiono come stringhe
|
|
ASCII leggibili in diversi campi ricorrenti:
|
|
|
|
- `model_name`, `generic_name`, `inst_name`, `gen_name`, `feat_name`,
|
|
`family_name`, `name` — metadati associati a un modello referenziato.
|
|
- `Componente ID N (<codice>.PRT|.ASM)` — riga di placement: `N` è un ID
|
|
progressivo assegnato da Creo al componente posizionato nell'assieme.
|
|
- `<codice>#AF0` — riferimento con suffisso di versione/configurazione.
|
|
|
|
Un codice reale compare **più volte** nel file (una per feature/placement
|
|
diverso); rumore binario che assomiglia casualmente a un codice compare quasi
|
|
sempre una sola volta. Questa è la base del filtro in
|
|
[`AssemblyComponentScanner.cs`](../CadSearchGui/AssemblyComponentScanner.cs)
|
|
e in [`scripts/ExtractCreoStrings.cs`](../scripts/ExtractCreoStrings.cs):
|
|
|
|
```
|
|
regex: \b\d{8,12}(?:_[A-Za-z]\d{2,4}|[A-Za-z]{0,2})\b
|
|
occorrenze: >= 2
|
|
```
|
|
|
|
`scripts/ExtractCreoStrings.cs` ha una versione più raffinata della regex e un filtro
|
|
aggiuntivo (vedi sotto), non ancora portati in `AssemblyComponentScanner.cs`:
|
|
|
|
```
|
|
regex: \b\d{8,12}[A-Za-z]{0,2}(?:_[A-Za-z]?\d{2,4})?\b
|
|
```
|
|
|
|
(lettera di revisione e suffisso "_..." possono comparire anche insieme, es.
|
|
`9284200366A_C01`; il suffisso dopo "_" può essere puramente numerico, es.
|
|
`2702220182_8188`, non solo lettera+cifre come `_C01`/`_D100`.)
|
|
|
|
## Falsi positivi noti
|
|
|
|
**ID di viste salvate.** Il pattern `ModelView#<numero>` (es.
|
|
`ModelView#1073741828`) genera candidati a 10 cifre indistinguibili da un
|
|
codice reale per forma, ma sono ID interni di viste orientate salvate, non
|
|
componenti. Si escludono con un lookbehind negativo sulla regex:
|
|
`(?<!ModelView#)`.
|
|
|
|
**Il codice dell'assieme stesso.** Il proprio codice compare spesso decine di
|
|
volte nei metadati (`CODICE`, `part_table`, `STAMPIGLIATURA`, ecc.) e supera
|
|
quindi la soglia di occorrenze. Va escluso esplicitamente confrontandolo con
|
|
il codice derivato dal nome del file in ingresso (`nomefile.split('.')[0]`).
|
|
|
|
**Il codice dell'assieme padre (o di qualunque altro assieme che lo
|
|
contiene).** Variante dello stesso problema: un sotto-assieme può contenere
|
|
anche il codice dell'assieme che lo referenzia (riferimento al nome
|
|
sessione/file salvato nei metadati), che supera la soglia di occorrenze pur
|
|
non essendo un componente. A differenza del proprio codice, non è noto a
|
|
priori: dipende da dove/come il file è stato aperto o da chi lo referenzia,
|
|
quindi non si può escludere per confronto diretto come per il caso
|
|
precedente. La regola generale che discrimina questo caso: un componente
|
|
vero compare **sempre** anche dentro un vero placement
|
|
`Componente ID N (<codice>...)`/`Component id N (<codice>...)` (la stringa
|
|
cambia con la localizzazione Creo con cui il file è stato salvato - osservate
|
|
sia italiana sia inglese); un riferimento incidentale al nome di un altro
|
|
assieme, anche se ripetuto più volte, non compare mai in quel contesto.
|
|
`scripts/ExtractCreoStrings.cs` applica questa regola ai codici "nudi" (senza
|
|
suffisso `_...` e senza bracket UNI - vedi sotto perché limitata a questi):
|
|
un codice ripetuto ma mai trovato dentro un placement viene scartato. Questo
|
|
NON copre i casi fantasma/soppressi sotto, che hanno un placement
|
|
sintatticamente identico a uno vero e restano quindi indistinguibili a
|
|
livello testuale.
|
|
|
|
**Riferimenti fantasma a codici superati/rinominati.** Caso osservato:
|
|
`9244207061.asm` contiene un riferimento a `9044207061` (stesso numero, prima
|
|
di una rinumerazione) con la stessa identica struttura sintattica di un
|
|
componente vero — `Componente ID 46 (9044207061.ASM)`, più i campi
|
|
`model_name`/`generic_name` corrispondenti. Il codice `9044207061` esiste
|
|
davvero nell'indice CAD (il file vecchio non è stato eliminato dalla share),
|
|
quindi supera anche una validazione incrociata contro il DB. Non è però un
|
|
componente realmente presente nell'albero mostrato da Creo per quell'assieme
|
|
(confermato aprendo il file in Creo).
|
|
|
|
Questo caso **non è distinguibile a livello testuale**: la sintassi è
|
|
identica a quella di un placement reale. Nessuna euristica sulla stringa
|
|
riesce a discriminarlo in modo affidabile senza rischiare di scartare
|
|
componenti veri con pattern simili altrove. Se ricompare, l'unica verifica
|
|
sicura resta l'apertura manuale in Creo del sotto-assieme sospetto.
|
|
|
|
**Componenti soppressi/rimossi con placement residuo.** Stessa natura del
|
|
caso precedente: capita che un codice compaia con un vero
|
|
`Componente ID N (<codice>.PRT)`/`Component id N (<codice>.PRT)` - con un ID
|
|
numerico nello stesso intervallo di quelli dei componenti realmente visibili
|
|
nell'albero Creo, quindi non distinguibile per posizione o formato - ma il
|
|
codice non compare nell'albero/BOM che Creo mostra per quell'assieme.
|
|
Osservato su più assiemi in questa sessione (`9044207061` dentro
|
|
`9244207061.asm`, e diversi codici dentro `9284208188_D200.asm`). Ipotesi più
|
|
probabile: feature soppresse, cancellate o superate in una revisione
|
|
successiva, il cui placement resta comunque nella storia binaria del file
|
|
(Creo non riscrive da zero il file a ogni salvataggio, accumula stato). Nella
|
|
pratica, quando compaiono, sono un numero ridotto di codici extra rispetto al
|
|
reale (falsi positivi, non falsi negativi): la BOM generata resta un
|
|
sovrainsieme sicuro dei componenti veri, mai un sottoinsieme. Nessuna
|
|
euristica testuale può escluderli con certezza; se serve un elenco esatto
|
|
l'unica verifica è aprire l'assieme in Creo e controllare a mano quali ID
|
|
sono effettivamente presenti/attivi.
|
|
|
|
**Placement senza il dettaglio del suffisso/bracket.** Il testo dentro
|
|
`Componente ID N (...)` a volte riporta solo il nome generico/istanza, senza
|
|
il suffisso di variante dimensionale o il bracket family-table, che compaiono
|
|
invece solo altrove nei metadati dello stesso file (non vicino al placement).
|
|
Osservato in due forme sullo stesso assieme (`9284208188_D200.asm`):
|
|
`Component id 82 (R8--_-_U6592.PRT)` (nessun `<UNI6592>` nel placement, pure
|
|
presente nel file) e `Component id 150 (2702220182.PRT)` (nessun `_8188`
|
|
nel placement, mentre la variante dimensionale reale `2702220182_8188`
|
|
compare solo come stringa ripetuta altrove). Per questo il requisito del
|
|
placement esplicito (caso sopra) si applica solo ai codici "nudi" (senza
|
|
suffisso `_...` e senza bracket UNI): per le varianti con suffisso o family
|
|
table il placement può mancare del dettaglio, quindi resta necessaria la
|
|
sola euristica delle occorrenze ripetute - meno precisa, ma l'unica
|
|
applicabile senza rischiare falsi negativi su casi come questi.
|
|
|
|
## Viti/dadi/rosette normalizzati (family table UNI)
|
|
|
|
I componenti di minuteria standard (viti, dadi, rosette UNI) sono definiti in
|
|
Creo come **family table**: un file generico (es. `uni6592.prt`) con tante
|
|
righe/istanze quante sono le varianti dimensionali. Nel binario dell'assieme
|
|
compaiono così:
|
|
|
|
```
|
|
Componente ID 28755 (R6--_-_U6592<UNI6592>.PRT)
|
|
```
|
|
|
|
`R6--_-_U6592` è il nome della singola istanza (riga della family table), **non
|
|
un file separato su disco** — sulla share esiste solo `uni6592.prt.<versione>`
|
|
(verificato in `Unificati/`). Cercare l'istanza intera nell'indice fallisce
|
|
sempre; va estratto solo il contenuto tra `<` e `>` (`UNI6592`), che coincide
|
|
col nome del file generico realmente indicizzato:
|
|
|
|
```
|
|
regex aggiuntiva: (?<=<)UNI\d+(?=>)
|
|
```
|
|
|
|
Implementata sia in [`scripts/ExtractCreoStrings.cs`](../scripts/ExtractCreoStrings.cs) sia in
|
|
[`AssemblyComponentScanner.cs`](../CadSearchGui/AssemblyComponentScanner.cs) (fase "Trova componenti
|
|
referenziati" dell'app).
|
|
|
|
## Risoluzione ricorsiva dell'albero
|
|
|
|
Un `.asm` referenzia solo i propri sotto-componenti diretti, non l'intero
|
|
albero annidato. Per ricostruire la distinta base completa (non solo il primo
|
|
livello) serve una BFS:
|
|
|
|
1. Estrarre i codici candidati dal file corrente (euristica sopra).
|
|
2. Per ogni codice, cercarlo nell'indice `cad_index.db`
|
|
(`files_ultima_versione`) per sapere se è un `.prt` (foglia) o un `.asm`
|
|
(da accodare alla coda per essere scansionato a sua volta).
|
|
3. Un codice non trovato nell'indice va scartato/segnalato: o è rumore
|
|
binario, o è un componente non ancora indicizzato.
|
|
|
|
Stessa logica di estrazione candidati in due punti del codice, con scopi
|
|
diversi:
|
|
|
|
- [`AssemblyComponentScanner.EstraiCodiciReferenziati`](../CadSearchGui/AssemblyComponentScanner.cs) — solo estrazione dei candidati da un file, usata dalla BFS in [`Form1.RisolviAlberoComponenti`](../CadSearchGui/Form1.cs) (fase "Trova componenti referenziati") e [`Form1.AssiemeCompleto`](../CadSearchGui/Form1.cs) (fase "Verifica completezza").
|
|
- [`scripts/ExtractCreoStrings.cs`](../scripts/ExtractCreoStrings.cs) — estrazione standalone da riga di comando, ma **un solo livello**: riporta solo i riferimenti diretti del file passato (come li mostra Creo per quell'assieme), senza scendere ricorsivamente nei sotto-assiemi. Usato per confrontare l'euristica contro l'albero Creo di un singolo file durante il reverse engineering; non genera una distinta base completa multi-livello.
|
|
|
|
Nota: le query contro `files_ultima_versione` filtrano solo per
|
|
`(cartella_radice, codice, tipo_file)` - se lo stesso codice esiste in più
|
|
cartelle radice sulla share (duplicati/copie storiche), va sempre ordinato
|
|
per `data_modifica DESC` e tenuta solo la riga più recente per tipo, altrimenti
|
|
si rischia di risolvere un codice contro una copia diversa (e potenzialmente
|
|
diversa nel contenuto) da quella realmente referenziata.
|
|
|
|
## Strumento di analisi manuale
|
|
|
|
[`scripts/Analyze.cs`](../scripts/Analyze.cs) stampa il contesto testuale ed
|
|
esadecimale attorno a ogni occorrenza di un pattern in un file binario — usato
|
|
per tutte le osservazioni di questo documento:
|
|
|
|
```powershell
|
|
dotnet run scripts/Analyze.cs -- raw/9244207061.asm.1 "9044207061"
|
|
```
|
|
|
|
Utile per verificare a mano un nuovo falso positivo prima di modificare la
|
|
regex o l'esclusione nello script di estrazione.
|