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

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

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

5 ответов

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

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

    API поддерживает UTF8. Для лучшего понимания используйте memory watcher и HEX editor для вашего файла.

  2. @JKP:

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

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

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

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

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

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

  3. 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");
    

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

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

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

    • Если вы генерируете часть пути самостоятельно, вы должны создать CFStringRef из вашего пути, а затем получить, что в представлении файловой системы, чтобы передать POSIX API, как 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 работают, чтобы избежать размещения нескольких файлов с одинаковым именем (как их воспринимает пользователь) в одном каталоге.

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

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

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