2008-08-15 15 views
16

Estoy buscando el equivalente de Windows _wfopen() bajo Mac OS X. ¿Alguna idea?_wfopen equivalente bajo Mac OS X

Necesito esto para portar una biblioteca de Windows que usa wchar* para su interfaz de archivo. Como se pretende que sea una biblioteca multiplataforma, no puedo confiar en cómo la aplicación cliente obtendrá la ruta del archivo y se la dará a la biblioteca.

Respuesta

14

La API POSIX en Mac OS X se puede usar con cadenas UTF-8. Para convertir una cadena wchar_t a UTF-8, es posible utilizar la infraestructura CoreFoundation desde Mac OS X.

Aquí hay una clase que ajustará una cadena generada en UTF-8 desde una cadena 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"); 

Esto funcionará para la lectura o escritura de archivos.

+0

si la eliminación es redundante, simplemente elimine – paulm

0

Si está utilizando Cocoa es bastante fácil con NSString. Simplemente cargue los datos UTF16 usando -initWithBytes: length: encoding: (o quizás -initWithCString: encoding :) y luego obtenga una versión UTF8 llamando a UTF8String en el resultado. Luego, solo llame a fopen con su nueva cadena UTF8 como parámetro.

Definitivamente puede llamar a fopen con una cadena UTF-8, independientemente del idioma; no obstante, no puede ayudar con C++ en OSX, lo siento.

+0

No estoy usando Cocoa y estoy usando C++, no Objective-C. Si está en lo cierto acerca de dar una cadena UTF-8 a fopen(), podría convertir mi cadena UTF-16 a UTF-8, pero ¿cómo es esto posible en Mac OS X (nuevamente usando C/C++)? –

+0

No es una respuesta definitiva ya que confío en CFString en lugar de NSString, pero la idea básica es la misma. Gracias. –

4

Simplemente desea abrir un identificador de archivo utilizando una ruta que puede contener caracteres Unicode, ¿verdad? Simplemente pase la ruta en representación del sistema de archivos a fopen.

  • Si la ruta de vino de las acciones marcos de Mac OS X (por ejemplo, un panel abierto si el carbono o el cacao), no tendrá que hacer ningún tipo de conversión en él y serán capaces de utilizarlo como -es.

  • Si se está generando parte de la ruta de usted, usted debe crear un CFStringRef de su camino y luego de que en la representación del sistema de ficheros para pasar a las API POSIX como open o fopen.

En general, no tendrá que hacer gran cantidad de eso para la mayoría de las aplicaciones. Por ejemplo, muchas aplicaciones pueden tener archivos de datos auxiliares almacenados en el directorio de soporte de aplicaciones del usuario, pero mientras los nombres de esos archivos sean ASCII, y use las API de Mac OS X estándar para localizar el directorio de soporte de aplicaciones del usuario, no necesita hacer un montón de conversión paranoica de una ruta construida con esos dos componentes.

Editado para agregar: quisiera advertir fuertemente contra arbitrariamente convertir todo a UTF-8 usando algo como wcstombs porque el sistema de archivos de codificación no es necesariamente idéntico a la UTF-8 generada. Tanto Mac OS X como Windows usan reglas de descomposición canónicas específicas (pero diferentes) para la codificación utilizada en las rutas del sistema de archivos.

Por ejemplo, deben decidir si "é" se almacenará como una o dos unidades de código (ya sea LATIN SMALL LETTER E WITH ACUTE o LATIN SMALL LETTER E seguido de COMBINING ACUTE ACCENT). Esto dará como resultado dos secuencias de bytes diferentes y de longitud diferente, y tanto Mac OS X como Windows funcionan para evitar colocar múltiples archivos con el mismo nombre (como el usuario los percibe) en el mismo directorio.

Las reglas sobre cómo realizar esta descomposición canónica pueden ser bastante complicadas, por lo que, en lugar de tratar de implementarlo por sí mismo, es mejor dejar las funciones que el sistema ha proporcionado para que realice el trabajo pesado.

2

@JKP:

No todas las funciones en MacOS X aceptan UTF8, pero los nombres de archivo y rutas de los archivos puede ser UTF-8, por lo tanto todas las funciones POSIX se ocupan de acceso a archivos (abrir, fopen, estadísticas, etc.) aceptan UTF8.

Ver here. Cita:

El nombre de un archivo se ve en el nivel API depende de la API. Las API actuales de Carbon manejan nombres de archivos como una matriz de caracteres UTF-16; POSIX maneja como una matriz de UTF-8, que es por qué UTF-8 funciona bien en la Terminal. Cómo se almacena en el disco depende del formato de disco ; HFS + usa UTF-16, pero eso no es importante en la mayoría de los casos.

Algunas otras funciones POSIX también manejan UTF8. P.ej. las funciones relacionadas con nombres de usuario, nombres de grupo o contraseñas de usuario utilizan UTF8 para almacenar la información (por lo tanto, un nombre de usuario puede ser japonés y su contraseña puede ser china, no hay problema).

Pero no todos los controladores UTF8. P.ej. para todas las funciones de cadena, una cadena UTF8 es simplemente una cadena C normal y los caracteres superiores a 126 no tienen ningún significado especial. No entienden el concepto de múltiples bytes (caracteres en C) que forman un único carácter Unicode. La manera en que otras API manejan el puntero char * que se les pasa es diferente de API a API. Sin embargo, como regla general, puede decir:

O bien la función solo acepta cadenas C con caracteres ASCII puros (solo en el rango de 0 a 126) o aceptará UTF8. Por lo general, las funciones no permiten caracteres por encima de 126 e interpretarlos en cualquier otra codificación que no sea UTF8. Si este fue realmente el caso, está documentado y luego debe haber una forma de pasar la codificación junto con la cadena.

0

He leído nombre de archivo del archivo de configuración a través UTF8 wifstream (utiliza wchar_t buffer).

La implementación de Mac es diferente de Linux y Windows. wifstream lee cada byte del archivo para separar la celda wchar_t en el búfer. Así que tenemos 3 bytes vacíos, aunque abierto requiere cadena de caracteres. Por lo tanto, el programador puede usar la función wcstombs para convertir cadenas de caracteres anchos a cadenas de bytes múltiples.

La API admite UTF8. Para una mejor comprensión use el vigilante de memoria y el editor hexadecimal para su archivo.