# 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) `, con i campi, in ordine: ` `. Il `` 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, `#`, a capo), che è un secondo modo di trovare la sezione (equivalente: l'inizio è la fine del marcatore). ``` # #AllFeatur # #BasFullData ... ``` ### 1.2 Come si leggono i contenuti: tre modi di conservarli Il `` 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_` | 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ãàfirst_feat_ptr...`, identico in tutti i file) e sceso il flusso cifrante (cifrato XOR chiaro), questo **cambia da file a file**. - **Non ha periodicità e non ripete sequenze**: indice di coincidenza = 1/256 a ogni periodo provato (1-39), nessun gruppo di 4 byte ripetuto in 3829 byte. Statisticamente è compresso bene o cifrato. - **Non è zlib/deflate** (provato a ogni offset 0-11, formati zlib, raw, gzip) **né LZW `.Z`** (provato a ogni offset 0-8, con 10 combinazioni di flag, via `gzip -dc`). - Non dipende dai `crc` della riga dell'indice in modo che io abbia visto. I 4 file in generazione `1632` hanno gli stessi dati in chiaro (tipo `9`): quindi la cifratura/ compressione è una caratteristica della generazione del programma, non del contenuto, e il modo più semplice per leggere un file vecchio è **riaprirlo in Creo e risalvarlo** (diventa tipo `9`). Possibili strade se serve leggere i vecchi senza Creo: confrontare lo stesso modello salvato da Wildfire 4 e da Creo 9 (stesso contenuto, due forme) per avere coppie chiaro/cifrato, oppure riaprire in Creo un file `1376` e risalvarlo con la stessa revisione. Le sezioni sono lo stesso formato a marcatori dei `.asm` (`\xe0 \0 `, array `\xf8`, schemi `\xf7`...). Valore in più rispetto ai `.asm`: `\xeb` introduce un intero a 4 byte big-endian (osservato in `time`, `random_num`). Le sezioni che servono per le feature: | Sezione | Cosa contiene | Serve per | |---|---|---| | `AllFeatur` | la lista **ordinata** di tutte le feature, con id e tipo | ordine, tipo, esistenza | | `MdlStatus` | lo storico delle modifiche; contiene i record di creazione con il nome | nome, icona, feature precedente | | `MdlRefInfo` / `ActDatums` | geometria di riferimento dei piani e del sistema di assi | nome del sistema di assi (`PRT_CSYS_DEF`) | ## 2. Le feature: `AllFeatur` `AllFeatur` è una **lista concatenata** (`first_feat_ptr`, poi `next_feat_ptr` in ogni record): un record per feature, nell'ordine di rigenerazione. Il primo record è scritto con i nomi di campo per esteso, quelli dopo sono posizionali (compressione per schema, `formato-asm-record.md` §2.2). I campi che contano, per ogni record: | Campo | Significato | Dove si trova | |---|---|---| | `id` | identificatore della feature nel modello (intero §2.1) | all'inizio del record | | `feat_type_ptr.type` | **tipo** di feature (§4) | `\xe3 \xf6 <2 byte>` | | `sect_name` | nome, solo per alcuni tipi (piani di riferimento) | stringa `\0` verso la fine del record | | `attributes` | flag della feature (§3) | subito dopo il tipo | Come si individua il record nei byte, perché non serve decodificare tutto lo schema: ``` primo record: ... \x01id\0 ... \x01table_id\0 \xf6 \xe0\x01type\0 ... secondo record: \xf7 \xeb ... \xe3 \xf6 ... record successivi:\xe3 \xeb <4 byte> ... \xe3 \xf6 ... ``` - `\xe3 \xf6 ` con `b0` in `0x80`-`0xbf` è l'àncora: `` è il tipo come intero a 2 byte (§2.1: `(b0 & 0x3f) << 8 | b1`). - L'`id` è l'intero che precede, nei 70 byte prima, il pattern ` \xeb`. - Esempio dal campione, il record di `DTM1`: `e3 80 93 eb 04 00 10 01 00 e6 | e3 f6 83 9b | ...` cioè `id = 0x93 = 147` (due byte: `0x80 0x93`) e `tipo = 0x839b = 923`. Nel campione la lista contiene **13** record, ma il model tree ne mostra **10** più la radice: | id | tipo | in `AllFeatur` | nel tree di Creo | |---|---|---|---| | 1 | 923 | RIGHT | RIGHT | | 3 | 923 | TOP | TOP | | 5 | 923 | FRONT | FRONT | | 7 | 979 | (sistema di assi) | PRT_CSYS_DEF | | 74 | 923 | piano interno | — | | 73 | 949 | schizzo | Sketch 1 | | 80 | 923 | piano interno | — | | 79 | 917 | protrusione | Estrusione 1 | | 100 | 911 | foro | Foro 1 | | 125 | 913 | raccordo | Arrotondamento 1 | | 147 | 923 | piano | DTM1 | | 150 | 923 | piano interno | — | | 149 | 917 | protrusione | Estrusione 2 | | 188 | 914 | smusso | Smusso 1 | Le tre righe senza voce nel tree sono **piani di riferimento interni**: Creo li crea da sé quando si apre uno schizzo o un'estrusione e non li mostra. Vanno scartati, e il file lo dice (§3). ## 3. Quali feature sono nel tree: i piani interni I piani interni (`74`, `80`, `150`) si distinguono perché il blocco `attributes` subito dopo il tipo ha una forma diversa da quella di un piano che l'utente vede: ``` piano visibile (id 5, 147): e3 f6 83 9b | e1 00 00 e7 07 10 00 e5 00 ... piano interno (id 74,80,150): e3 f6 83 9b | e1 00 03 00 e4 eb 40 00 00 00 00 e7 07 00 ... ``` Regola usata: il record è interno se entro 10 byte dal tipo compare la sequenza `03 00 e4 eb 40`. Non ho decodificato i singoli bit di `attributes`: la regola è un riconoscitore del *pattern*, non la lettura di un flag con nome. Prova (livello 2, vale solo dove esistono i nomi di §5 e dove l'`id` è stato letto, vedi §7): sugli 11 file con record di creazione, i piani con quel pattern sono **13**, e **nessuno** ha un nome nello storico; i piani senza il pattern e con un nome sono 7. Nessuna eccezione, ma sono pochi file. ## 4. Il tipo di feature `feat_type_ptr.type` è un intero. I valori incontrati, con l'icona che lo storico (§5) associa alle feature di quel tipo: | Tipo | Icona (`icon_name`) | Significato | Verificato su | |---|---|---|---| | 911 | `feathole` | Foro | `test.prt.1` (Foro 1) | | 913 | `featround` | Raccordo (Arrotondamento) | `test.prt.1` | | 914 | `featchamfer` | Smusso | `test.prt.1` | | 916 | `cutextrude`, `cutrevolve` | Taglio (estrusione o rivoluzione) | sondaggio `raw/` | | 917 | `protextrude`, `protrevolve` | Protrusione (estrusione o rivoluzione) | `test.prt.1` (estrusione) | | 923 | `dtmplane` | Piano di riferimento | `test.prt.1` | | 926 | `dtmaxis` | Asse di riferimento | sondaggio `raw/` | | 931 | `dtmpoint` | Punto di riferimento | sondaggio `raw/` | | 949 | `dtmsktcurve`, `dtmcurve` | Schizzo / curva | `test.prt.1` (schizzo) | | 979 | `dtmcoordsys` | Sistema di assi | `test.prt.1` | | 1052 | `section_planar16X16` | Sezione | sondaggio `raw/` | | 1118 | `def_compintfc` | Interfaccia di componente | sondaggio `raw/` | | 1000 | — | Componente di assieme (nei `.asm`) | sondaggio `raw/`, nessun nome | Altri tipi compaiono in `AllFeatur` senza nessun nome nello storico, quindi non so cosa siano: `214`, `258`, `932`, `1070`, `1104`, `1232`, `1238`. Vanno trattati come "feature di tipo N", non inventati. > **Il tipo non distingue estrusione da rivoluzione.** `917` vale per `protextrude` e per > `protrevolve`, `916` per `cutextrude` e `cutrevolve`: la differenza sta solo nell'icona dello > storico (§5). Senza quel record non si può dire se la protrusione è un'estrusione. Lo stesso > vale per tutti i tipi: la tabella è "tipo → famiglia", non "tipo → nome del comando". I valori coincidono con quelli che ricordo delle costanti `PRO_FEAT_*` di Creo Toolkit (es. `PRO_FEAT_HOLE`=911), ma **non l'ho verificato su una fonte**: la tabella sopra poggia solo sui file. ## 5. I nomi e l'ordine del tree: lo storico in `MdlStatus` `AllFeatur` dà ordine e tipo, **non il nome**. Il nome che Creo mostra ("Estrusione 1", "Foro 1") sta nello storico delle modifiche, sezione `MdlStatus`, in un record di creazione per ogni feature creata dall'utente: ``` \xe0\x00 typed_data(MTTyped_CreateData) \0 \xe3 \xe0\x00 created_features \0 \xf8 \xf7 \xfb \xe3 \xe0\x01 feat_id \0 \xe0\x01 ft_type \0 \xe0\x01 comp_type \0 <0> \xe0\x01 prev_feat_id \0 \xe0\x0a feat_name \0 \0 \xe0\x01 pat_group_header_id \0 ... \xe0\x01 is_header \0 ... \xe0\x03 icon_name \0 \0 ``` Il primo record porta i nomi di campo; i successivi sono posizionali e si riconoscono dalla forma ` \0 \0 \0`. Dal campione, tutti e 7: | `feat_id` | `ft_type` | `prev_feat_id` | `feat_name` | `icon_name` | |---|---|---|---|---| | 73 | 949 | 7 | Sketch 1 | `dtmsktcurve` | | 79 | 917 | 73 | Estrusione 1 | `protextrude` | | 100 | 911 | 79 | Foro 1 | `feathole` | | 125 | 913 | 100 | Arrotondamento 1 | `featround` | | 147 | 923 | 125 | DTM1 | `dtmplane` | | 149 | 917 | 147 | Estrusione 2 | `protextrude` | | 188 | 914 | 149 | Smusso 1 | `featchamfer` | Due cose da notare: - **`prev_feat_id` è la catena del tree.** Salta i piani interni: `73` punta a `7`, non a `74`, che pure lo precede in `AllFeatur`. Seguire `prev_feat_id` dà quindi già l'ordine delle sole feature visibili. - **I nomi sono nella lingua della sessione che ha creato la feature** ("Estrusione", non "Extrude"): `test.prt.1` è stato fatto con Creo in italiano. Non si può dedurre il nome dal tipo da una tabella fissa. I nomi di default sono eccezioni, e stanno altrove: - **RIGHT, TOP, FRONT, DTM1**: nel record di `AllFeatur`, campo `sect_name` (stringa subito dopo `attributes`). DTM1 è anche nello storico. - **PRT_CSYS_DEF** (id 7): in `MdlRefInfo`, nella voce `ent_list(coord_sys)` con `feat_id` 7, e in `GeomDepen`. Non compare in `AllFeatur`. ## 6. Algoritmo, con la prova sul campione 1. Leggere il file come Latin1 (come in `formato-asm-record.md` §2) e ritagliare le sezioni `AllFeatur` e `MdlStatus` con i marcatori `#\n#\n` (§1). 2. Da `AllFeatur`: elenco `(id, tipo, nome-di-default)` in ordine; scartare i record con il pattern interno (§3). 3. Da `MdlStatus`: mappa `id → (nome, icona, prev)` dai record `MTTyped_CreateData` (§5). 4. Per ogni feature restante: nome = nome dello storico se c'è, altrimenti `sect_name`, altrimenti il nome dell'asse in `MdlRefInfo` (solo `PRT_CSYS_DEF`). Se non c'è nessuno dei tre, mostrare "feature tipo N" e non inventare il nome (vedi §7). 5. Ordine: quello di `AllFeatur` (equivalente a seguire `prev_feat_id`, §5). Risultato su `test.prt.1`, confrontato con la schermata del model tree: ``` TEST.PRT RIGHT (1) sect_name TOP (3) sect_name FRONT (5) sect_name PRT_CSYS_DEF (7) MdlRefInfo Sketch 1 (73) storico, 949 dtmsktcurve <- grigio nel tree: nascosto Estrusione 1 (79) storico, 917 protextrude Foro 1 (100) storico, 911 feathole Arrotondamento 1 (125) storico, 913 featround DTM1 (147) storico + sect_name, 923 dtmplane Estrusione 2 (149) storico, 917 protextrude Smusso 1 (188) storico, 914 featchamfer ``` Identico al tree di Creo per ordine, nomi e numero di voci (11, più la radice `TEST.PRT`). I piani interni 74, 80 e 150 sono correttamente assenti. **Non decodificato, e che la schermata mostra:** - **Sketch 1 in grigio** (nascosto/non visualizzato): lo stato di visibilità non l'ho ricavato dal file. Non è in `attributes` di `AllFeatur` in una forma che abbia riconosciuto; probabilmente sta nello stato dei livelli o in `DispCntrl`. Va cercato confrontando due salvataggi dello stesso modello con lo schizzo nascosto/visibile. - **La freccia di espansione** di Estrusione 1 e 2 (le sotto-voci: la sezione dello schizzo interno): i figli di una feature non li ho decodificati. - **Soppressione, feature fuori ordine, pattern, gruppi:** non presenti nel campione, quindi mai osservati (`pat_group_header_id` e `is_header` sono letti e ignorati). ## 7. Dove la decodifica NON regge Sondaggio sui 89 file di `raw/` (livello 2, nessun model tree di riferimento). Per generazione del formato (secondo numero dopo `PART`/`ASSEMBLY`) e modo di conservare `AllFeatur` (§1.2): | Generazione | File | `AllFeatur` | Leggibile oggi | |---|---|---|---| | `2038`, `2063`, `1967` (Creo) | 31 | tipo `9`, in chiaro (3 con sezione vuota) | sì | | `1632` | 4 | tipo `9`, in chiaro | sì (ma con una sola feature, tipo 932: nessun albero reale) | | `1322`, `1375`, `1376` (Wildfire) | 54 | tipo `11` | **no** (§1.3) | I 31 recenti sono quelli con i marcatori di sezione; con la regola di §1.1 diventano leggibili anche i `1632` e si possono ritrovare le sezioni senza marcatori. Dei 31 leggibili, solo **10 hanno record di creazione con nome** in `MdlStatus` (`MTTyped_CreateData`, introdotto con le versioni recenti di Creo): gli altri 21 hanno `AllFeatur` ma **nessun nome** nel file. Fra questi ci sono parti con una vera storia di modellazione (es. `9251200385.prt.3`: schizzo, estrusioni, smusso...). Per loro ordine e tipo si leggono, il nome no, e il tipo non basta a ricostruirlo (§4: estrusione e rivoluzione sono lo stesso tipo, e la numerazione "…1, …2" non è una proprietà dei tipi). **Correzione (§9):** i nomi si possono **calcolare** (famiglia + contatore, §9.1) e riproducono il tree di Creo anche senza lo storico; restano da leggere dallo storico solo i nomi non calcolabili (assi, punti, rivoluzioni). Quanto scritto sopra vale quindi solo per quei nomi. Altre cautele: - Nei `.asm` `AllFeatur` elenca anche i componenti (tipo 1000) ma i nomi di quei componenti non stanno nello storico: il modo giusto di avere i componenti resta `members` (`formato-asm-record.md` §3). - Con più record di creazione per lo stesso `feat_id` (feature rigenerate o modificate) non so quale prevalga: sul campione ce n'è sempre uno solo per feature. - **L'`id` letto da `AllFeatur` non è affidabile fuori dal campione.** Su 11 file con storico (i 10 di `raw/` più `test.prt.1`), in 7 lo storico cita `feat_id` che nel mio elenco di `AllFeatur` non ci sono (es. `4503220100_c03.prt.3`, `9252000507.prt.11`). Nei file dove ho controllato, in `AllFeatur` il record c'è ma il pattern con cui estraggo l'`id` (§2) non lo trova: il layout del record cambia (altro schema, o altri campi prima). Quindi il collegamento `id` → nome di §5 è provato **solo su `test.prt.1`** e va rifatto leggendo il record con il suo schema, non con l'àncora a pattern. - `prev_feat_id` punta a volte a id che non sono in nessuno dei due elenchi (stessi 7 file): stessa causa probabile, non verificata. Per l'ordine ci si fida di `AllFeatur`, non della catena. - Un file su 11 ha due record di creazione con lo stesso `feat_id`; non so quale valga. - La regola del piano interno (§3) è un pattern di byte validato su pochi file recenti. ## 8. Cosa serve per renderlo codice Per portare tutto questo in `PrepStep/` (non fatto): 1. Un `PrtFeatureReader` accanto ad `AsmRecordReader`, che riusi la lettura Latin1 e `AsInt`, con le stesse regole di sicurezza: se `AllFeatur` manca, o i record trovati non tornano con il conteggio dichiarato (`f8 ` dell'array delle feature), lanciare `InvalidDataException` invece di restituire un tree parziale. 2. Verificare i punti aperti di §6 e §7 con **altri model tree reali**, uno per caso: schizzo nascosto/visibile, feature soppressa, feature rinominata a mano, pattern, un file della generazione vecchia. Un campione solo non basta per fidarsi. 3. Per i file senza storico decidere cosa mostrare (§7): è una scelta di prodotto, non tecnica. Quote, coordinate degli schizzi e cosa manca per ricostruire il solido: [`formato-prt-geometria.md`](formato-prt-geometria.md). ## 9. Ricostruire l'albero identico a quello di Creo Verificato su `9239901907.prt.19` (63 record in `AllFeatur`, un albero con gruppo, guscio, sezioni: ~40 voci): l'algoritmo sotto riproduce **voce per voce, nell'ordine e con gli stessi nomi** il model tree mostrato da Creo (RIGHT, TOP, FRONT, PRT_CSYS_DEF, Sketch 1, Estrusione 1, Guscio 1, Sketch 2 ... Estrusione 6, Gruppo VITI con 7 voci dentro, DTM1, DTM2, Sketch 10, Estrusione 10, e le sezioni A, B, C, D). Riproduce anche `test.prt.1` (§6). Lo storico (`MdlStatus`, §5) **non serve per i nomi**: per quel file ne copriva solo 7 su ~40, e coincide al 100% con i nomi generati. ### 9.1 I nomi si calcolano: un contatore per famiglia Il nome di una feature non è scritto nel file (salvo i pochi dello storico): è la **famiglia** più un **contatore** che cresce nell'ordine di `AllFeatur`, contando *tutte* le feature della famiglia, visibili o nascoste: | Tipo (§4) | Famiglia, nome | Nota | |---|---|---| | 949 | `Sketch n` | tutti gli schizzi, anche quelli nascosti | | 917 e 916 | `Estrusione n` | **protrusioni e tagli condividono un unico contatore**: 6 protrusioni e 4 tagli arrivano a "Estrusione 10" | | 914 | `Smusso n` | | | 913 | `Arrotondamento n` | | | 928 | `Guscio n` | scoperto qui: 928 è il guscio | | 911 | `Foro n` | | | 923 non interno | nome nel record (`sect_name`: RIGHT, TOP, FRONT, DTM1...) | | | 979 | `PRT_CSYS_DEF` | | | 1104 | gruppo, vedi §9.2 | | Prova interna: i 7 nomi dello storico di `9239901907` (Foro 1, Sketch 9, Estrusione 8, DTM1, DTM2, Sketch 10, Estrusione 10) coincidono con quelli generati, e fra loro "Sketch 9" e "Estrusione 8" si trovano solo se il contatore conta anche le feature senza nome. ### 9.2 Gruppi: `LOCAL_GROUP`, tipo 1104 Un gruppo è una feature di tipo 1104 in `AllFeatur`. Il suo nome sta in `LargeText`, tabella `names_table`, voce con lo stesso `id` e `type 3`: ``` id àtype  à name VITI ``` e il numero dei membri in `FeatDefs`, record `feat_defs_1104`, campo `index_count` (7 per VITI). I membri sono le **7 feature visibili che seguono l'intestazione** in `AllFeatur`, nello stesso ordine: `Sketch 7`, `Estrusione 7`, `Sketch 8`, `Foro 1`, `Sketch 9`, `Estrusione 8`, `Estrusione 9`. Il nome mostrato è "Gruppo " + nome. Un secondo record 1104 (`COPIED_GROUP`, id 1326) sta in mezzo ai membri: è un marcatore di copia, non una voce dell'albero, e non va mostrato né contato fra i 7. ### 9.3 Le sezioni ("Sezioni" in fondo) Le voci di tipo 1052 in `AllFeatur` sono le sezioni (`Sezioni` → A, B, C, D), **non** si mostrano nel corpo dell'albero ma in una cartella a parte. I nomi stanno nella sezione `Xsections`, lista `mdl_xsec_list`: ogni voce ha un `leader_id` e, subito dopo, il nome (`D`; nelle voci posizionali è ``). Ordinate per id crescente danno A, B, C, D, come in Creo. ### 9.4 L'`id` della feature (correzione di §2) L'ancora che ho dato in §2 per l'`id` (` ë ...`) vale per i file che hanno il primo elemento degli attributi come intero a 4 byte (`eb 04 00 10 01`). In altri (`9252000507.prt.11`) quel campo è `90 01 00` e l'`id` è seguito da quello: l'espressione corretta è `(id | ÷ | ã) (ë | )`. È la causa dei "7 file su 11 con id non letti" del §7, che con questa regola tornano leggibili. ### 9.5 Verifica sul corpus Confronto fra i nomi generati e quelli dello storico, sui file leggibili (29 voci confrontabili): | Esito | Voci | Spiegazione | |---|---|---| | Uguali | 18 | | | Diversi: rivoluzione letta come estrusione | 2 | `Rivoluzione 1` (tipo 917) esce `Estrusione 1`: vedi sotto | | Diversi: assi (`A_3`...) | 1 | nome non calcolato (contatore degli assi con i loro id interni) | | Diversi: piani e sistemi di assi con nome non standard | 8 | `ADTM1`, `ASM_RIGHT`, `CS0`, `DTM2`...: file con un'altra *template*, il nome del piano va letto dal record con più cura (la mia lettura di `sect_name` guarda in avanti e può prendere quello del record successivo) | | File non letti: primo record con layout diverso | 19 di 33 | assiemi e parti senza i campi del primo record come nei campioni | I 58 file Wildfire restano fuori (§1.3). ### 9.6 Cosa non riproduco ancora - **Rivoluzione e estrusione**: stesso tipo (917/916). Nell'unico caso con rivoluzione disponibile (`9252000507`), il primo `type` delle istruzioni di `feat_defs_917` è 5209 (`0x1459`), mentre nelle estrusioni è 1851, 1853 o 1854. È un indizio, **non provato** (un solo esempio). - **Schizzi in grigio** (nascosti): in Creo `Sketch 1-6` e `Sketch 10` sono grigi. Tutti i record di schizzo (tipo 949) di `AllFeatur` hanno gli stessi byte di attributi (eccetto `Sketch 9`, con un flag `0x20` in più che compare anche su `Estrusione 8` e `9`, i membri del gruppo copiato): lo stato "nascosto" non sta lì. Non ho trovato dove sia, e non ho un esempio con uno schizzo *visibile* da confrontare. - **Elementi progetto** (cartella in testa al tree in `9252000507`): corrispondono, probabilmente, alle due voci di tipo 1234 in `AllFeatur`, che però non compaiono in `9239901907`. - **Nomi degli assi** (`A_3`, `A_4`, `A_5`) e dei punti (`PNT0`): dallo storico, non calcolati. - **Foro, gruppo, e figli di una feature**: l'espansione delle feature (la freccia ▸ davanti a `Estrusione n`) non l'ho decodificata.