_wfopen equivalente no Mac OS X

Eu estou olhando para o equivalente do Windows _wfopen() no Mac OS X. Alguma idéia?

Eu preciso disso para portar uma biblioteca do Windows que use o wchar* para sua interface de arquivo. Como isso se destina a ser uma biblioteca de plataforma cruzada, não posso confiar em como o aplicativo cliente obterá o caminho do arquivo e o fornecerá à biblioteca.

A API POSIX no Mac OS X pode ser usada com strings UTF-8. Para converter uma string wchar_t em UTF-8, é possível usar a estrutura CoreFoundation do Mac OS X.

Aqui está uma class que irá envolver uma string gerada por UTF-8 a partir de uma string 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; }; 

Uso:

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

Isso funcionará para ler ou gravar arquivos.

Você só quer abrir um identificador de arquivo usando um caminho que pode conter caracteres Unicode, certo? Basta passar o caminho na representação do sistema de arquivos para fopen .

  • Se o caminho veio das estruturas do Mac OS X padrão (por exemplo, um painel Abrir, seja Carbono ou cocoa), você não precisará fazer nenhuma conversão nele e poderá usá-lo como está.

  • Se você está gerando parte do caminho, você deve criar um CFStringRef a partir do seu caminho e, em seguida, obter isso na representação do sistema de arquivos para passar para as APIs POSIX como open ou fopen .

De um modo geral, você não terá que fazer muito disso para a maioria dos aplicativos. Por exemplo, muitos aplicativos podem ter arquivos de dados auxiliares armazenados no diretório Application Support do usuário, mas desde que os nomes desses arquivos sejam ASCII e você use APIs padrão do Mac OS X para localizar o diretório Application Support do usuário, não é necessário fazer um monte de conversão paranóica de um caminho construído com esses dois componentes.

Editado para adicionar: Eu recomendaria fortemente contra a conversão arbitrária de tudo para UTF-8 usando algo como wcstombs porque a codificação do sistema de arquivos não é necessariamente idêntica à UTF-8 gerada. Mac OS X e Windows usam regras de decomposição canônicas específicas (mas diferentes) para a codificação usada nos caminhos do sistema de arquivos.

Por exemplo, eles precisam decidir se “é” será armazenado como uma ou duas unidades de código ( LATIN SMALL LETTER E WITH ACUTE ou LATIN SMALL LETTER E seguido de COMBINING ACUTE ACCENT ). Isso resultará em duas sequências de bytes diferentes e de comprimento diferente, e tanto o Mac OS X quanto o Windows funcionarão para evitar a colocação de vários arquivos com o mesmo nome (conforme o usuário os percebe) no mesmo diretório.

As regras sobre como realizar essa decomposição canônica podem ficar bem cabeludas, então, em vez de tentar implementá-la sozinho, é melhor deixá-la para as funções que as estruturas de sistema forneceram para você fazer o trabalho pesado.

@JKP:

Nem todas as funções no MacOS X aceitam UTF8, mas nomes de arquivos e caminhos de arquivos podem ser UTF8, assim todas as funções POSIX que lidam com access a arquivos (open, fopen, stat, etc.) aceitam UTF8.

Veja aqui Citar:

A aparência de um nome de arquivo no nível da API depende da API. As APIs atuais do Carbon tratam nomes de arquivos como uma matriz de caracteres UTF-16; Os POSIX os manipulam como uma matriz de UTF-8, e é por isso que o UTF-8 funciona bem no Terminal. Como ele é armazenado no disco depende do formato do disco; O HFS + usa o UTF-16, mas isso não é importante na maioria dos casos.

Algumas outras funções POSIX também lidam com o UTF8. Por exemplo, funções que lidam com nomes de usuários, nomes de grupos ou senhas de usuários usam o UTF8 para armazenar as informações (assim, um nome de usuário pode ser japonês e sua senha pode ser em chinês, sem problemas).

Mas nem todos lidam com UTF8. Por exemplo, para todas as funções de string, uma string UTF8 é apenas uma String C normal e os caracteres acima de 126 não têm significado especial. Eles não entendem o conceito de múltiplos bytes (caracteres em C) formando um único caractere Unicode. Como outras APIs manipulam o char * pointer sendo passado para elas é diferente da API para a API. No entanto, como regra geral, como o polegar você pode dizer:

A function só aceita strings C com caracteres ASCII puros (somente no intervalo de 0 a 126) ou aceitará UTF8. Normalmente, as funções não permitem caracteres acima de 126 e as interpretam em qualquer outra codificação que não seja UTF8. Se este foi realmente o caso, está documentado e, em seguida, deve haver uma maneira de passar a codificação junto com a seqüência de caracteres.

Se você estiver usando o Cocoa, é bastante fácil com o NSString. Basta carregar os dados UTF16 usando -initWithBytes: length: encoding: (ou talvez -initWithCString: encoding 🙂 e, em seguida, obter uma versão UTF8 chamando UTF8String no resultado. Então, basta chamar fopen com sua nova string UTF8 como o param.

Você pode definitivamente chamar fopen com uma string UTF-8, independentemente do idioma – não pode ajudar com C ++ no OSX – desculpe.

Eu li o nome do arquivo da configuração do arquivo UTF8 através do wifstream (ele usa o buffer wchar_t ).

A implementação do Mac é diferente do Linux e do Windows. wifstream lê cada byte do arquivo para separar a célula wchar_t no buffer. Portanto, temos 3 bytes vazios, embora a abertura exija uma string char . Assim, o programador pode usar a function wcstombs para converter uma cadeia de caracteres ampla em uma cadeia de múltiplos bytes.

A API suporta UTF8. Para entender melhor, use o watcher de memory e o editor hexadecimal para o seu arquivo.