Установить заголовок пути UTF-8 в libarchive

РЕЗЮМЕ

Как я могу написать zip-файл, используя libarchive на C ++, чтобы имена путей были в кодировке UTF-8? При использовании путей к UTF-8 специальные символы будут правильно декодироваться при использовании OS X / Linux / Windows 8/7-Zip / WinZip.

ПОДРОБНОСТИ

Я пытаюсь написать zip-архив с помощью libarchive, компилируя с Visual C ++ 2013 для Windows.

Я хотел бы иметь возможность добавлять файлы с не-ASCII-символами (например, äöü.txt) в zip-архив.

В libarchive есть четыре функции для установки заголовка пути:

void archive_entry_set_pathname(struct archive_entry *, const char *);
void archive_entry_copy_pathname(struct archive_entry *, const char *);
void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
int  archive_entry_update_pathname_utf8(struct archive_entry *, const char *);

К сожалению, ни один из них, кажется, не работает.

В частности, я попробовал:

const char* myUtf8Str = ...
archive_entry_update_pathname_utf8(entry, myUtf8Str);
// this sounded like the most straightforward solution

а также

const wchar_t* myUtf16Str = ...
archive_entry_copy_pathname_w(entry, myUtf16Str);
// UTF-16 encoded strings seem to be the default on Windows

В обоих случаях полученный zip-архив неправильно отображает имена файлов как в Windows Explorer, так и в 7-Zip.

Я уверен, что мои входные строки закодированы правильно, так как я конвертирую их из Qt QString примеры, которые отлично работают в других частях моего кода:

const char* myUtf8Str = filename.toUtf8().constData();
const wchar_t* myUtf16Str = filename.toStdWString().c_str();

Например, это работает даже для другого вызова libarchive, при создании zip-файла:

archive_write_open_filename_w(archive, zipFile.toStdWString().c_str());
// creates a zip archive file where the non-ASCII
// chars are encoded correctly, e.g. äöü.zip

Я также попытался изменить параметры для libarchive, как предложено этот пример:

archive_write_set_options(a, "hdrcharset=UTF-8");

Но этот вызов не удался, поэтому я предполагаю, что мне нужно установить какой-то другой вариант, но у меня заканчиваются идеи …

ОБНОВЛЕНИЕ 2

Я сделал еще немного чтения о формате zip. Он позволяет записывать имена файлов в UTF-8, так что OS X / Linux / Windows 8/7-Zip / WinZip всегда будет правильно их декодировать, см., Например, Вот.

Это то, чего я хочу достичь с помощью libarchive, то есть я хотел бы передать его в кодировке UTF-8 pathname и сохраните его в zip-файле без каких-либо преобразований.

Я добавил подход «установить локаль» в качестве (неудовлетворительного) ответа.

7

Решение

Это обходной путь, при котором имена путей будут храниться с использованием настроек локали системы, т. Е. Полученный файл zip может быть правильно декодирован в той же системе, но не переносим.

Это не удовлетворяет, я просто публикую это, чтобы показать, что это не то, что я ищу.

Установите глобальную локаль на "" как объяснил здесь:

std::locale::global(std::locale(""));

и затем прочитайте это назад:

std::locale loc;
std::cout << loc.name() << std::endl;
// output: English_United States.1252
// may of course be different depending on system settings

Затем установите pathname используя archive_entry_update_pathname_utf8,

Файл zip теперь содержит имена файлов, закодированные с помощью Windows-1252, поэтому моя Windows может их прочитать, но они отображаются как мусор, например, на. Linux.

Будущее

Eсть проблема с архивами для файлов UTF-8. Вся история довольно сложная, но похоже, что они могут добавить лучшую поддержку UTF-8 в libarchive 4.0.

2

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

Я добавлю это как ответ, потому что это превышает ограничения текста для комментария.

При запуске программы глобальная локаль совпадает с классической локалью. Классическая локаль C — это английская локаль ASCII в США в стандартной библиотеке C, которая неявно используется в программах, которые не интернационализированы.
И в качестве этот источник предлагает —

…Если вы планируете локализовать свою программу,
подходящая стратегия может заключаться в том, чтобы получить родную локаль один раз на
начало вашей программы, и никогда, никогда не меняйте эту настройку снова.
Таким образом, ваше приложение адаптируется к одной конкретной локали, и
использует это на протяжении всего времени выполнения. Пользователи таких приложений
может явно установить свою любимую локаль перед началом
приложение. В системах UNIX они делают это, устанавливая среду
переменные, такие как LANG; другие операционные системы могут использовать другие методы.

В вашей программе вы можете указать, что вы хотите использовать пользователя
предпочитаемый родной язык, позвонив std::setlocale("") при запуске,
передавая пустую строку в качестве имени локали. Пустая строка говорит
setlocale для использования локали, указанной пользователем в среде.

0

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