83 lines
4.6 KiB
Markdown
83 lines
4.6 KiB
Markdown
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
|
|
|
|
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md` din acest folder) — capcana
|
|
ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, nu de un proiect anume.
|
|
|
|
Descoperit de 2 ori în aceeași sesiune (2026-07-10, în ROAAUTO): odată în
|
|
`COMUN/clase/cmd_butoane.vc2` (clasa `cmd_select_adv`), odată în `Clase/ofundal_dev.vc2`
|
|
(meniul principal) — de fiecare dată un agent anterior a editat text-cache-ul cu un tool care
|
|
nu scrie cp1252 nativ, și a corupt TOATE caracterele cu diacritice din fișier, nu doar linia
|
|
pe care voia s-o schimbe.
|
|
|
|
## De ce se întâmplă
|
|
|
|
Fișierele `.sc2`/`.vc2` generate de FoxBin2Prg sunt **cp1252 (Windows-1252)**, nu UTF-8
|
|
(vezi antetul fiecărui fișier: `CPID="1252"`). Dacă un editor/tool citește fișierul ca UTF-8
|
|
(sau alt encoding), fiecare byte >= 0x80 (diacritic) devine invalid ca secvență UTF-8 și e
|
|
înlocuit cu caracterul de replacement U+FFFD. Dacă apoi tool-ul **salvează rezultatul tot ca
|
|
UTF-8**, acel U+FFFD e scris ca 3 octeți UTF-8 (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca
|
|
cp1252 (cum face FoxBin2Prg la write-back), apar ca `�`. Rezultatul: caracterul original e
|
|
**ireversibil pierdut** (nu mai există în fișier sub nicio formă) — recuperabil DOAR din altă
|
|
sursă (git history, backup).
|
|
|
|
Codebase-ul ROA folosește un hack vechi de "reciclare" a unor caractere cp1252 needependente
|
|
de Ș/ă/ț (care nu au echivalent direct în cp1252) pentru diacritice românești:
|
|
|
|
| Literă românească | Caracter folosit (cp1252) | Byte |
|
|
|---|---|---|
|
|
| ă | ã (a-tilde) | `0xE3` |
|
|
| Ă | Ã | `0xC3` |
|
|
| ț | þ (thorn minuscul) | `0xFE` |
|
|
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
|
|
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
|
|
| î, â | î, â (existente nativ în cp1252) | `0xEE`, `0xE2` |
|
|
|
|
Aceste caractere par "gunoi"/typo la prima vedere într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) —
|
|
**sunt corecte, nu le "corecta" fără să verifici encoding-ul.**
|
|
|
|
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
|
|
|
|
```powershell
|
|
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
|
|
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
|
|
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
|
|
```
|
|
|
|
Dacă apare `�` (sau `$text` conține U+FFFD) în output — fișierul are corupere de encoding.
|
|
|
|
## Cum se repară
|
|
|
|
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul
|
|
curent.
|
|
2. Dacă fișierul e sub control de versiune (git) și corupera s-a întâmplat **într-o sesiune
|
|
anterioară necomisă** (deci HEAD-ul git încă are versiunea curată): recuperează originalul
|
|
convertind binarul din HEAD în text și comparând:
|
|
```bash
|
|
git show HEAD:<cale>.vcx > /tmp/head.vcx
|
|
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
|
|
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
|
|
```
|
|
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
|
|
linie (PowerShell, nu `diff` direct — `diff`/Bash nu decodează cp1252 corect pentru afișare,
|
|
deși detectează totuși diferența de octeți).
|
|
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), și reaplică DOAR
|
|
modificările intenționate din sesiunea curentă peste ea (nu invers — nu încerca să "cârpești"
|
|
fișierul corupt caracter cu caracter, e mai sigur să repornești de la baza curată).
|
|
4. Scrie rezultatul înapoi ca bytes cp1252 (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`),
|
|
NU ca string UTF-8/`Out-File` implicit (care scrie UTF-8 sau UTF-16 după caz).
|
|
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
|
|
|
|
## Cum se evită pe viitor
|
|
|
|
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
|
|
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă a
|
|
fișierului trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând
|
|
UTF-8 implicit. Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul
|
|
păstrează restul fișierului byte-identic (nu rescrie tot fișierul reîncodat).
|
|
|
|
## Vezi și
|
|
|
|
`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează deja riscul ("Headerul
|
|
CPID="1252" poate minți...") pe scurt; acest fișier e detalierea completă (tabel de caractere,
|
|
pași de recuperare din git).
|