9
votes

Utilisation de zlib avec des chemins de fichier unicode sur Windows

Je lis, je lisez des fichiers compressés gzip en utilisant zlib. Ensuite, vous ouvrez un fichier en utilisant xxx

Comment gérez-vous des chemins de fichiers unicode stockés sous forme const wchar_t * sous Windows?

sur UNIX -Les plates-formes simples, vous pouvez simplement convertir le chemin de fichier en UTF-8 et appeler gzopen (), Mais cela ne fonctionnera pas sur Windows.


13 commentaires

Pas sûr, mais je m'attendrais à ce que cela accepte UTF8, de sorte que vous puissiez convertir votre UTF16 en UTF8 et transmettre le résultat comme char * .


Avez-vous essayé d'utiliser wcstombs ou iconv ?


@Appleman: sur Windows WCSTOMBS sera au moins par défaut, convertira la chaîne à Windows-1252. Les caractères qui ne peuvent pas être représentés comme Windows-1252 seront remplacés par divers caractères de substitution. Si cela se produit, la chaîne convertie ne peut pas être utilisée comme chemin de fichier.


C'est ce que le client SVN de la console sous Windows fait, apparemment. Et cela rend le travail avec des noms de fichiers unicodes vraiment douloureux;)


Difficile de voir ce problème, c'est un problème pour le gars qui créé le fichier gzip. Les noms de fichiers sont codés dans ISO 8859-1. Ou quelle que soit l'application utilisée qui a créé le fichier, un problème courant.


@Hans Passant: J'écris une bibliothèque dont l'interface prend un chemin de fichier en tant que Soost :: FileSystem :: Path et dont la mise en œuvre peut lire le fichier à l'aide de la bibliothèque ZLIB. Ensuite, c'est un problème.


Donc, convertissez simplement la corde de large en étroit. ICU par exemple.


@Hans Passant: étroit avec ce qui codant? Le codage par défaut sur Windows pour chaînes étroites est Windows-1252 et qui ne fonctionnera pas. Il ne peut pas gérer la plupart des points de code ci-dessus 0xFF.


Citation: "Les noms de fichiers sont codés dans ISO 8859-1".


@Hans Passant: Je lis ça, mais je n'ai pas compris ce que tu veux dire. Je peux créer des fichiers sur mon ordinateur Windows avec des noms tels que "黒 .txt". Et je peux ouvrir ce fichier en passant son nom (en tant que chaîne large codée UTF-16) à _wfopen (...)


@Hans Passant: Comment ifil irait "黒 死 .txt" avec ISO 8859-1? De toute évidence, il me manque un peu d'informations. S'il vous plaît éclairer moi.


Encore une fois, c'est un problème pour le gars qui crée le gzip. Vous pouvez facilement supposer que GZIP n'est pas un format très populaire en Asie de l'Est.


Le problème est que certaines bibliothèques entre votre code et le système d'exploitation ont besoin d'un char * . (au moins c'est mon problème et pourquoi je suis ici aujourd'hui). Donc, il doit y avoir un moyen de faire wchar * → → [Lib Space] char * fopen → [espace OS] _wfopen < / code>, avec la finale _wfopen ayant une reconstruction de la chaîne d'origine. La question est donc de savoir quelle est la fonction inverse du toutf16 ? est-ce wcstombs ? Pendant la chaîne entre My-Code et My Space, il n'est pas nécessaire de pouvoir interpréter la chaîne sous forme de glyphes, des caractères non codables peuvent être conservés comme MBS et reconstruit par ToutF16.


5 Réponses :


4
votes

Vous avez les options suivantes

 #ifdef _WIN32 

 #define F_OPEN(name, mode) _wfopen((name), (mode))

 #endif    


2 commentaires

Quelqu'un peut-il aider à déchiffrer ce que ici Lien pointé sur?


La page ne semble pas être archivée sur archive.org, je pense que c'était un poste sur les anciens forums de développement BSNES, élaborant davantage sur le travail effectué sous l'élément de ligne - ZLIB modifié pour prendre en charge les caractères non-ANSI de BSNES Changelog. static.hexostum.net/bsnes/bsnes_changelog.txt



12
votes

Tout d'abord, ce que un nom de fichier?

Sur Unix systèmes

Un nom de fichier est une séquence d'octets terminé par zéro. Le noyau n'a pas besoin de se soucier de l'encodage des caractères (sauf pour connaître le code ASCII / ).

Cependant, il est plus pratique du point de vue des utilisateurs d'interpréter les noms de fichiers sous forme de séquences de caractères , et cela se fait par un caractère encodage spécifié dans le cadre de la locale . Unicode est pris en charge en faisant UTF-8 locales disponibles .

Dans les programmes C, les fichiers sont représentés avec ordinaire char * chaînes dans des fonctions comme fopen . Il n'y a pas de version grand caractère de l'API Posix. Si vous avez un wchar_t * nom de fichier, vous devez explicitement le convertir en un char * .

Sous Windows NT

Un nom de fichier est une séquence d'unités de code UTF-16 . En fait, tous manipulation de chaînes dans Windows se fait en UTF-16 en interne.

Toutes les bibliothèques C (++) de Microsoft, y compris la bibliothèque d'exécution Visual C ++, utilisez la convention que char * chaînes sont dans l'héritage local spécifique "ANSI" page de code et le code < > wchar_t * chaînes sont en UTF-16. Et le char * fonctions ne sont que des enveloppes de compatibilité ascendante dans le nouveau wchar_t * fonctions.

Alors, si vous appelez MessageBoxA (hwnd, texte, légende, type) , qui est essentiellement le même que d'appeler MessageBoxW (hwnd, ToUTF16 (texte), ToUTF16 (légende), type) . Et lorsque vous appelez fopen (nom de fichier, Mode) , qui est comme _wfopen (ToUTF16 (nom de fichier), ToUTF16 (mode)) .

Notez que _wfopen est l'un des de nombreuses fonctions non standard C pour travailler avec wchar_t * chaînes . Et ce n'est pas seulement pour la commodité; ne peut pas utiliser le standard char * équivalent parce qu'ils vous limiter à la page de code "ANSI" (qui ne peut pas être UTF-8 ). Par exemple, dans un lieu de Windows 1252, vous ne pouvez pas (facilement) fopen le fichier שלום. C , parce qu'il n'y a aucun moyen de représenter ces personnages dans une étroite string.

Dans les bibliothèques multi-plateforme

Certaines approches typiques sont:

  1. Utiliser les fonctions standard C avec char * chaînes, et juste ne donnent pas un 💩 sur le support des caractères non-ANSI sous Windows.
  2. Utiliser char * chaînes mais les interpréter comme UTF-8 au lieu de la norme ANSI. Sous Windows, écriture wrapper fonctions qui prennent UTF-8 arguments, les convertir en UTF-16 et les fonctions d'appel comme _wfopen .
  3. Utilisez des chaînes de caractères large partout, ce qui est comme # 2 sauf que vous avez besoin d'écrire des fonctions wrapper pour non systèmes -Windows.

    Comment les noms de fichiers poignée zlib?

    Malheureusement, il semble utiliser l'approche naïve 1 ci-dessus, avec open (plutôt que _wopen ) utilisé directement.

    Comment pouvez-vous travailler autour d'elle?

    En plus des solutions déjà mentionnées (mon préféré qui est de Appleman1234 gzdopen suggestion), vous pouvez profiter de nom court .


5 commentaires

Il y a donc deux approches pour Zlib. Soit A) avoir gzopen () effectuez toujours la conversion UTF-8 à UTF-16 sur Windows et utilisez _wopen () ou b) laissez gzopen () comme utilise ouverte () et ajoutez une nouvelle fonction _wgzopen () uniquement sur Windows qui prend un argument UTF-16 et utilise _wopen (). Quelle serait la recommandation de DAN04?


@Mark: Vous ne devez pas vous demander si la bibliothèque GZIP doit utiliser ceci ou ce codage. La bibliothèque ne doit pas décider quel codage à utiliser. C'est la responsabilité de l'application qui utilise la bibliothèque. L'application fait généralement cela en définissant la locale actuelle. La bibliothèque doit simplement utiliser les codages spécifiés par la locale actuelle. Le moyen le plus simple de le faire est de déléguer aux fonctions sensibles aux paramètres régionaux existants, comme dans votre alternative B).


@Markadler: Pour ME , il serait plus pratique si Zlib a utilisé UTF-8, car c'est ce que la norme de codage de ma équipe nécessite (principalement pour des raisons de compatibilité avec d'autres bibliothèques tiers telles que SQLite et Tinyxml). Peut-être que vous pourriez fournir des versions UTF-8 et UTF-16 des fonctions.


D'accord. Donc, je pourrais faire les deux. gzopen () pourrait convertir de l'UTF-8 en UTF-16 et appeler _wopen lors de la compilation de Windows. Et il pourrait également y avoir un _wgzopen () qui utilise UTF-16 pour une entrée (pour les deux arguments?). Je ne reçois pas tout le "délégué aux fonctions de sensibilisation des paramètres régionaux existants". Cela signifie-t-il que la routine qui convertit de l'UTF-8 en UTF-16 n'est pas "au courant"? Au fait, quelle est cette routine?


@Markadler: Cette routine est MultiByteTowidechar () ou iconv () .



3
votes

Voici une implémentation de l'option N ° 2 de Appleman. Le code a été testé.

FILE* _wfopen(const wchar_t* filename, const wchar_t* mode);


3 commentaires

Testé cela avec la compilation Visual Studio 2010, dans le débogage, vous obtenez une exception lorsque l'application est sur le point de se terminer. Cela vient probablement parce que le fichier a été ouvert à l'aide de _wfopen, mais après cette poignée est fermée par _Close. Il est possible que vous puissiez obtenir une implémentation "sans danger" par DUP: la licence Fileno, puis fermez-la, mais j'ai joint ma propre implémentation de cette fonction ci-dessous.


Il y a une certaine bizarrerie lorsque cela est exécuté en application. L'application se termine bien, mais dans l'icône de la barre d'affaires, j'ai remarqué que certains bugs sont envoyés à Microsoft - c'est la première fois que je vois un rapport de bogue "silencieux". Rien n'est affiché pour mettre fin à l'utilisateur.


Débogué en VS2012 et après la fin de l'application se termine, une exception est affichée - vous essayez de mettre fin à l'application, mais le débogueur se bloque pendant une demi-minute. Également vs doit être redémarré après ce bogue.



14
votes

La prochaine version de ZLIB comprendra cette fonction où _win32 est #defined:

gzfile gzopen_w (const wchar_t * chemin, mode char *);

Il fonctionne exactement comme gzopen () , sauf qu'il utilise _wopen () au lieu de ouvert () . .

J'ai volontairement ne pas dupliquer le deuxième argument de _wfopen () et, par conséquent, je ne l'ai pas appelé _wgzopen () pour éviter toute confusion possible avec les arguments de cette fonction . D'où le nom gzopen_w () . Qui évite également l'utilisation de l'espace de nom réservé à C.


2 commentaires

Meilleur type de réponse. Vous demandez comment le faire et l'auteur de la bibliothèque est livré avec une nouvelle fonctionnalité.


@ Erkinalpgüney Je ne suis pas d'accord, une meilleure option consisterait à utiliser le suivi de la question. BTW: cette la version suivante était 1.2.7 (2 mai 2012) (voir Premier commis sur ce , il n'y a pas d'entrée correspondante dans le suivi de la question)



1
votes

Voici ma propre version de Unicode Helper Fonction, testée légèrement mieux que la version ci-dessus. XXX


3 commentaires

Mark a ajouté une prise en charge des noms de fichiers de caractères larges sur Windows aux versions récentes de ZLIB.


Je suis d'accord. Mais si vous avez déjà une bibliothèque de ZLIB et que vous ne voulez pas vous soucier de la ré-intégration de la nouvelle bibliothèque (compatibilité à l'envers, de nouvelles fonctionnalités, etc.) - Ensuite, il est plus facile d'envelopper existant.


Vous devez passer o_binary à _wopen dans tous les cas, non seulement si les données non compressées sont binaires, sinon elle corrompre toutes les 0x10 dans la sortie comprimée!