вторник, 5 октября 2010 г.

Почему ACP <> OEMCP (обычно)

Это перевод Why ACP != OEMCP (usually). Автор: Майкл Каплан.

Обычно при работе с консолью люди сразу же замечают такую вещь: страница по-умолчанию ANSI (ACP) не совпадает с кодовой страницей OEM (OEMCP) для большинства локалей.

Это идёт из времён MS-DOS (как и многие другие вещи!)...

Когда у нас было время DOS, кодовые страницы контролировались IBM, а не Microsoft. Многие "оригинальные" кодовые страницы появились в это время - от интересных до очень странных (да, я говорю о кодовой странице №437!), хотя некоторые из них предшествуют даже IBM (насчёт этого я точно не уверен).

Затем вышла Windows с кодовыми страницами Windows, разработанными (если можно так сказать о данных), чтобы обрабатывать много языков одновременно. Смоделированными по серии ISO-8859, но с добавлением символов, полезных большинству языков, а не выбранным (типа базовой поддержки французского в арабской кодовой странице):
  • 1250 - Central Europe
  • 1251 - Cyrillic
  • 1252 - Latin 1 (иногда называемая Western European)
  • 1253 - Greek
  • 1254 - Turkish
  • 1255 - Hebrew
  • 1256 - Arabic
  • 1257 - Baltic
  • 1258 - Vietnam
Идея была в том, что DOS-программы (в тот момент не рассматриваемые как "устаревшие" - потому что других программ практически не было) работали бы с теми же самыми старыми кодовыми страницами, а Windows приложения использовали бы новые кодовые страницы и работали бы с многими языками. Были даже добавлены API-функции, чтобы менять поведение базовых функций файловой системы, поскольку файловая система - это то место, где пересекаются эти приложения. Так были рождены функции AreFileApisANSI, SetFileApisToOEM и SetFileApisToANSI1.

Итак, эти кодовые страницы не равны по соображениям совместимости.

- Ага - скажете вы, - но почему же тогда ACP и OEMCP равны для всех локалей CJK? У нас есть:
  • 932 - Japanese (Shift-JIS)
  • 936 - Simplified Chinese (GBK)
  • 949 - Korean
  • 950 - Traditional Chinese (Big5)
И они работают и как кодовые страницы ANSI и как OEM в большинстве локалей восточной Азии.

Для этого есть много причин. Одна из самых очевидных - эти четыре кодовые страницы изначально создавались по стандартам (государственным или промышленным) и поэтому у них нет вопроса обратной совместимости. Никто не захотел просто так штамповать кодовые страницы.

Одна из архитектурных причин, которые влияют на NT - правила о кодовых страницах в режиме ядра. У функции API типа RtlUnicodeStringToOemString и RtlUnicodeStringToAnsiString есть неявное предположение, что размер строки при конвертации никогда не изменится (т.е. при конвертации ANSI <-> OEM размер строки в байтах меняться не может). И для кодовых страниц не-CJK это не проблема: потому что либо символ находится в кодовой странице и занимает один байт, либо его там нет и он представлен вопросительным знаком (который тоже занимает один байт). Но кодовые страницы CJK могут иметь символы длиной в несколько байт. Поэтому будет плохой идеей заводить разные (для ANSI/OEM) кодовые страницы, одна из которых кодирует символ в один байт, а другая - в несколько.

(Эти функции также предполагают, что размер любого Unicode-символа равен двум байтам - что действительно так для символов из любых кодовых страниц ANSI и OEM. И для тех, кому интересно: функции в ntdll.dll не ставят вопрос об обработке precomposed или composite Unicode - они поддерживают только форму precomposed. И Джулия не несёт за эти функции никакой ответственности, хотя она когда-то исправляла в них баги!)

В любом случае, кодовые страницы восточной Азии избавлены от необходимости в двух кодовых страницах. Это хорошо, потому что у них есть и другие вещи, о которых нужно волноваться - функции типа IsDBCSLeadByte...

Ну, разве вы не рады, что вы используете Unicode и вам не нужно волноваться об этих проблемах? :-)

1 - и даже не заикайтесь о системе наименования, в которой у одного акронима (API) не все буквы заглавные, а в других (ANSI, OEM) - все. Боже...

This post brought to you by "ì" (U+00ec, a.k.a. LATIN SMALL LETTER I WITH GRAVE)

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.