Skip to content

fix(text): decode Latin-1 and other single-byte txt files instead of GB18030 - #326

Closed
4gray wants to merge 1 commit into
flyfish-dev:mainfrom
4gray:fix/text-single-byte-encodings-20260925
Closed

4gray wants to merge 1 commit into
flyfish-dev:mainfrom
4gray:fix/text-single-byte-encodings-20260925

Conversation

@4gray

@4gray 4gray commented Sep 25, 2026

Copy link
Copy Markdown

Summary

  • options.text.encoding: 'auto' resolved every buffer that is not UTF-8 or UTF-16 to GB18030, so an ISO-8859-1 / Windows-1252 txt file rendered Saarbrücken as Saarbr點ken. The union offered no single-byte encoding, so nothing could correct it.
  • Add iso-8859-1, iso-8859-2, iso-8859-15, windows-1250, windows-1251, and windows-1252 to text.encoding, with common aliases such as latin1, cp1252, and cp1251.
  • Add options.text.fallbackEncoding, the decoder auto uses for bytes that are not valid UTF-8. It defaults to gb18030, so existing GBK files render exactly as before. Single-byte text is structurally valid GB18030, so it cannot be detected from the bytes; the fallback is an explicit option, not a heuristic.
  • Thread the fallback through the code, Markdown, HTML source, XML, patch, and virtual large-text paths. The large-text renderer now treats single-byte encodings as one byte per character when slicing long lines and when mapping search matches to byte offsets; it previously reused the UTF-8 continuation-byte alignment, which skipped 0x80–0xBF bytes at segment starts.
  • resolveFileViewerTextEncoding and decodeFileViewerTextBuffer take an optional third fallbackEncoding argument; isSingleByteFileViewerTextEncoding and DEFAULT_FILE_VIEWER_TEXT_FALLBACK_ENCODING are exported. Download still returns the original bytes.

Related issue

N/A: the bug report was received outside GitHub (renderer-text 2.3.0 / core 3.1.2, Latin-1 umlauts decoded as GB18030); the reporter's reproduction is committed as test/fixtures/text-encoding/latin1-umlauts.txt and reproduced from the library decode path on main.

Change classification

  • User-visible UI or rendering change
  • Non-visual change
  • File-format or renderer behavior
  • Public API, package, Worker, WASM, or deployment-path change

Verification

Check Result
pnpm install --frozen-lockfile Pass
pnpm exec vitest run test/text-single-byte-encodings.spec.ts (9 tests: resolver, aliases, UTF-8/BOM/UTF-16 precedence, jsdom virtual large-text segments and search) Pass
pnpm exec vitest run test/core-options.spec.ts test/html-preview.spec.ts test/text-single-byte-encodings.spec.ts (17 tests) Pass
pnpm type-check:core Pass
pnpm --filter @file-viewer/renderer-text type-check Pass
pnpm type-check Pass after pnpm --filter @file-viewer/asset-installer build; on a cold checkout packages/tools/assets-standard fails first because the unbuilt @file-viewer/asset-installer workspace package is missing, which is unrelated to this change
pnpm build:core Pass
pnpm --filter @file-viewer/renderer-text build (tsc plus 12 node tests) Pass
pnpm docs:build Pass
Mutation check: with the two single-byte branches in largeText.ts disabled, the segment-slicing and search tests fail (' ' instead of «»…, 138 matches instead of 200) Pass

Sample / fixture evidence

  • Repository fixtures: test/fixtures/text-encoding/latin1-umlauts.txt (ISO-8859-1, the reporter's sentences) and test/fixtures/text-encoding/windows-1251-cyrillic.txt (Windows-1251), with a README that records the iconv commands used to generate them. Both are original text written for this repository.
  • The Vitest suite also builds a 3000-byte «» line in memory so segment boundaries land on bytes that look like UTF-8 continuation bytes.

Visual evidence

  • Before / After (same viewport, real renderText from @file-viewer/renderer-text on latin1-umlauts.txt in Chrome):

Latin-1 txt before and after the fallback option

Left: default auto still shows Saarbr點ken (unchanged default). Right: text.fallbackEncoding: 'windows-1252' shows Saarbrücken, Fußgänger, Nächste, öffnet, Büro, Nähe.

Risk and compatibility

  • Affected packages/formats: @file-viewer/core (FileViewerTextOptions, text encoding resolver, new exports), @file-viewer/renderer-text (txt/code, Markdown, HTML source, XML, patch, virtual large text). CSV / TSV keep their separate spreadsheet.textEncoding union and are unchanged.
  • Compatibility or migration risk: fully additive. The default fallback stays gb18030, the new function parameters are optional with the old default, and the existing union members keep their meaning. Browsers decode the iso-8859-1 label with the windows-1252 table per the WHATWG Encoding Standard, which is documented. Component wrappers pass options.text through untouched, so no wrapper changes are needed.
  • Rollback: revert the single commit; no data, asset, or API migration is involved.

Checklist

  • I added or updated focused automated coverage, or explained why it is not needed.
  • I updated user-facing documentation or release notes when behavior or API changed, or marked them not applicable.
  • I verified offline/private-deployment paths when changing Worker, WASM, fonts, vendor assets, or URLs.
  • I did not commit secrets, customer files, private samples, generated caches, or unrelated changes.

🤖 Generated with Claude Code

@4gray
4gray force-pushed the fix/text-single-byte-encodings-20260925 branch from 02cd842 to 72d0cfe Compare September 25, 2026 20:27
wybaby168 added a commit that referenced this pull request Oct 8, 2026
Selectively adapt PR #326 without importing its historical dependency or
Markdown implementation. Preserve BOM/UTF-16/strict UTF-8 auto precedence
and the default GB18030 fallback; expose six explicit single-byte labels
and text.fallbackEncoding throughout current text rendering, including LRC.

Use single-byte offsets for virtual line segments and search. Add charset,
public type, precedence, exact-offset and real-browser regression gates to
the standard test chain, retaining browser artifacts in Public CI.

Validated locally: 53 focused tests, 35 text package tests, core and all 34
renderer builds/type-checks, governance, docs, browser fixtures and bundle.
Chromium/WebKit execution is pending on GitHub-hosted CI; local browser
launch was not attempted. No dependency, release or compatibility-floor change.

Co-authored-by: 4gray <fourgray@proton.me>

Prepared as local commit 1809ec12042523f0c7158263c6dab39150ab01c5; published through the authorized connector with identical tree ecabf9c.
…GB18030

`text.encoding: 'auto'` sent every buffer that is not UTF-8 or UTF-16 to
GB18030, so ISO-8859-1 / Windows-1252 files rendered `Saarbrücken` as
`Saarbr點ken`, and the union had no single-byte encoding to correct it.

- Add iso-8859-1, iso-8859-2, iso-8859-15, windows-1250, windows-1251 and
  windows-1252 to `text.encoding`, with common aliases.
- Add `text.fallbackEncoding` for the non-UTF-8 case. It defaults to
  gb18030 so existing GBK files are unchanged; single-byte text is valid
  GB18030 structurally and cannot be detected from the bytes.
- Pass the fallback through code, Markdown, HTML source, XML, patch and
  the virtual large-text path, which now slices long lines and maps
  search matches one byte per character for single-byte encodings.
- Export `isSingleByteFileViewerTextEncoding` and
  `DEFAULT_FILE_VIEWER_TEXT_FALLBACK_ENCODING`; document both options.
- Add Latin-1 and Windows-1251 fixtures and a Vitest suite covering the
  resolver and the jsdom large-text renderer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@4gray
4gray force-pushed the fix/text-single-byte-encodings-20260925 branch from 72d0cfe to b957c2b Compare October 8, 2026 06:36
wybaby168 added a commit that referenced this pull request Oct 9, 2026
* fix: restore intermediate stabilization contracts

Combine current-base PRs #348, #346, #349 and #347 and preserve newer main changes while restoring reviewed renderer and package boundaries.

Prepared and validated by Codex <codex@openai.com> in an independent cloud workspace. Local candidate: 7f478f7e0ea01aa9a596a2cc7c054913fe46b892. Exact validated tree: 3524dfa. Connector publication controls remote author metadata.

No npm release or compatibility-floor change.

* fix(docs): update Next security patch cohort

Pin Next and its matching env/SWC cohort to16.3.8 to resolve six current docs-site advisories. Preserve unrelated dependencies and compatibility floors.

Validated by Codex in the independent cloud: frozen install, full and production official audits, docs build/type-check, cohort tests and governance. Existing ignored Vue2 low finding remains explicit.

Local validated commit accf4a6e01a818bb75de1d43666ca30b76c2a09c; exact tree285cc92f0dc18b7aa5abc7ab10fce451a8ca616b. Connector controls remote author metadata.

* fix(ci): install required CJK vertical fonts

The actual Chromium font-table gate reproduced zero-height vertical glyphs from WenQuanYi. Install the reviewed Noto CJK prerequisite and retain its physical font cohort as evidence; keep all glyph bounds and advance assertions unchanged.

Local workflow formatting/governance passed. Original failed pixels and geometry retained from run37718395780. Local commit249c3700c91b71693b0e8b9a70c1658e4aaa715f; exact tree320792ed4bcbfbf09ea9992d76b61cbb605a9679. No renderer/runtime source change.

* fix(text): adapt single-byte encoding support to current renderers

Selectively adapt PR #326 without importing its historical dependency or
Markdown implementation. Preserve BOM/UTF-16/strict UTF-8 auto precedence
and the default GB18030 fallback; expose six explicit single-byte labels
and text.fallbackEncoding throughout current text rendering, including LRC.

Use single-byte offsets for virtual line segments and search. Add charset,
public type, precedence, exact-offset and real-browser regression gates to
the standard test chain, retaining browser artifacts in Public CI.

Validated locally: 53 focused tests, 35 text package tests, core and all 34
renderer builds/type-checks, governance, docs, browser fixtures and bundle.
Chromium/WebKit execution is pending on GitHub-hosted CI; local browser
launch was not attempted. No dependency, release or compatibility-floor change.

Co-authored-by: 4gray <fourgray@proton.me>

Prepared as local commit 1809ec12042523f0c7158263c6dab39150ab01c5; published through the authorized connector with identical tree ecabf9c.

* docs(dicom): explain application installation policy

Document the application-owned dependency overrides, current default versus constrained audit results, existing transitive Node requirement, CLI Full selection and workspace license-snapshot boundary. Link both installation guides to the shipped policy.

Six Markdown files only; runtime, package dependencies, engines and workflows are unchanged. Validation: JSON examples and links, release facts, 114-page documentation production build, and final wording diff checks. Prepared and reviewed from local Codex commit 892b058791a0c3493d763e85c8550c1793985f19; remote tree is identical.

* test(release): verify packed DICOM browsers and normal DOCX migration

Add isolated packed DICOM browser evidence with contamination controls and repair transactional preparation for an ordinary versioned DOCX dependency. Preserve rendering assertions and verify registry package integrity after migration.

Locally validated source tree: 0fe8d63
Local source commit: 303dfe3d780e8e1beb10af78feef4ec4726c6ecf

* test(dicom): retain the asserted browser pixel sample

Keep the exact measurement that satisfied the rendering poll and independently enforce the retained report thresholds. Add negative controls for an intervening blank read and blank retained evidence while preserving the original hosted discrepancy.

Validated source tree: b506193
Local source commit: cd3fcf5cdd7f97d609064738b9dbf0195ce508d4

* Adopt published DOCX and verify browser runtime and full asset delivery

Use ordinary published DOCX 0.3.34 and remove its transitional patch. Bundle DICOM and Mermaid runtime inputs with exact license and file identities; verify cold installed consumers, rendered screenshots, compressed DICOM syntaxes, visible mathematics, and cleanup in Chromium and WebKit.

Retain the complete Full renderer set while using exact-version CAD and drawing asset dependencies to meet the CDN unpacked-size limit. Validate complete offline copying and actual DWG/Draw.io rendering. Add independent Linux browser evidence gates and project all licensed DICOM test fixtures.

This is a source review candidate. Aggregate versions remain unfrozen, Linux validation is pending, and the traditional PPT publisher binding is unresolved.

Source commit: 8d6531781b5d193c84fd94008bc462a755346f44

* Build capability dependencies before their renderer consumers

Schedule renderer and capability workspaces together through pnpm's dependency order instead of building all renderers before capabilities. A clean drawing build now waits for the Mermaid engine and its declarations. Remove the redundant later capability batch from the root build.

Validation: a fresh isolated checkout with independent frozen dependencies and empty affected dist/build-info directories passed the normal root build and standalone type checks. Text completed before Mermaid, and Mermaid completed before drawing started. All 17 DICOM and 104 Mermaid output files match the passed browser evidence byte-for-byte; 11 projection checks and two clean-build contracts passed.

Source commit: 7f6e90984f04b76aa95af92b5c6e4f72440064f3
@wybaby168

Copy link
Copy Markdown
Member

Thanks @4gray. The complete change at b957c2be56e753a05889fbb3828e950cc4277d1d has been compared against main fc2a7487dfc1ba26a3c929509df463e9cc3256c3. The public decoder/export APIs, fallback forwarding, single-byte segment/search handling, binary fixtures and original regression cases are preserved in the adapted implementation. main also retains later Markdown behavior and adds charset, BOM/UTF-16 and exact byte-offset coverage.

#360 preserves your original 31,501-byte before/after image without modification, under docs/regressions/text-single-byte-encodings/original-before-after.png, with your attribution and original commit recorded in the regression documentation. The complete main CI has passed, including the actual text regression gates. Closing as fully incorporated; this does not request deletion of your fork branch or dismiss any historical review.

@wybaby168 wybaby168 closed this Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants