- 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>
10 KiB
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
e in 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 sia in
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:
- Estrarre i codici candidati dal file corrente (euristica sopra).
- 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). - 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— solo estrazione dei candidati da un file, usata dalla BFS inForm1.RisolviAlberoComponenti(fase "Trova componenti referenziati") eForm1.AssiemeCompleto(fase "Verifica completezza").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 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:
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.