Matrici 4x3 di fori e feature (regola degli zeri corretta), foro a punti di schizzo con facce piane di Estrusione 1, profilo a L, quote per feature e tipi 928/1104/1052. Corregge l'ipotesi errata sul codice 12266. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
479 lines
27 KiB
Markdown
479 lines
27 KiB
Markdown
# Decodifica del `.prt` Creo: l'albero delle feature
|
|
|
|
Come leggere da un `.prt` (o dalla parte "feature" di un `.asm`) l'**albero delle feature** che
|
|
Creo mostra nel model tree: quali feature ci sono, in che ordine, di che tipo e con che nome.
|
|
Complementare a [`formato-asm-record.md`](formato-asm-record.md), che decodifica la sezione
|
|
`members` dei `.asm`: la serializzazione a marcatori e la codifica degli interi sono le stesse e
|
|
qui non si ripetono (§2 e §2.1 di quel doc).
|
|
|
|
**Stato: ricavato per reverse engineering, nessun codice nel progetto lo usa ancora.** Non c'è un
|
|
`PrtFeatureReader` accanto ad `AsmRecordReader`; la decodifica qui sotto è stata fatta con script
|
|
di prova usa-e-getta. Livelli di prova, da non confondere (come in `formato-asm-record.md`):
|
|
|
|
1. **Contro il model tree reale di Creo** (la prova forte): un solo file, `test.prt.1` (Creo
|
|
9.0.3.0, 11 voci nel tree più la radice, schermata di riferimento). L'albero ricostruito
|
|
dal file coincide voce per voce, per ordine, nome e tipo (§6).
|
|
2. **Sondaggio su `raw/`** (89 file `.prt`/`.asm` reali): solo conteggi e coerenza interna, **non**
|
|
contro il model tree. Serve a dire dove la decodifica regge e dove no (§7), non a provarla.
|
|
|
|
## 1. Il contenitore: header, indice delle sezioni, sezioni
|
|
|
|
Il file è un contenitore "UGC":
|
|
|
|
```
|
|
#UGC:2 PART 2038 1760 805 1 1 15 4000 2022414 000002cc \ <- tipo (PART/ASSEMBLY) e numeri
|
|
#- VERS ... #- UOBJ_ID ... #- CMNM 008test.prt <- campi a righe fisse, chiusi da '\'
|
|
#-END_OF_UGC_HEADER
|
|
#Creo TM 9.0 (c) 2026 by PTC Inc. ... 9.0.3.0 <- versione di Creo che ha salvato
|
|
#UGC_TOC 2 32 81 17####... <- indice delle sezioni
|
|
ND:0:Model_L05_PX:1 ab4 422 541 2038 a 1 b396 68b0####
|
|
SolidPersistTable 13af 878 e84 2038 a 1 a248 3b21####
|
|
...
|
|
BasicData 201c 15761 15756 2038 9 -1 e1de afe3####
|
|
```
|
|
|
|
Il secondo numero dopo `PART`/`ASSEMBLY` (`2038`, `2063`, `1967`, `1376`, `1322`, `1632`...)
|
|
distingue la **generazione del formato** (§1.2 e §7: da lei dipende se le sezioni sono leggibili).
|
|
|
|
### 1.1 Come trovare una sezione (qualsiasi generazione)
|
|
|
|
Ogni riga dell'indice è `nome offset(hex) lunghezza(hex) <campi>`, con i campi, in ordine:
|
|
`<dimensione decompressa(hex), oppure 1> <generazione> <tipo(hex)> <metodo> <crc1> <crc2>`. Il
|
|
`<metodo>` vale `-1` per le sezioni non compresse.
|
|
|
|
**Gli offset dell'indice non sono offset di file**: sono relativi a un'origine spostata di una
|
|
costante `K` che cambia da file a file (727 in `test.prt.1`, 1563 in `1701010009.prt.1`). Regola
|
|
ricavata e verificata, perché le sezioni sono contigue fino alla fine del file:
|
|
|
|
```
|
|
K = dimensioneFile - (offsetUltimaSezione + lunghezzaUltimaSezione) - 1
|
|
inizio sezione = K + offset
|
|
```
|
|
|
|
Verifica: con questa regola le sezioni non compresse cominciano esattamente con
|
|
`e0 00 Sld_...` (es. `Sld_BasicData`, `Sld_Features`) in tutti i file dove l'ho provata
|
|
(controllato su `AllFeatur`: 86 file su 89; i 3 che non tornano sono `.prt` del 2038 con `AllFeatur` vuoto, non ho indagato).
|
|
Nei file recenti il corpo è inoltre preceduto da una riga marcatore (`#`, a capo, `#<Nome>`, a capo),
|
|
che è un secondo modo di trovare la sezione (equivalente: l'inizio è la fine del marcatore).
|
|
|
|
```
|
|
#
|
|
#AllFeatur
|
|
<corpo della sezione> #
|
|
#BasFullData
|
|
...
|
|
```
|
|
|
|
### 1.2 Come si leggono i contenuti: tre modi di conservarli
|
|
|
|
Il `<tipo>` dell'indice dice come la sezione è stata scritta. Sul corpus di `raw/` (89 file):
|
|
|
|
| Tipo | Come è conservata | Dove | Decodifica |
|
|
|---|---|---|---|
|
|
| `9` | **in chiaro**: formato a marcatori, comincia con `e0 00 Sld_<nome>` | quasi tutte le sezioni nei file `1632`, `1967`, `2038`, `2063`; le sezioni "leggere" (`BasicData`, `LargeText`...) anche in quelli vecchi | si legge direttamente |
|
|
| `a`, `10`, `12`, `18` (metodo `1`/`2`) | compressa **Unix `compress` (`.Z`, LZW)**: dopo la riga del nome c'è la firma `1f 9d 10` | `ND:0:Model_*`, `SolidPersistTable`, `SolidPrimdata`, `DispDataTable` | decodificabile con un LZW standard (verificato: `gzip -dc` apre lo stream così com'è) |
|
|
| `11` | **non decodificata**: i primi 4 byte sono in chiaro (`e0 00` + le prime due lettere del nome, es. `Sl`), il resto ha entropia massima | `AllFeatur`, `VisibGeom`, `NovisGeom`, `IndentTag`, `FeatRefData` nei file `1322`, `1375`, `1376` | **da risolvere**, vedi §1.3 |
|
|
|
|
Le sezioni `.Z` non servono per le feature, ma una vale la pena di conoscere: `ND:0:Model_*`
|
|
decompressa è un documento XML (SOAP) con **nome del modello, tipo (`prt`/`asm`), numero di
|
|
revisione, e i parametri** (`ParamSet`). È un modo alternativo di leggere i parametri di un
|
|
file senza passare dal formato a marcatori. Non ho decodificato oltre il nome e la revisione.
|
|
|
|
### 1.3 Il blocco: le sezioni di tipo `11` (file 1322/1375/1376)
|
|
|
|
È il limite principale oggi: **54 dei 89 file** (tutti quelli con generazione `1322`, `1375` e
|
|
`1376`, cioè salvati da Pro/ENGINEER Wildfire 2-4) hanno `AllFeatur` in tipo `11`. Sono illeggibili
|
|
con quello che ho: in quei file l'albero delle feature, e la geometria, non si possono ricavare.
|
|
Fa eccezione solo ciò che sta nelle sezioni di tipo `9` (es. la sezione `members` degli
|
|
assiemi, che è la ragione per cui `AsmRecordReader` funziona anche su file vecchi).
|
|
|
|
Quello che ho escluso, per non rifarlo:
|
|
|
|
- **Non è un XOR a chiave fissa**: noto il testo in chiaro dei primi ~40 byte
|
|
(`Sld_Features |