Skip to content

Add GB2312 encoding, and build both encoding lists from one source - #689

Merged
Hirogen merged 2 commits into
Developmentfrom
feature/gb2312-encoding
Jul 30, 2026
Merged

Add GB2312 encoding, and build both encoding lists from one source#689
Hirogen merged 2 commits into
Developmentfrom
feature/gb2312-encoding

Conversation

@Hirogen

@Hirogen Hirogen commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Closes #688.

What was reported

from 1.21, it has two utf-8 encoding, but i need gb2312, thanks!

Both halves turned out to be real.

GB2312 was missing. It is now offered as the Preferences default encoding and as a row in View → Encoding.

The "two utf-8 encoding" reproduced. LogTabWindow's constructor overwrote each encoding row's label with Encoding.<X>.HeaderName, after the localized resource labels had been applied. Encoding.Default is UTF-8 on .NET, so the "ANSI" row rendered as utf-8 directly above the "UTF8" row, which rendered as utf-8 too — two rows, same label, same encoding. The ANSI row is dropped (the Preferences combo lost the identical duplicate in #673, for the same reason) and the HeaderName overwrite with it.

A third defect fell out while pinning the above: check state was matched by runtime type and equality, testing Equals(Encoding.Default) before is UTF8Encoding. Clicking "UTF8" applies UTF-8 without a BOM, which compares equal to Encoding.Default — so the checkmark landed on the ANSI row.

One offered-encoding list

The Preferences combo and the encoding menu each carried their own list, and they had drifted: the menu lacked windows-1250 and windows-1252, and carried the ANSI row Preferences did not. Adding an encoding meant editing both, plus a third place — the lookup mapping a file's encoding back onto a menu row.

EncodingRegistry.OfferedEncodings is now the one list, documenting the invariants both UIs depend on (resolvable by its own header name, no two entries sharing a code page, append rather than sort). Adding an encoding is a one-line change there.

Menu rows are built from it at runtime by EncodingMenuBuilder instead of being declared one-by-one in the designer. Each row carries the Encoding it stands for in its Tag, so the click handler applies whatever the clicked row carries (one handler, was five) and the check-state lookup compares against it (was a cascade naming every encoding, plus a field per row). Rows are labelled with their header name — the same text the combo shows — which retires five resource keys across en/de/zh-CN that were dead anyway, overwritten before anyone saw them.

A bug GB2312 exposed

GetPosIncPrecomputed credited every encoding that is not UTF-8 or UTF-16 with one byte per character. That is the step the legacy and XML readers advance their byte position by. GB2312 is the first offered encoding that is neither single-byte nor Unicode (one byte per ASCII character, two per Chinese one), so the position drifted on the first Chinese character and every later line began at the wrong offset — picking GB2312 with ReaderType.Legacy would have produced a garbled file. The step is now keyed on Encoding.IsSingleByte, with 0 ("measure the character") covering the variable-width case.

Behaviour changes worth knowing

  • The ANSI row is gone. Functionally lossless: it applied Encoding.Default, which on .NET is UTF-8 without a BOM — byte-identical to what the surviving UTF-8 row applies.
  • The menu now also offers windows-1250, windows-1252 and gb2312, so a Preferences default of windows-1252 finally shows a checkmark.
  • Menu rows are labelled us-ascii / iso-8859-1 / utf-8 / utf-16 / windows-1250 / windows-1252 / gb2312 instead of ASCII / ANSI / ISO-8859-1 / UTF8 / Unicode, matching the Preferences combo.
  • A file read with an encoding the menu does not offer now leaves every row unchecked. Previously a UTF-16BE file checked "Unicode", but clicking that row applies UTF-16LE — the checkmark was lying.

Testing

1557 tests pass, build clean with no new warnings. Tests were written red-first at each layer the choice passes through: the offered list, menu check state, the settings JSON and .lxp round trips, and the reader stack — where the direct reader's byte positions are asserted against the system reader on mixed ASCII/Chinese lines, and the legacy reader's per-line positions against GetByteCount. Both position tests were confirmed to fail without the GetPosIncPrecomputed fix.

The list invariants are asserted once against the registry rather than per dialog, and the controller's menu fixture is filled by the real builder, so it cannot describe a menu the application does not build.

Note: code page 936 on Windows is really GBK, a GB2312 superset — it decodes strictly more than requested, so nothing is at risk.

BRUNER Patrick added 2 commits July 30, 2026 09:49
Closes #688.

GB2312 (code page 936) is now offered both as the Preferences default
encoding and as a row in View > Encoding, so a simplified-Chinese log
can be read without relying on the machine default.

The issue also reported "two utf-8 encoding". The encoding menu built
its row labels from Encoding.<X>.HeaderName in the constructor, after
the localized resource labels had been applied. Encoding.Default is
UTF-8 on .NET, so the "ANSI" row rendered as "utf-8" next to the "UTF8"
row, which rendered as "utf-8" as well - two rows applying the same
encoding under the same name. The ANSI row is dropped (the Preferences
combo lost the same duplicate in #673, for the same reason) and the
HeaderName overwrite with it, so the remaining rows keep their
translated labels.

Row check state is now matched by code page rather than by runtime type
and equality. That ordering had a defect of its own: clicking UTF8
applies UTF-8 without a BOM, which compares equal to Encoding.Default,
so the checkmark landed on the ANSI row instead.

Pinned by tests at every layer the choice passes through: the offered
list, the menu check state, the settings JSON and .lxp round trips, the
reader stack (GB2312 is the first offered encoding that is neither
single-byte nor Unicode, so the direct reader's byte-position tracking
is asserted against the system reader on mixed ASCII/Chinese lines).
The Preferences default-encoding combo box and the View > Encoding menu
each carried their own list of encodings, and they had drifted: the menu
lacked windows-1250 and windows-1252, and carried an "ANSI" row that the
combo did not. Adding GB2312 for #688 meant editing both, plus a third
place - the check-state lookup that maps the encoding a file is read
with back onto a menu row.

EncodingRegistry.OfferedEncodings is now the one list, and it documents
the invariants both UIs depend on (resolvable by its own header name, no
two entries sharing a code page, append rather than sort). Adding an
encoding is a one-line change there.

The menu rows are built from it at runtime by EncodingMenuBuilder rather
than declared one by one in the designer. Each row carries the Encoding
it stands for in its Tag, so the click handler applies whatever the
clicked row carries (one handler, was five) and the check-state lookup
compares against it (was a cascade naming every encoding). Rows are
labelled with their header name, the same text the combo box shows,
which retires five resource keys that were dead anyway - the constructor
overwrote them before anyone saw them.

Also fixes what GB2312 exposed in the legacy and XML readers, which
advance their position per character by a per-encoding step:
GetPosIncPrecomputed credited every encoding that is not UTF-8 or UTF-16
with one byte per character. GB2312 is the first offered encoding that
is neither single-byte nor Unicode, so the position drifted on the first
Chinese character and every later line began at the wrong offset. The
step is now keyed on Encoding.IsSingleByte, and 0 ("measure the
character") covers the variable-width case.

Test coverage follows the seam: the list invariants are asserted once
against the registry instead of per dialog, and the menu fixture is
filled by the real builder, so it can no longer describe a menu the
application does not build.
Comment on lines +35 to +49
foreach (var encoding in EncodingRegistry.OfferedEncodings)
{
var row = new ToolStripMenuItem(encoding.HeaderName)
{
Name = RowName(encoding),
Tag = encoding,
// Carried over from the designer-declared rows, which set both on every encoding row.
BackColor = SystemColors.Control,
ForeColor = SystemColors.ControlDarkDark
};

row.Click += onRowClick;

_ = encodingMenu.DropDownItems.Add(row);
}
@Hirogen
Hirogen merged commit 5cb65fe into Development Jul 30, 2026
3 checks passed
@Hirogen
Hirogen deleted the feature/gb2312-encoding branch July 30, 2026 09:57
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.

Request to support GB2312 encoding

1 participant