Skip to content

fix(libSceCesCs): terminate and count MBCS string conversions as measured on a PS5 - #10185

Merged
oneandonlydean merged 23 commits into
boykopovar:mainfrom
orezraey:fix/libscecescs-mbcs-strings-measured-ps5
Oct 25, 2026
Merged

oneandonlydean merged 23 commits into
boykopovar:mainfrom
orezraey:fix/libscecescs-mbcs-strings-measured-ps5

Conversation

@orezraey

@orezraey orezraey commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What

The MBCS string conversions (sceCesUtf8StrToMbcsStr, sceCesUcs2StrToMbcsStr, sceCesMbcsStrToUtf8Str, sceCesMbcsStrToUcs2Str and their Get*Len forms) wrote no terminator and set no length on an error. I measured them on a retail PS5 (firmware 13.60) with homebrew probes, from a payload process loading libSceCesCs.sprx, with the Cp1252 and EUC-JP profiles. The sources and console logs are in this gist (pces8, pces9, pces10).

On the console:

  • Terminator. The output always gets a terminating zero, which is not counted. A character is written only if it and the terminator fit. Converting ABC into 3 bytes gives AB, a terminator and 0x805C0031 with lengths 2 and 2. With a capacity of 0, nothing is written.
  • Errors keep what was converted. On an error mid-string, the characters before it stay written, terminated and counted. For example, A, 0x81, B in Cp1252 returns 0x805C0020 with lengths 1 and 1 and the output A, terminator.
  • Source limit 0 reads up to the terminating zero. We converted nothing.
  • Order. The lengths are cleared and a terminator is written first. Then the checks run in this order: context (0x805C0001), source (0x805C0010), output (0x805C0030).
  • Decoding.
    • UTF-8 sources decode as sceCesUtf8ToSbc does: overlong forms and surrogates give 0x805C0015, and a zero byte inside a sequence is an invalid byte.
    • A UTF-16 surrogate gives 0x805C0015.
    • EUC-JP sources decode as sceCesEucJpToUcs2 does, so 8F A2 AF gives 0x805C0014.
  • No JIS X 0212 encoding either. U+02D8, U+0386, U+0402 and U+4E02 give 0x805C0020 with the EUC-JP profile. We encoded them as 0x8F triples.

This PR implements all of the above with one conversion loop shared by the eight functions. sceCesMbcsUcsContextInit with a null profile now returns 0x805C0001 as well, as the console did; before, it stored the null profile.

Not changed, recorded in the debt file. The console encodes U+00A5, U+203E and U+0080–U+009F to EUC-JP bytes where we answer UNASSIGNED_CODE. Its Shift-JIS encoder answers 0x805C0024 for U+0080–U+009F and accepts the JIS forms of a few Microsoft characters. These table choices are a separate change. A zero-filled context converted nothing and returned 0 on the console; here it returns 0x805C0001.

Depends on the two scalar PRs, for decodeScalarUtf8 and decodeEucJpScalar. This branch carries their commits until they merge.

On top of #8967 and #8972. The UTF-16 and UTF-32 string forms from #8972 now run through the same loop, so they stop, terminate and count the same way. sceCesUtf8ToSJis, sceCesUtf8ToEucJp and the GBK and EUC-CN forms from #8976 decode UTF-8 like sceCesUtf8ToSbc. JIS X 0212 is neither decoded nor encoded, as measured, so two guest_ces_japanese checks that expected 0x8FB0A1 for U+4E02 now expect INVALID_ENCODE and UNASSIGNED_CODE.

Tested

Checklist

orezraey and others added 15 commits October 22, 2026 21:58
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r-measured-ps5

# Conflicts:
#	core/libs/prx/libSceCesCs/Export.cpp
#	core/libs/tests/GuestCes.cpp
#	docs/dev/debt/libSceCesCs.md
…F-32 round trip

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-measured-ps5

# Conflicts:
#	core/libs/tests/GuestCes.cpp
#	docs/dev/debt/libSceCesCs.md
…s-mbcs-strings-measured-ps5

# Conflicts:
#	core/libs/tests/GuestCes.cpp
…ured on a PS5

The UTF-16 and UTF-32 string forms and the UTF-8 to Shift-JIS and EUC-JP
calls now share the measured string loop and UTF-8 decoder, and the
Japanese tests expect JIS X 0212 to be neither decoded nor encoded.
sceCesMbcsUcsContextInit rejects a null profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rough the shared loop

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r-measured-ps5

# Conflicts:
#	docs/dev/debt/libSceCesCs.md
…cs-mbcs-strings-measured-ps5

# Conflicts:
#	core/libs/prx/libSceCesCs/Export.cpp

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the MBCS conversion-loop change at head 00b45d4, stacked on #10183 and #10184. The shared loop clears lengths and initializes the terminator before validation, preserves converted prefixes on error, reserves terminator capacity, and handles sourceMax=0 as the measured NUL-terminated mode. UTF-8/EUC-JP/UCS-2 decode paths and the new focused cases align with the described firmware measurements. This exact head is included in the descendant #10186 syntax check; its hosted eligibility, conventions, intake, labels and report checks pass, while product builds are path-skipped. The author reports the ten focused tests passing three consecutive runs on Windows. I could not execute them here because full CMake configuration is blocked by the missing SDL2 development package. The declared dependencies match the branch stack.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 10428 core/libs/prx/libSceCesCs/Export.cpp L27-28, L631-657
core/libs/tests/GuestCesJapanese.cpp L158-163
docs/dev/debt/libSceCesCs.md L12-14, L18-19
PR 10718 core/libs/prx/libSceCesCs/Export.cpp L631-657
core/libs/tests/GuestCesJapanese.cpp L158-163
docs/dev/debt/libSceCesCs.md L12-14
PR 10722 core/libs/prx/libSceCesCs/Export.cpp L631-657
core/libs/tests/GuestCesJapanese.cpp L69, L72-73, L159-163, L173-174, L182-183, L202, L220, L223-224, L234
docs/dev/debt/libSceCesCs.md L18-19
PR 10739 core/libs/tests/GuestCesChinese.cpp L228-231
docs/dev/debt/libSceCesCs.md L17-18
PR 10751 core/libs/prx/libSceCesCs/Export.cpp L27, L572-573

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 9912 core/libs/prx/libSceCesCs/Export.cpp
core/libs/tests/GuestCes.cpp
docs/dev/debt/libSceCesCs.md

@github-actions github-actions Bot added docs prx needs rebase Conflicts with main, rebase needed labels Oct 23, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 23, 2026

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of exact current head e4ed848821e95fb162923e68991d6c32d9d5cfb8. The source/test/debt diff against current main is unchanged by this head's merge-main refresh. Its checklist records the agreed #10183/#10184 prerequisites, and #10186 records #10185 as its prerequisite; #10056 then depends on #10186. Exact-head repository conventions and git diff --check pass, and GCC C++20 strict syntax-only compilation of the CES export passes. Hosted eligibility, conventions, labels and report pass; product test/build jobs are path-skipped. The author reports the focused CES tests passing three runs; no full runtime suite was available locally. Approving this exact head in the agreed stack order.

@oneandonlydean oneandonlydean self-assigned this Oct 23, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@orezraey #9204 and #9210 are landing ahead of this PR and both change libSceCesCs/Export.cpp, so this needs a rebase. Taking either side whole drops behaviour. #9204 adds the strict JIS/SS2/SS3 profiles and the JIS X 0212 reverse cells, and #9210 adds the GB18030 supplementary mappings and encodeUtf16. This PR replaces the profile-aware reverse map and adds convertString. Please keep the strict-profile selection and the GB18030/supplementary paths inside your new helpers, with the measured CP51932 and string-length semantics on top. Then rerun the Japanese, Chinese, Unicode and string guest_ces* tests on Linux and Windows.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
Keep boykopovar#9204's strict JIS X 0208 profiles with their SS2 and SS3 choices inside the new helpers: decodeEucJp sends the measured CP51932 profile to decodeEucJpScalar and the strict profiles to boykopovar#9204's rules, and only the X0208Ss2Ss3 profile encodes JIS X 0212. The EUC-KR, UHC and Big5 UTF-8 forms decode with decodeScalarUtf8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@orezraey

Copy link
Copy Markdown
Contributor Author

Merged main (with #9204) in cce3beb. A new decodeEucJp keeps the profile selection: the measured CP51932 profile goes to decodeEucJpScalar, and the strict X0208, X0208Ss2 and X0208Ss2Ss3 profiles keep #9204's SS2/SS3 and strict-table rules, both for the string loop and for sceCesEucJpToUcs2/sceCesEucJpToUtf8. The reverse map keeps #9204's strict and supplementary cells, but only X0208Ss2Ss3 encodes JIS X 0212, because CP51932 answered 0x805C0020 for those code points on the console. Shift-JIS still never encodes a supplementary cell, and the new EUC-KR, UHC and Big5 UTF-8 forms decode with decodeScalarUtf8 like the other scalar forms. Three tests from main changed to this PR's semantics: the strict-profile sceCesEucJpToUcs2 failures now expect the cleared output and the console-style length, the EUC-KR overlong case expects 0x805C0015, and the UCS-2 string comparison in guest_ces_dbcs leaves room for the terminator. All 14 guest_ces* tests pass three runs in a row on Windows; I have no Linux machine for this, so Linux is covered by CI. #9210 has not landed yet; I will fold its GB18030 and encodeUtf16 paths into convertString when it does.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@orezraey The #9204 resolution preserves strict JIS and the measured CP51932 split. Please retain the #9210 prerequisite: after it lands, fold supplementary GB18030 decode/encode and encodeUtf16 into Ces.cpp’s convertString without losing that split, then rerun all 14 guest_ces cases on Linux and Windows and report the final head. The current branch still lacks that integration, so the earlier request is only partly resolved.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@orezraey

orezraey commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Agreed, #9210 stays the prerequisite, and it is still open. Once it lands I will fold its supplementary GB18030 decode/encode and encodeUtf16 into convertString in Ces.cpp keeping the strict JIS and CP51932 split, then report all 14 guest_ces cases on Linux and Windows with the final head. The AI-assisted line now reads yes.

orezraey and others added 4 commits October 23, 2026 19:03
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The strict JIS X 0208 EUC-JP profiles from main keep their decodeMbcs
path in sceCesEucJpToUcs2 and sceCesEucJpToUtf8; the measured scalar
decoder applies to the CP51932 profile it was measured with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…trings-measured-ps5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rings-measured-ps5

Brings in main with boykopovar#9210. The MBCS string forms keep convertString
and now encode UTF-16 with encodeUtf16, so GB 18030 supplementary
characters become surrogate pairs and UCS-2 answers UNASSIGNED_CODE.
The GB 18030 string test checks the short-buffer error in its own
buffer, since a failed conversion now terminates the output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@orezraey

Copy link
Copy Markdown
Contributor Author

#9210 has landed, so this branch now merges #10183 and #10184 refreshed on main (head b51910b). The MBCS string forms keep convertString: the UTF-16 forms encode with #9210's encodeUtf16, so GB 18030 supplementary characters become surrogate pairs, and UCS-2 answers UNASSIGNED_CODE for them. #9210's GB 18030 string test now checks the short-buffer error in its own buffer, since a failed conversion terminates its output here. All 14 guest_ces* tests pass three runs in a row on Windows (MinGW GCC 15.2) and Linux (WSL, GCC) at b51910b.

@orezraey

Copy link
Copy Markdown
Contributor Author

@rooklz: #9175, #10426, #10430 and #10431 change the same lines as this PR in core/libs/prx/libSceCesCs/Export.cpp and docs/dev/debt/libSceCesCs.md (git merge-tree of both heads over current main conflicts there). I propose they land first; I will then merge main into this branch, keeping both sides' behaviour, and rerun its tests. Depends on now lists them (merge order only).

@orezraey

Copy link
Copy Markdown
Contributor Author

@rooklz #10718 and this PR both rewrite the EUC-JP decoder in core/libs/prx/libSceCesCs/Export.cpp (this PR moves it into decodeEucJp, #10718 changes its strict JIS X 0208 lookup) and the EUC-JP and strict-profile entries of docs/dev/debt/libSceCesCs.md. The changes do not contradict each other. I suggest #10718 lands first; this PR will then be refreshed to keep #10718's strict-profile tables inside decodeEucJp and its debt wording, with this PR's rules unchanged. Separately, #10706 removes the local test declarations this PR adds to core/libs/tests/GuestCes.cpp; this PR will be refreshed to use its headers if it lands first. I added both to Depends on (merge order only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@oneandonlydean
oneandonlydean merged commit 471e062 into boykopovar:main Oct 25, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants