2026-09-17 09:01:45 +02:00
# 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
```
2026-09-17 14:59:23 +02:00
`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` .)
2026-09-17 09:01:45 +02:00
## 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]` ).
2026-09-17 14:59:23 +02:00
**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
2026-09-17 16:14:52 +02:00
vero compare **sempre** anche dentro un vero placement, in una delle quattro
2026-09-17 15:32:46 +02:00
forme osservate nel binario:
- `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);
- il codice ripetuto due volte di seguito separato da un singolo byte NUL,
`<codice>\0<codice>\0` (osservato per componenti di family table non-UNI,
es. cuscinetti `CUSCI_...` - vedi sotto; il placement testuale
2026-09-17 16:14:52 +02:00
"Componente ID" non li copre, ma questa coppia doppia sì);
- il campo `family_name\0<codice>\0` (con `name` e `family_name` uguali,
entrambi pari al codice). Osservato una sola volta per file, su un
sotto-assieme referenziato come family table generica invece che con un
placement testuale esplicito - caso `9284202452` dentro
`9284208188_D400.asm` : il sotto-assieme (che contiene a sua volta
`9284202452_C01/_C02/_C03` ) non ha nessun `Componente ID (...)` né coppia
NUL, solo questo campo `family_name` . Verificato su 5 file diversi
(`9284208188_D400/D600/D610/D620/D630.asm` ): l'unica occorrenza di
`family_name\0<codice>\0` in ciascuno corrisponde sempre a un componente
reale confermato dalla BOM Creo, mai al riferimento fantasma verso l'alto;
- il codice seguito immediatamente da un bracket, `<codice><GENERICO>`
(senza NUL né spazio in mezzo) - l'istanza di una family table non-UNI
(es. `2510060303<CUSCI_ACBB7>` , un cuscinetto, confermato aprendo l'assieme
in Creo: descrizione "CUSC.OBL.SFERE 2COR 17X40"). Il codice dell'istanza
non è mai indicizzato a sé sulla share (solo il generico tra `<` e `>` lo
è - stesso meccanismo di UNI, vedi sotto), quindi anche riconosciuto come
placement reale finisce comunque negli "scartati" alla ricerca nel DB - ma
in modo tracciabile, invece di sparire in silenzio prima ancora di essere
cercato.
2026-09-17 15:32:46 +02:00
Un riferimento incidentale al nome di un altro assieme, anche se ripetuto più
2026-09-17 16:14:52 +02:00
volte, non compare mai in nessuna delle quattro forme. `scripts/ExtractCreoStrings.cs`
2026-09-17 15:32:46 +02:00
e `AssemblyComponentScanner.cs` applicano questa regola ai codici "nudi" (senza
suffisso `_...` e senza bracket family table - vedi sotto perché limitata a
2026-09-17 16:14:52 +02:00
questi): un codice ripetuto ma mai trovato dentro uno dei quattro segnali
2026-09-17 15:32:46 +02:00
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.
**Il codice radice del proprio assieme (assieme generale, senza suffisso
`_D.../_C...` ).** Caso particolare e sistematico del precedente, non solo
incidentale: un assieme suddiviso in sotto-assiemi con suffisso
(`9284208188_D600.asm` , `_D610.asm` , ...) referenzia **sempre** al suo interno
anche il codice radice dell'assieme generale (`9284208188` , senza suffisso) -
il "padre" a cui tutti i `_D...` appartengono nella struttura Creo - con un
vero placement sintatticamente identico a un componente reale. Non è un
componente di quel sotto-assieme, è la risalita verso l'assieme che lo
contiene. Osservato su `9284208188_D600.asm` : `Componente ID N (9284208188...)` .
Se seguito in una risoluzione ricorsiva, riporta dentro l'intero albero del
prodotto invece del solo sotto-assieme richiesto: 598 componenti raccolti
invece dei ~65 reali. A differenza del caso generico sopra, qui il codice
"padre" _è_ prevedibile a priori (è la parte del proprio codice prima del
primo `_` ), quindi va escluso esplicitamente seminando l'insieme dei codici
già visitati anche con la radice del codice di partenza, non solo con il
codice stesso — non basta il controllo generico sul placement, perché il
placement qui è reale. Vedi `AssemblyComponentScanner.CodiceRadice` .
2026-09-17 14:59:23 +02:00
2026-09-17 09:01:45 +02:00
**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.
2026-09-17 14:59:23 +02:00
**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.
2026-09-17 15:32:46 +02:00
## Componenti normalizzati (family table UNI, CUSCI, ...)
2026-09-17 12:26:31 +02:00
2026-09-17 15:32:46 +02:00
I componenti di minuteria standard (viti, dadi, rosette UNI) e i cuscinetti
(`CUSCI_...` ) sono definiti in Creo come **family table** : un file generico
(es. `uni6592.prt` , `cusci_acbb7.prt` ) con tante righe/istanze quante sono le
varianti dimensionali. Nel binario dell'assieme compaiono così:
2026-09-17 12:26:31 +02:00
```
Componente ID 28755 (R6--_-_U6592<UNI6592>.PRT)
2026-09-17 15:32:46 +02:00
2510060303<CUSCI_ACBB7>
2026-09-17 12:26:31 +02:00
```
2026-09-17 15:32:46 +02:00
`R6--_-_U6592` e `2510060303` sono il nome/codice della singola istanza (riga
della family table), **non un file separato su disco** — sulla share esiste
solo il generico (`uni6592.prt.<versione>` , `cusci_acbb7.prt.<versione>` ,
verificato in `Unificati/` ). Cercare l'istanza intera nell'indice fallisce
sempre; va estratto solo il contenuto tra `<` e `>` (`UNI6592` , `CUSCI_ACBB7` ),
che coincide col nome del file generico realmente indicizzato:
2026-09-17 12:26:31 +02:00
```
2026-09-17 15:32:46 +02:00
regex aggiuntiva: (?<=<)(?:UNI\d+|CUSCI_[A-Za-z0-9]+)(?=>)
2026-09-17 12:26:31 +02:00
```
Implementata sia in [`scripts/ExtractCreoStrings.cs` ](../scripts/ExtractCreoStrings.cs ) sia in
[`AssemblyComponentScanner.cs` ](../CadSearchGui/AssemblyComponentScanner.cs ) (fase "Trova componenti
2026-09-17 15:32:46 +02:00
referenziati" dell'app). Il prefisso family table non è garantito essere solo `UNI` /`CUSCI` :
se ricompaiono famiglie diverse (altri componenti normalizzati), vanno aggiunte allo stesso modo,
verificando prima con `scripts/Analyze.cs` che il contenuto tra `<` e `>` corrisponda a un codice
realmente indicizzato in `Unificati/` .
2026-09-17 12:26:31 +02:00
2026-09-17 09:01:45 +02:00
## Risoluzione ricorsiva dell'albero
Un `.asm` referenzia solo i propri sotto-componenti diretti, non l'intero
2026-09-17 14:59:23 +02:00
albero annidato. Per ricostruire la distinta base completa (non solo il primo
livello) serve una BFS:
2026-09-17 09:01:45 +02:00
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.
2026-09-17 15:32:46 +02:00
Stessa logica di estrazione candidati ed euristica del codice radice (sopra),
duplicata in due punti del codice per scopi diversi:
2026-09-17 09:01:45 +02:00
2026-09-17 15:32:46 +02:00
- [`AssemblyComponentScanner.EstraiCodiciReferenziati` ](../CadSearchGui/AssemblyComponentScanner.cs ) + `CodiceRadice` — 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"). Entrambe seminano l'insieme dei codici visitati con codice + radice di ogni file di partenza.
- [`scripts/ExtractCreoStrings.cs` ](../scripts/ExtractCreoStrings.cs ) — stessa BFS ricorsiva standalone da riga di comando (copia indipendente della stessa euristica, nessun `ProjectReference` verso la GUI). Usato per confrontare l'euristica contro l'albero Creo di un singolo file durante il reverse engineering, senza dover passare dalla UI/dal DB `raw` .
2026-09-17 14:59:23 +02:00
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.
2026-09-17 09:01:45 +02:00
## 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.