Skip to content

Fix opening non-ASCII file names with an ASCII locale - #203

Merged
JeromeMartinez merged 3 commits into
MediaArea:masterfrom
sbraz:filename-utf8
Nov 4, 2026
Merged

JeromeMartinez merged 3 commits into
MediaArea:masterfrom
sbraz:filename-utf8

Conversation

@sbraz

@sbraz sbraz commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Hello,

This fixes sbraz/pymediainfo#121.

Before this change, file names were converted with wcstombs(), so under the C locale, which programs get when they never call setlocale(), non-ASCII file names couldn't be opened. This PR uses UTF-8 for file names on macOS and Android, where they are always UTF-8, and on other Unix-like systems when the locale is ASCII. Other locales, such as ISO-8859-1 or EUC-JP, still use wcstombs(). Windows behavior is unchanged.

Tested on Linux, macOS (ARM64 and x86-64) and Windows (x86-64 and x86) by building libmediainfo against this branch and opening café.mkv, Åsnan é 测试.mkv and 🎵.mkv:

Platform Locale Before After
Linux, macOS C can't open opens
Linux, macOS UTF-8 opens opens
Windows C, cp1252 opens opens

On Linux under en_US.ISO-8859-1, a café.mkv with a Latin-1 name opened before and after, but Dir::GetAllFileNames() only listed it after this change.

The macOS and Windows tests ran on GitHub Actions: https://github.com/sbraz/pymediainfo/actions/runs/41442332292

The MediaInfoA_* functions and the CLI, which decodes its arguments with From_Local(), still use the locale. Because of the former, this PR alone doesn't fix MediaArea/MediaInfoLib#2464. @JeromeMartinez, if you agree with these ZenLib changes, would you like me to make similar PRs for the CLI and MediaInfoLib, using FileName_From_Native()?

It may also help with MediaArea/MediaInfo#134 and MediaArea/MediaInfo#349.

@JeromeMartinez

Copy link
Copy Markdown
Member

@JeromeMartinez, if you agree with these ZenLib changes, would you like me to make similar PRs for the CLI and MediaInfoLib, using FileName_From_Native()?

It was always a bit messy there, and if you are motivated to have something more coherent, I am fine with that.

sbraz added a commit to sbraz/MediaInfoLib that referenced this pull request Nov 3, 2026
The MediaInfoA_* and MediaInfoListA_* functions decoded file names with
the locale encoding, so under the C locale, non-ASCII names couldn't be
opened [1]. Decode them with FileName_From_Native(), which uses UTF-8
under an ASCII locale and on macOS and Android, as ZenLib does when
opening files [2].

Other strings, such as option values, still use the locale encoding.

[1] MediaArea#2464
[2] MediaArea/ZenLib#203

Assisted-by: Claude:claude-opus-5-5
sbraz added a commit to sbraz/MediaInfo that referenced this pull request Nov 3, 2026
Command line arguments were decoded with the locale encoding, so under
the C locale, non-ASCII file names couldn't be opened. Decode them with
FileName_From_Native(), which uses UTF-8 under an ASCII locale and on
macOS and Android, as ZenLib does when opening files [1].

The output still uses the locale encoding.

[1] MediaArea/ZenLib#203

Assisted-by: Claude:claude-opus-5-5
@sbraz

sbraz commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! I opened MediaArea/MediaInfoLib#2767 and MediaArea/MediaInfo#1331.

Testing them showed that this PR should be merged together with them. On macOS, the C locale maps bytes 0x80–0xFF to U+0080–U+00FF and back, so the narrow API and the CLI could open files with UTF-8 names before. With this PR alone, these names are encoded to UTF-8 twice and the files can't be opened. With all three PRs, they open on every platform I tested.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

An empty filename conversion can cause the default recursive directory scan to revisit the same directory indefinitely, exhausting the stack or file descriptors.

1 open issue
What changed in this PR

This PR centralizes native filename conversion so ZenLib can access non-ASCII paths under ASCII locales while preserving locale-based conversion for other Unix encodings and leaving Windows behavior unchanged.

Changes:

  • Add filename conversion helpers with UTF-8 handling for macOS, Android, and ASCII Unix locales.
  • Apply the helpers to file operations and metadata queries.
  • Use consistent encoding conversion for directory enumeration and creation.
File Description
Source/​ZenLib/​OS_Utils.h Declare native filename conversion helpers.
Source/​ZenLib/​OS_Utils.cpp Implement platform- and locale-aware filename conversion.
Source/​ZenLib/​File.cpp Apply conversion helpers to file paths.
Source/​ZenLib/​Dir.cpp Apply conversion helpers to directory paths and returned filenames.

Review effort: Balanced

Comment thread Source/ZenLib/Dir.cpp Resolved
sbraz added 2 commits November 3, 2026 13:58
Dir::GetAllFileNames() decoded names with From_UTF8(), which returns an
empty string for names that aren't valid UTF-8, such as Latin-1 names.
The entry then pointed to the directory itself, which was listed again
and again until file descriptors ran out. Skip these entries instead.

Assisted-by: Claude:claude-opus-5-5
File names were converted with wcstombs(), which depends on the
LC_CTYPE locale. Programs that never call setlocale() and macOS apps
launched from the Finder use the C locale, where non-ASCII characters
can't be converted, or become Latin-1 bytes on macOS and FreeBSD. These
files couldn't be opened [1].

On macOS and Android, file names are always UTF-8, so use UTF-8 there.
On other Unix-like systems, keep the locale encoding but use UTF-8 when
the locale is ASCII, as Python does for file names: its UTF-8 Mode is
enabled automatically under the C locale [2]. Decode directory listings
the same way.

[1] sbraz/pymediainfo#121
[2] https://peps.python.org/pep-0540/

Assisted-by: Claude:claude-opus-5-5
FileName_To_Native() and FileName_From_Native() used UTF-8 under an
ASCII locale, but the other conversions kept the locale encoding. Under
the C locale, programs could open files with non-ASCII names but showed
these names with '?', or with Latin-1 bytes on macOS and FreeBSD. On
macOS and FreeBSD, programs decoding their command line arguments with
From_Local() could no longer open files with UTF-8 names, which were
encoded to UTF-8 twice.

Use UTF-8 under an ASCII locale in Ztring::From_Local() and
Ztring::To_Local() instead, so that all conversions agree. File names
still use UTF-8 on macOS and Android whatever the locale, and there,
FileName_From_Native() falls back to the locale encoding for strings
which aren't valid UTF-8, such as arguments typed in a terminal using
another encoding.

Also skip directory entries whose decoded name doesn't give back the
same bytes, such as overlong UTF-8 sequences decoded to "/", since they
can't be opened with this name, and free the glob() results.
@JeromeMartinez
JeromeMartinez merged commit ee5828f into MediaArea:master Nov 4, 2026
15 checks passed
JeromeMartinez added a commit that referenced this pull request Nov 4, 2026
File names and text conversions: follow-up of #203
sbraz added a commit to sbraz/MediaInfo that referenced this pull request Nov 4, 2026
Command line arguments were decoded with the locale encoding, so under
the C locale, non-ASCII file names couldn't be opened. Decode them with
FileName_From_Native(), which uses UTF-8 under an ASCII locale and on
macOS and Android, as ZenLib does when opening files [1].

The output still uses the locale encoding.

[1] MediaArea/ZenLib#203

Assisted-by: Claude:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants