String encoding functions in far2l code #1063
Replies: 14 comments 1 reply
-
Классный подробный ответ, спасибо! А что, теоретически, нужно сделать, чтоб far2l стал полностью внутри работать на честном utf-32? Пройтись по всему коду, и заменить WideCharToMultiByte/MultiByteToWideChar на utf32-полностью-совместимые аналоги? В putty4far2l, кстати, тоже utf16 винды "конвертируется" в utf32 far2l'а дописываем нулей, потому что я пока не такой крутой сишник, чтоб разобраться, как там с честным utf32 в Винде работать |
Beta Was this translation helpful? Give feedback.
-
внутри фар работает на честном UTF32, "не честные" только перекодировки между всякими CP_* (исключая UTF8/16) и UTF32. То есть гипотетически есть вероятность что открыв вьювером файл в какой нить CP_949 то (некоторые) отображаемые иероглифы могут оказаться не правильные. Но ктож это проверит.. |
Beta Was this translation helpful? Give feedback.
-
А, кстати, какой строковой тип можно считать "поумолчательным" для far2l, если новый функционал какой-то решаешь запилить? |
Beta Was this translation helpful? Give feedback.
-
а хз в зависимости от того что за функционал и с чем связывается. если активно взаимодействует с фаровским кодом юзающим FARString - то FARString, иначе std::(w)string. Еще важный момент - у FARString проблемы с многопоточностью. Так что если код както юзает многопоточность то очень много думать в местах где юзается FARString |
Beta Was this translation helpful? Give feedback.
-
Я смотрю, там большая работа по улучшению FARString'ов происходит! А можно про неё рассказать немножко? Жутко интересно :) |
Beta Was this translation helpful? Give feedback.
-
да (пока) ниче особо принципиального, просто раньше там неэффективно память выделялась - выделялся кусок в котором хранилась инфа об строке - длина и указатель на другой кусок с самой строкой. Переделал объединив два этих маллока в один - получилось ~20% меньший расход памяти если открыть дир с ~500k файлов) |
Beta Was this translation helpful? Give feedback.
-
Только сейчас дошло. А как UTF32 работала в оригиральном фаре, если WinApi изначально только UTF16 умеет? |
Beta Was this translation helpful? Give feedback.
-
Никак, пересадка на 32хбитный wchar_t была частью портирования. Но там ниче особо сложного не было - кое где поправить захардкоженные размеры буферов и все. |
Beta Was this translation helpful? Give feedback.
-
В смысле оригинальный фар не мог открыть текст в utf-32? Ничосси. А я и забыл уже, какие кодировки там поддерживались, кроме 1251, 866 и utf-8 :) |
Beta Was this translation helpful? Give feedback.
-
Неа, за самый свежак не скажу, но 3.0.5665 не умеет. В принципе они могут сделать преобразование из utf32 в свой нативный utf16, так же как far2l умеет из utf16 в utf32, но на самом деле гдеж тексты на том UTF32 найдешь? UTF8 закономерно победил, даже микрософт признала что UTF16 не нужен, и те функции Вин АПИ которые заканчиваются на A, и раньше умели в однобайтные ANSI кодировки нынче могут работать в режиме UTF8: https://docs.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page |
Beta Was this translation helpful? Give feedback.
-
Вроде теперь с многопоточностью у FARString должно быть норм. |
Beta Was this translation helpful? Give feedback.
-
Теперь стало интересно, у чего ещё в far2l с ней не норм :) |
Beta Was this translation helpful? Give feedback.
-
Смотреть надо по месту, многопоточность штука сложная. В целом фар исторически к ней не приспособлен но я местами прикручиваю некоторые оптимизации-параллелезации, и ограничения FARString в этом плане стали немного мешать. |
Beta Was this translation helpful? Give feedback.
-
Вопрос: а не нужно ли когда-нибудь со временем полностью перейти на UTF-8? |
Beta Was this translation helpful? Give feedback.
-
Ответ на #692 (comment) ибо там это офтопик, а народу в CC той темы много;)
unxed> Обновился. Кстати, давно хотел спросить — а зачем нужны Wide2MB и MB2Wide, если есть реализации того же самого в APIStringCodepages.cpp?
Wide2MB/MB2Wide это основные функции взаимодействия с линуксовыми АПИ, так как код фара внутри весь на wchar_t, то на каждый readdir нужно MB2Wide() а на каждый open() - Wide2MB(). MB тут multibyte, гипотетически far2l можно научить работать на системах с произвольной системной кодировкой, а не только UTF8, но судя по тому что ни разу не было багов типа 'ой в моей KOI8 far2l кракозяблков показывает' - это наверное не нужно
Важный момент - все эти Wide2MB/MB2Wide - плюсовые функции, заточеные на работу с std::string/std::wstring. Кроме того они (не все правда) делают escaping некорректных последовательных при преобразовании из utf8 в wchar_t и этот escaping отматывается назад, при обратном преобразовании. Так что если readdir найдет файл с корявым именем не в utf8, то после преобразования этого имени в FARString, прохода по кишкам фара и последующем преобразовании обратно при вызове скажем open - последнему будет скормлено идентичное корявое имя.
А APIStringCodepages.cpp - это реализация 'виндовых' апи WideCharToMultiByte/MultiByteToWideChar - это чисто сишные функции работающие с жестко заданными буферами, и они умеют перекодировать разные кодовые страницы в wchar_t и назад. Включая UTF8/16/32.
Для UTF8/16/32 и Wide2MB/MB2Wide и WideCharToMultiByte/MultiByteToWideChar юзают один и тот же код utf-cpp, то есть для случая перекодировки UTF* они оба являются интерфейсами одной и той же реализации, просто Wide2MB/MB2Wide заточена для использования с C++-сными строками, а WideCharToMultiByte/MultiByteToWideChar - просто юзается там где всегда юзались в оригинальном фаровском коде.
Небольшая ремарка - оригинальный код wine'а для перекодировки между utf8-16-32 не годится, так как он умеет только перекодировать только между utf8 и utf16. А в линуксе wchar_t - 32хбитный. Для всяких кодировок CP_* там сделал хак, который просто по сути кастует 16битные символы UTF16 в 32хбитные и таким образом получается UTF32 оно работает (хотя не уверен что для всех кодировок) просто потому что львиная доля UTF16 именно так и отображается на UTF32, львиная - но не вся, а потому преобразвывать utf8 в wchar_t и назад оригинальным вайновским кодом низзя, и потому все преобразования между CP_UTF8/CP_UTF32*/CP_UTF16* в APIStringCodepages.cpp уходят в итоге в utf-cpp, находящуюся в utils. В WinPort остались ошметки оригинального вайновского кода поддержки utf8, но лишь по двум причинам - во первых вычищать лень, во вторых utf-cpp не умеет в UTF7, потому для работы с UTF7 юзается вайновский код (с неизбежными проблемами описанными выше). В принципе можно дописать поддержку UTF7 в utf-cpp, если вдруг внезапно захочется идеальной поддержки UTF7, и тогда можно будет выкинуть вайновский код работы с UTF8/UTF7 - он там просто весьма взаимосвязан потому выкидывать можно только все сразу.Beta Was this translation helpful? Give feedback.
All reactions