Как выбрать правильную кодовую страницу для декодирования контента, закодированного CArchive

В .net я хочу декодировать некоторые необработанные данные, закодированные приложением C ++. Приложение C ++ является 32-разрядным, а приложение C # — 64-разрядным.

Приложение C ++ поддерживает русские и испанские символы, но он не поддерживает символы Юникода. Этот двоичный читатель C # не может читать русские или испанские символы и работает только для английских символов ascii.

CArchive не указывает никакой кодировки, и я не уверен, как читать его из C #.

Я проверил это на пару простых строк, это то, что обеспечивает C ++ CArchive:

Для «Азбуки»: «03 41 42 43»

Для «ÁåëÀÇ 7555»: «0B C1 E5 EB C0 C7 20 37 35 35 35 C2»

Ниже показано, как приложение C ++ записывает двоичный файл.

void CColumnDefArray::SerializeData(CArchive& Archive)
{
int iIndex;
int iSize;
int iTemp;
CString sTemp;

if (Archive.IsStoring())
{
Archive << m_iBaseDataCol;
Archive << m_iNPValueCol;

iSize = GetSize();
Archive << iSize;
for (iIndex = 0; iIndex < iSize; iIndex++)
{
CColumnDef& ColumnDef = ElementAt(iIndex);
Archive << (int)ColumnDef.GetColumnType();
Archive << ColumnDef.GetColumnId();
sTemp = ColumnDef.GetName();
Archive << sTemp;
}
}
}

И вот как я пытаюсь прочитать это в C #.

Далее можно расшифровать «Азбуку», но не русские символы. Я проверял this.Encoding со всеми доступными опциями (Ascii, UTF7 и т. д.). Русские символы работают только для Encoding.Default. Но, очевидно, это ненадежный вариант, так как кодирование и декодирование обычно происходит на разных компьютерах.

        public override string ReadString()
{
byte blen = ReadByte();
if (blen < 0xff)
{
// *** For russian characters it comes here.***
return this.Encoding.GetString(ReadBytes(blen));
}

var slen = (ushort) ReadInt16();
if (slen == 0xfffe)
{
throw new NotSupportedException(ServerMessages.UnicodeStringsAreNotSupported());
}

if (slen < 0xffff)
{
return this.Encoding.GetString(ReadBytes(slen));
}

var ulen = (uint) ReadInt32();
if (ulen < 0xffffffff)
{
var bytes = new byte[ulen];
for (uint i = 0; i < ulen; i++)
{
bytes[i] = ReadByte();
}

return this.Encoding.GetString(bytes);
}

//// Not support for 8-byte lengths
throw new NotSupportedException(ServerMessages.EightByteLengthStringsAreNotSupported());
}

Какой правильный подход для декодирования этого? Как вы думаете, выбор правильной кодовой страницы — способ решить эту проблему? Если да, то как узнать, какая кодовая страница использовалась для кодирования?

Цените, если кто-то может показать мне правильное направление, чтобы сделать это.

редактировать

Похоже этот вопрос а также «Абсолютный минимум, который должен знать каждый разработчик программного обеспечения, абсолютно точно должен знать о Unicode и наборах символов (никаких оправданий!)» Статья разрешит некоторые сомнения. По-видимому, нет способа найти правильную кодовую страницу для существующих данных.

Я думаю, теперь вопрос: есть ли кодовая страница, которая поддерживает все испанские, русские и английские символы? Могу ли я указать кодовую страницу в классе C ++ CArchive?

4

Решение

Программа не на Unicode C ++ записывает данные как 0B C1 E5 EB C0 C7 20 37 35 35 35 C2 (длина строки, затем bytes)

"ÁåëÀÇ 7555Â" это представление bytes в кодовой странице 1252

На английском языке компьютер возвращает следующий код "ÁåëÀÇ 7555Â", Это работает, если обе программы используют одну и ту же кодовую страницу:

string result = Encoding.Default.GetString(bytes);

Вы также можете использовать кодовую страницу 1252 напрямую. Это гарантирует, что результат всегда "ÁåëÀÇ 7555Â" для этого конкретного набора байтов:

//result will be `"ÁåëÀÇ 7555Â"`, always
Encoding cp1252 = Encoding.GetEncoding(1252);
string result = cp1252.GetString(bytes);

Однако это не может решить никаких проблем. Рассмотрим пример с греческим текстом:

string greek = "ελληνικά";
Encoding cp1253 = Encoding.GetEncoding(1253);
var bytes = cp1253.GetBytes(greek);

bytes будет аналогичен выводу программы C ++. Вы можете использовать ту же технику для извлечения текста:

//result will be "åëëçíéêÜ"Encoding cp1252 = Encoding.GetEncoding(1252);
string result = cp1252.GetString(bytes);

Результат "åëëçíéêÜ", Но желаемый результат "ελληνικά"

//result will be "ελληνικά"Encoding cp1253 = Encoding.GetEncoding(1253);
string greek_decoded = cp1253.GetString(bytes);

Таким образом, чтобы сделать правильное преобразование, вы должны иметь исходную кодовую страницу, которую использовала программа C ++ (Я просто повторяю Ганса Пассанта)

Вы можете сделать следующую модификацию:

public override string ReadString()
{
//Default code page if both programs use the same code page
Encoding encoder = System.Text.Encoding.Default;

//or find out what code page the C++ program is using
//Encoding encoder = System.Text.Encoding.GetEncoding(codepage);

//or use English code page to always get "ÁåëÀÇ 7555Â"...
//Encoding encoder = System.Text.Encoding.GetEncoding(1252);
//(not recommended)

byte blen = ReadByte();
if (blen < 0xff)
return encoder.GetString(ReadBytes(blen));

var slen = (ushort)ReadInt16();
if (slen == 0xfffe)
throw new NotSupportedException(
ServerMessages.UnicodeStringsAreNotSupported());

if (slen < 0xffff)
return encoder.GetString(ReadBytes(blen));

var ulen = (uint)ReadInt32();
if (ulen < 0xffffffff)
{
var bytes = new byte[ulen];
for (uint i = 0; i < ulen; i++)
bytes[i] = ReadByte();
return encoder.GetString(ReadBytes(blen));
}

throw new NotSupportedException(
ServerMessages.EightByteLengthStringsAreNotSupported());
}

Дополнительные комментарии:

Программа не-Unicode MFC может принимать ввод на английском или русском языке, но не на обоих языках одновременно. Эти старые программы используют char хранить до 255 букв на байт. 255 не хватает места для всех алфавитов на английском, русском, греческом, арабском …

Кодовая страница 1252 сопоставляет символы латинским алфавитам. В то время как кодовая страница 1253 отображает символы на греческий алфавит и так далее.

Поэтому ваш файл MFC содержит только один язык одной кодовой страницы.

Западноевропейские языки (английский, испанский, португальский, немецкий, французский, итальянский, шведский и т. Д.) Используют кодовую страницу 1252. Если пользователи остаются в этой языковой группе, проблем не должно быть. System.Text.Encoding.Default должен решить проблему, или еще лучше System.Text.Encoding.GetEncoding(variable_codepage)

В Windows есть несколько соответствующих кодовых страниц ANSI

874 – Windows Thai
1250 – Windows Central and East European Latin 2
1251 – Windows Cyrillic
1252 – Windows West European Latin 1
1253 – Windows Greek
1254 – Windows Turkish
1255 – Windows Hebrew
1256 – Windows Arabic
1257 – Windows Baltic
1258 – Windows Vietnamese

Некоторые азиатские языки не поддерживаются без Unicode. Некоторые символы Unicode не поддерживаются в ANSI, с этим ничего не поделаешь.

Можно заставить программу, не поддерживающую Юникод, использовать более одной кодовой страницы. Но это не практично. Гораздо проще перейти на Unicode и сделать это правильно.

Смотрите также Минимальные разработчики программного обеспечения должны знать о Unicode

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]