TagLib — Как обрабатывать пути к файлам в кодировке UTF-8?

#c #windows #qt #unicode #taglib

#c #Windows #qt #Юникод #taglib

Вопрос:

Проблема: Я хочу, чтобы TagLib::FileRef открыл файл с символами Юникода в имени файла или пути, но не удается.

Я скомпилировал TagLib 1.7 с помощью MinGW (GNU Make 3.81, GCC 4.4.0) под Windows 7 (64-разрядный, но 32-разрядный компилятор) после создания Makefile с помощью CMake 2.8.4. Я использую TagLib совместно с платформой Qt 4.7.2.

Для обмена строками между двумя библиотеками TagLib предоставляет:

 #define QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
#define TStringToQString(s) QString::fromUtf8(s.toCString(true))
// toUtf8() is a fix, originally spelled utf8(), but that's not relevant here.
  

Я сконструировал TagLib::FileRef следующим образом:

 TagLib::FileRef fileRef( QStringToTString(filePath).toCString(true) );
// or:
TagLib::FileRef fileRef( TagLib::FileName( QStringToTString(filePath).toCString(true) ) );
  

В результате не удается загрузить файлы с путями, содержащими символы Unicode или символы Latin-1 с другим кодом в представлении UTF-8 (например, умляуты или китайские символы) (fileRef.isNull()).

Если я передам false функции toCString() выше (объявление: см. Ниже), TagLib может обрабатывать умляуты (но не символы только для Unicode). Поэтому я предполагаю, что я неправильно скомпилировал TagLib (TagLib::FileRef интерпретирует данную строку как Latin-1), но я не знаю, как проверить или даже исправить это. Примечание: Строки Unicode в тегах (ID3) правильно извлекаются с помощью TagLib.

toCString():

 const char* TagLib::String::toCString( bool unicode = false ) const;
  

Документ: документация по TagLib

Ответ №1:

FileRef Конструктор принимает FileName объект (не String !), который может быть char* или wchar_t* строкой. В Windows вы можете предположить, что оба wchar_t и QChar имеют 16 бит, поэтому вы можете просто передать их filePath.constData() .

Обратите внимание, что если вы планируете запускать код на платформе, отличной от Windows, вам необходимо провести #ifdef проверку при FileRef создании объекта, потому что на других платформах он принимает только char* строки, и вам следует использовать QFile::encodeName(filePath).constData() .

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

1. Спасибо, TagLib::FileRef fileRef( reinterpret_cast<const wchar_t*>(filePath.constData()) ); хорошо работает под Windows. Я планирую запустить это на разных системах; QFile::encodeName() вероятно, это будет кодироваться в UTF-8?

2. Да, большинство других систем сейчас используют имена файлов в формате UTF-8, но обычно это зависит от настроек пользователя, поэтому вы не можете предположить, что это будет UTF-8.

Ответ №2:

Другой способ — использовать, toStdString() за которым c_str() следует.

 QString path(...);
std::string stdString = path.toStdString();
const char *cPath = stdString.c_str();
TagLib::FileRef fr(cPath);
  

Обязательно сохраните stdString как переменную, так как без этого она будет уничтожена к концу строки.

По крайней мере, в моем случае оба QFile::encodeName(filePath) и QString::toLocal8Bit() завершились неудачей — они были заменены ąęóżłćĄĘŁ на aeózlcAEL (похоже, ó мне повезло пережить это), что привело к сбою моего приложения. К сожалению, я не могу ответить, почему методы Qt не сработали в моем случае.