Win32.Utf8.
Я тут совсем недавно удивлялся почему нет библиотек, эмулирующих поддержку UTF-8 на уровне Win32 API. Т.е. такая библиотека реализует, скажем, CreateFileUtf8 в дополнение к предлагаемым системой CreateFileA и CreateFileW, а макрос CreateFile будет выбирать нужную реализацию уже из трех вариантов. Надо сказать, что по итогам обсуждения моё недоумение нисколько не уменьшилось. Даже ссылки на Michael Caplan - авторитета в этой области не помогли. Это, впрочем, как раз очень понятно. Набивать свои шишки куда как интереснее, чем послушать что говорят умные люди уже ходившие по этим граблям.
В общем я решил попробовать набить своих шишек, - попробую написать эту библиотеку и добавить с её помощью поддержку Unicode в Notepad2 (вернее адаптированную под себя версию Notepad2). Пока что, всё выглядит довольно невинно - верный знак, что на самом деле всё гораздо сложнее. Нужно сделать следующее:
- Написать или взять готовый парсер С – для разбора заголовочных файлов и извлечения из них объявлений функций и типов;
- Научиться обрабатывать SAL аннотации параметров функций и членов структур;
- Продумать сценарии прямого (UTF-8 -> UTF-16) и обратного (UTF-16 -> UTF-8) конвертирования текстовых параметров, включая нетривиальные случаи вроде «текстового буфера определённого размера, вложенного в структуру на которую указывает указатель» и т.п.;
- Создать инфраструктуру, которая будет использоваться для конвертирования текстовых параметров;
- Написать генератор оберток, который будет пользоваться этой инфраструктурой;
- Предусмотреть всяческие исключения для всяких неординарных случаев и возможность написания оберток вручную.
Учитывая, что тратить на это я могу от силы часов 8 в неделю – затея затянется надолго. Опять же цель этого мероприятия не столько получить конечный результат, сколько получить «бесценный» опыт. Так что торопиться не будем. Кроме того, это означает, что вариант написать всё обертки вручную так же не рассматривается. (Хотя, вполне возможно, это было бы проще всего).
В качестве языков разработки я выбрал Python и C (или C-подобный C++). На Python легко пишется всякая скриптовая логика. На C будет генерироваться код обёрток. Да и парсить C проще в разы.
О ходе работ и своих находках буду делиться в блоге. Если из проекта выйдет хоть какой толк, то исходный код будет выложен в публичный Subversion репозиторий.
Критика и идеи приветствуются.
до сих пор не встретил ещё ни одного неинтересного вашего поста
>О ходе работ и своих находках буду делиться в блоге
ждёмс
Нивапрос! Исправлюсь.
Интересно… Ждем-с.
Итого - примерно 2к-3к функций Win32 API этот слой сможет обработать, хотя я не вполне верю, что SAL декларации получится конвертировать каким-либо способом кроме консервативного, ака “возьмем и умножим длину char буфера на 4 == max(sizeof(any utf8char from first 17 planes))” который сразу потребует в 4 раза больше памяти, чем для ANSI кода, и в 2 раза больше чем для UTF16. А это вызовет каскад предупреждений, правильных и по делу, причем исправить их будет сложнее, чем перейти на TCHAR.
Но что делать с COM интерфейсами? Это значительная часть API. Тот же Direct3D имеет в интерфейсах как XxxA так и XxxW функции плюс макрос для этих целей, но XxxU8 там нет, и ни язык, ни рантайм не позволят их туда вставить.
Недавно я стал программистом под Mac OS X, ее “новый” системный язык, Objective C, имеет интересную особенность. Вызов любого метода там осуществляется динамически. Компилятор преобразует сигнатуру вызываемого метода в селектор, который в рантайме ищется в аналоге vtbl. Этот подход, привнеся накладные расходы, позволил некоторые уникальные вещи - например, чужой класс можно расширить своими методами, которые станут неотличимы от первоначальных. Что-то типа написать новый метод для System.Object, который станет доступен всем, как только будет загружена assembly с его реализацией, возможно динамически.
В случае COM задачу внедрения Utf-8 API можно решить только замещением содержимого vtbl слотов оригинальных интерфейсов для ANSI функций, например в прокси-стабах, причем тут же появляется проблема с подсовыванием таких стабов, в том числе для COM интерфейсов, которые создаются не стандартным CoCreateInstance, а custom способом, как тот же Direct3D. Безнадега
Не надо пытаться объять необъятное.
Сделаем сначала Win32 API, набъём руку…
Хотя именно с COM интерфейсами особых сложностей может и не случиться. Особенно если есть в наличии IDL или type library.
При этом никто не мешает модифицитовать код приложения так, что получаемые объекты будут заворачиваться в proxy. Так что никаких страшных манипуляций с vtbl не требуется.
Возможно, я отвлеку от первоначальной идеи, но есть место, где UTF-8 мог бы пригодиться:
Меня не устраивает текущая реализация MinGW. MinGW — это инструмент портирования юниксовых программ. Все юниксовые программы нормально держат Юникод на настоящих Юниксах, потому что там UTF-8. Под MinGW, однако же, POSIX API принимают ANSI строки. Оправдывается это тем, что, мол, MinGW — это minimalistic в самом названии, а перекодировка из UTF-8 в UTF-16 — это уже не minimalistic. Хотите, мол, полной эмуляции, есть cygwin. Эта позиция меня не устраивает. Хотелось бы увидеть форк MidGW (midimalistic, соответственно), в котором всё в порядке. Просто MinGW — это сейчас единственный способ делать нормальные бинарии под Windows. Cygwin’овские слишком “инопланетные”. Вот эмуляция POSIX fork() и ptty меня, к примеру, не интересует, а UTF-8 — да. Если делать UTF-8 в MidGW, то там ещё проблема возникает, библиотека должна различать консольный хендл и неконсольный. На неконсольный нужно выводить UTF-8, а на консольный — преобразовывать его в UTF-16 и выводить через особые функции WinAPI. По–хорошему ещё нужно адекватно реагировать на ANSI.
На этапе инициализации, когда природа stdin, stdout и stderr не ясна, на них нужно попытаться вывести 0 символов, но именно через консольную процедуру вывода. Если это файл, то будет ошибка. Если консоль, то OK.
В других случаях (кроме stdin, stdout, stderr) обычно должно быть понятно сразу, файл открывается или консоль. Ну это так, к слову о том, какие проблемы могут встретиться.
API POSIX вроде бы не такое необъятное, как WinAPI. Можно примерно представить объём работ. Коль скоро эти работы будут сделаны, MinGW проги станут 100% Юникодными. Мб, придётся чуть допилить, в любом случае, много людей скажут спасибо.
Ну насколько я могу судить там не все так тривиально. Чтобы добавить нормальную поддержку UTF-8 там по хорошему нужно реализовать поддержку всех остальных кодировок. Т.е. втащить libiconv и всё что с ним связяно. Можно конечно, написать узкоспециализированный UTF-8 only вариант. Но я бы на месте авторов MinGW такое бы в свой код не пустил бы.
Умножайте все оценки на 20.
Да нет, зачем же всех? Вот как раньше ANSI была, так сделать UTF-8 вместо неё.
libiconv здесь зачем? Даже если нужны кодировки, я видел сопоставление юниксовых и виндовых кодировок, а там уж виндовыми средствами перекодировку можно доделать. Я не совсем уловил суть проблемы.
Если добавляь поддержку кодировок, то её реализация должна быть совместимой с тем как это сделано в posix системах. С примерно теми же настройками, возможностами и т.д. Остальное - грязный хак.