эквивалент _wfopen в Mac OS X

Я ищу эквивалент Windows _wfopen()под Mac OS X. Есть идеи?

Мне это нужно для того, чтобы портировать библиотеку Windows, которая использует wchar* ее файловый интерфейс. Поскольку это должна быть кроссплатформенная библиотека, я не могу полагаться на то, как клиентское приложение получит путь к файлу и передаст его библиотеке.

Ответов (5)

Решение

POSIX API в Mac OS X можно использовать со строками UTF-8. Чтобы преобразовать строку wchar_t в UTF-8, можно использовать платформу CoreFoundation из Mac OS X.

Вот класс, который будет обертывать сгенерированную строку UTF-8 из строки wchar_t.

class Utf8
{
public:
    Utf8(const wchar_t* wsz): m_utf8(NULL)
    {
        // OS X uses 32-bit wchar
        const int bytes = wcslen(wsz) * sizeof(wchar_t);
        // comp_bLittleEndian is in the lib I use in order to detect PowerPC/Intel
        CFStringEncoding encoding = comp_bLittleEndian ? kCFStringEncodingUTF32LE
                                                       : kCFStringEncodingUTF32BE;
        CFStringRef str = CFStringCreateWithBytesNoCopy(NULL, 
                                                       (const UInt8*)wsz, bytes, 
                                                        encoding, false, 
                                                        kCFAllocatorNull
                                                        );

        const int bytesUtf8 = CFStringGetMaximumSizeOfFileSystemRepresentation(str);
        m_utf8 = new char[bytesUtf8];
        CFStringGetFileSystemRepresentation(str, m_utf8, bytesUtf8);
        CFRelease(str);
    }   

    ~Utf8() 
    { 
        if( m_utf8 )
        {
            delete[] m_utf8;
        }
    }

public:
    operator const char*() const { return m_utf8; }

private:
    char* m_utf8;
};

Использование:

const wchar_t wsz = L"Here is some Unicode content: éà€œæ";
const Utf8 utf8 = wsz;
FILE* file = fopen(utf8, "r");

Это будет работать для чтения или записи файлов.

Я прочитал имя файла из файла конфигурации UTF8 через wifstream (он использует буфер wchar_t ).

Реализация Mac отличается от Linux и Windows. wifstream считывает каждый байт из файла в отдельную ячейку wchar_t в буфере. Итак, у нас есть 3 пустых байта, хотя для открытия требуется строка char . Таким образом, программист может использовать функцию wcstombs для преобразования строки широких символов в многобайтовую строку.

API поддерживает UTF8. Для лучшего понимания используйте наблюдатель памяти и шестнадцатеричный редактор для вашего файла.

Если вы используете Какао, это довольно просто с NSString. Просто загрузите данные UTF16 с помощью -initWithBytes: length: encoding: (или, возможно, -initWithCString: encoding :), а затем получите версию UTF8, вызвав UTF8String для результата. Затем просто вызовите fopen с вашей новой строкой UTF8 в качестве параметра.

Вы определенно можете вызвать fopen со строкой UTF-8, независимо от языка - хотя не может помочь с C++ в OSX - извините.

Вы просто хотите открыть дескриптор файла, используя путь, который может содержать символы Unicode, верно? Просто передайте путь в представлении файловой системы в fopen .

  • Если путь был получен из стандартных фреймворков Mac OS X (например, из открытой панели Carbon или Cocoa), вам не нужно будет выполнять какие-либо преобразования на нем, и вы сможете использовать его как есть.

  • Если вы сами генерируете часть пути, вы должны создать CFStringRef из своего пути, а затем получить его в представлении файловой системы для передачи в API POSIX, например openили fopen.

Вообще говоря, для большинства приложений вам не придется делать много этого. Например, многие приложения могут иметь вспомогательные файлы данных, хранящиеся в каталоге поддержки приложений пользователя, но пока имена этих файлов являются ASCII и вы используете стандартные API Mac OS X для поиска каталога поддержки приложений пользователя, вам не нужно сделать кучу параноидальных преобразований пути, построенного из этих двух компонентов.

Отредактировано для добавления: я бы настоятельно предостерегал от произвольного преобразования всего в UTF-8 с использованием чего-то вроде, wcstombs потому что кодировка файловой системы не обязательно идентична сгенерированной UTF-8. Mac OS X и Windows используют определенные (но разные) правила канонической декомпозиции для кодировки, используемой в путях файловой системы.

Например, им нужно решить, будет ли «é» сохраняться в виде одной или двух кодовых единиц (либо, LATIN SMALL LETTER E WITH ACUTE либо с LATIN SMALL LETTER E последующим COMBINING ACUTE ACCENT ). В результате образуются две последовательности байтов разной длины, причем Mac OS X и Windows работают так, чтобы не помещать несколько файлов с одинаковыми именами (как их воспринимает пользователь) в один и тот же каталог.

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

@JKP:

Не все функции в MacOS X принимают UTF8, но имена файлов и пути к файлам могут быть UTF8, поэтому все функции POSIX, имеющие дело с доступом к файлам (open, fopen, stat и т. Д.), Принимают UTF8.

Смотрите здесь . Цитировать:

То, как имя файла выглядит на уровне API, зависит от API. Текущие API-интерфейсы Carbon обрабатывают имена файлов как массив символов UTF-16; POSIX обрабатывают их как массив UTF-8, поэтому UTF-8 хорошо работает в Терминале. То, как он хранится на диске, зависит от формата диска; HFS + использует UTF-16, но в большинстве случаев это не важно.

Некоторые другие функции POSIX также обрабатывают UTF8. Например, функции, имеющие дело с именами пользователей, именами групп или паролями пользователей, используют UTF8 для хранения информации (таким образом, имя пользователя может быть японским, а ваш пароль может быть китайским, без проблем).

Но не все работают с UTF8. Например, для всех строковых функций строка UTF8 - это обычная строка C, а символы выше 126 не имеют особого значения. Они не понимают концепцию нескольких байтов (символов в C), образующих один символ Unicode. То, как другие API-интерфейсы обрабатывают передаваемый им указатель char *, отличается от API к API. Однако, как правило, можно сказать:

Либо функция принимает только строки C с чистыми символами ASCII (только в диапазоне от 0 до 126), либо принимает UTF8. Обычно функции не допускают символов выше 126 и интерпретируют их в любой другой кодировке, кроме UTF8. Если это действительно так, это задокументировано, и тогда должен быть способ передать кодировку вместе со строкой.