Replies: 6 comments 23 replies
-
|
@WaldemarH this may be an ignorant C++ question but I feel like there has to be some String library out there that already handles all this? We can't be the first app to run into this issue right? |
Beta Was this translation helpful? Give feedback.
-
|
What is then the issue with all of that? I have been following the whole UTF discussion with Salamander for over 10 years and in the meantime, other similiar applications (that are even older, like Total Commander) don't have this issue. Instead, what I have gathered around all of the iterations of Salamander, there always have been bandaids around the issues, written some custom support slapped onto parts of Salamander. Why doesn't Salamander does replace the old ANSI encoding core (I'll just call it in lack of better definition) with a proper, portable (for the future...) one that sits on top of standard Windows functions, encapsulates them and provide for the rest of the application an uniform interface? I won't even start at the portability of the application for other operating systems, where I sorely miss Salamander, but have arranged myself begrudgingly using KDE Dolphin (and midnight commander). Come to it, it smells like at times, like the Python 2 and 3 situation, where the latter evolution of Python fundamentally tackled that and solved it mostly? |
Beta Was this translation helpful? Give feedback.
-
|
Thanks to @WaldemarH for the thorough exploration of the issue and for starting work on the UTF-16 conversion. He came to the same conclusion as Petr and I did: we need to encapsulate all operations on path buffers into a dedicated class. The old Salamander code is very unfortunate in this regard - path operations are scattered throughout the codebase, implemented differently in each place depending on what was convenient at the time. If we want to switch to UTF-16 (or UTF-8), we must handle the situation where a single character does not always map back to exactly 2 (or 1) bytes in the buffer, exactly as WaldemarH points out. Without encapsulating path operations, we can never be sure that somewhere in the code there isn’t pointer arithmetic accessing [pos - 1] in the buffer. If we wanted to ignore this risk (which we believe is dangerous and certainly not what Salamander users would expect in terms of robustness and code quality), one option would be to simply triple the size of all MAX_PATH buffers, let the system return UTF-8 instead of ANSI strings, and… pray. However, the UTF-8 solution comes with a problem that UTF-16 paths do not suffer from. Internally, all names on file system are just sequences of WORDs. They are not necessarily valid UTF-16 strings. On disk, it is easy to encounter WORD sequences that are invalid in sense of UTF-16 encoding. When we request UTF-8, Windows performs a UTF-16 -> UTF-8 conversion. The behavior on invalid UTF-16 sequences depends on the conversion settings (we can check in the debugger what parameters Windows 11 currently uses, but this provides no guarantees for the future). Once the conversion to UTF-8 has happened "somehow", Salamander may perform an operation on the path - for example, appending a backslash and a filename. The operating system will then convert the string back UTF-8 -> UTF-16. At this point, the original directory name may differ from the new one. In short, the UTF-8 approach carries all the problems ( https://github.com/KRtkovo-eu-AI/salamander/issues?q=is%3Aissue%20state%3Aopen%20UTF8 ) we need to solve for UTF-16, and adds this extra one on top. |
Beta Was this translation helpful? Give feedback.
-
|
To demonstrate the described disadvantage of the UTF-8 approach compared to UTF-16, I prepared a sample that lets you test file and directory names that are invalid from the perspective of UTF-16 encoding. It’s available at tools\utfnames\utfnames.vcxproj. Example usage: This creates a directory name that can be opened by UTF-16 applications (for example, Windows Explorer, Notepad, …), but will not be accessible to UTF-8 applications. |
Beta Was this translation helpful? Give feedback.
-
|
Just asking a dumb question: Why do other file managers on Windows don't have any issues on that and that since decades? Also you will be cornering yourself all the years that is being discussed, but no proper action taken. My recommendation (I'm not really a developer, I let Claude look at your source and asked it how to solve it): Go Direct to UTF-16 - Skip TCHAR Altogether
Implement a SalString wrapper for gradual migration Convert file operations to UTF-16 systematically (one module at a time)
Add UTF-8 manifest support for modern Windows versions
Create plugin compatibility layer that converts between UTF-8/UTF-16 as needed
This is actually simpler than UTF-16 for text processing Ship incremental updates rather than waiting for complete rewrite
|
Beta Was this translation helpful? Give feedback.
-
|
I had assumed that the request for UNICODE support was so that the Internal Viewer would function better. I hadn't considered anything besides that. Whenever I needed to view something that Salamander didn't support, I'd open it in Emacs. |
Beta Was this translation helpful? Give feedback.






Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi guys,
I've been reading and reading and reading,..... on what to do with this whole UNICODE thingy and for us to properly support UNICODE it's not just enough to use TCHAR. Unfortunately even UTF-16 is a multi-code-unit encoding.
Currently Salamander uses locale which uses whole unsinged 8 bit as a representation of the character, but if we want to make it a real 'full blown UNICODE' there is no other way then to make it multi-code-unit encoding aware.
And as soon as you go down that rabbit hole we'll have to start using string class that processes code-units and not chars.
A simple At(0) would return a View that could be 1 to 2/4 code-units long (depending on the char type used).
Now with W10 some UTF-8 support started to be present, but I'll assume that this is really just a User level layer that converts UTF-8 into UTF-16 and not a real UTF-8 Kernel level support (i.e. slower calls)... there is simply toooo much history involved to make Wins UTF-8 OS.
Also additional though is that if we limit the APP to UTF-8 most of the old Wins versions wont support UNICODE and that would be a bummer if we'll invest so much time to make the app UNICODE aware.
So my solution would be:
we'll have a 'string class' which will ALWAYS assume that the string is encoded (i.e. can be made out of multiple code-units... locale (1 code unit), UTF8 (1..4) or UTF16 (1..2))
always use TEXT( .. )_str to create a 'view of a text' which 'string class' will know how to use
if some really special string manipulation would be performed we can:
(higher chance of new bugs)
code points
This solution would made Salamander a little slower as it would be processing DWORDs instead of
BYTES, but the algos would stay the same and the results can always be converted back to the
"encoded" string class to lower the space needed.
string class will have:
Size_CodePoints() -> return number of "real UNICODE characters" (even if encoded as 4 bytes it will still represent 1 real UNICODE character)
Size_CodeUnits() -> return number of code-units
Size_Bytes() -> number of bytes used to encode the string
I've intentionally used Size instead of Length just to make sure that nobody would think of "string length" anymore.. it's "size" i.e number of requested units (whatever that unit is).
So.. my thoughts:
With this rules we'll have the flexibility to use locale or UTF-8 or UTF-16 encoding... i.e. we can then adapt to any OS version we need.
Anyway I'm already writing the string class... it's now the 3rd version already... that's why this whole text came to be as I've encountered issues when dealing with characters.
Any thoughts?
Best regards
Waldemar
Beta Was this translation helpful? Give feedback.
All reactions