Files
comun/docs/conventie_encoding_cp1252.md

4.6 KiB

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

$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:
    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).