2017-09-19 1 views
9

Voici un problème que je n'ai pas réussi à résoudre malgré tous mes efforts. Donc, je suis totalement coincé, s'il vous plaît aider!Wrong CRLF dans le flux UTF-16?

Pour régulier, le mode « ASCII » les sorties de fichiers et de flux simplifiés suivants

FILE *fa = fopen("utfOutFA.txt", "w"); 
fprintf(fa, "Line1\nLine2"); 
fclose(fa); 
ofstream sa("utfOutSA.txt"); 
sa << "Line1\nLine2"; 
sa.close(); 
résultat

, naturellement, exactement les mêmes fichiers texte (vidage hexadécimal):

00000000h: 4C 69 6E 65 31 0D 0A 4C 69 6E 65 32    ; Line1..Line2 

où le nouveau La ligne \n est développée en CRLF: 0D 0A - typique pour Windows. Maintenant, nous faisons de même pour la sortie Unicode, à savoir UTF-16 LE qui est une sorte de "défaut". Sortie fichier

FILE *fu = fopen("utfOutFU.txt", "w, ccs=UNICODE"); 
fwprintf(fu, L"Line1\nLine2"); 
fclose(fu); 

de ce contenu:

00000000h: FF FE 4C 00 69 00 6E 00 65 00 31 00 0D 00 0A 00 ; ÿþL.i.n.e.1..... 
00000010h: 4C 00 69 00 6E 00 65 00 32 00     ; L.i.n.e.2. 

qui semble parfaitement correct compte tenu de la nomenclature et boutisme, y compris CRLF: 0D 00 0A 00. Cependant, la sortie de flux similaire

wofstream su("utfOutSU.txt"); 
su.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t, 0x10ffffUL, 
          codecvt_mode(generate_header + little_endian)>)); 
su << L"Line1\nLine2"; 
su.close(); 

résultats dans un octet moins et le fichier global de texte incorrect:

00000000h: FF FE 4C 00 69 00 6E 00 65 00 31 00 0D 0A 00 4C ; ÿþL.i.n.e.1....L 
00000010h: 00 69 00 6E 00 65 00 32 00      ; .i.n.e.2. 

La raison est mauvaise expansion de CRLF: 0D 0A 00. Est-ce un bug? Ou ai-je fait quelque chose de mal? J'utilise le compilateur Microsoft Visual Studio (14.0 et autre). J'ai essayé d'utiliser le flux endl au lieu de \n - même résultat! J'ai essayé de mettre su.imbue() d'abord, puis su.open() - tout de même! J'ai également vérifié la sortie UTF-8 (ccs=UTF-8 pour le fichier et codecvt_utf8 pour le flux) - aucun problème CRLF reste le même que dans le mode ASCII: 0D 0A

J'apprécie des idées et des commentaires sur la question.

+0

Ceci est très probablement un bogue, car UTF-16 ne peut pas avoir un nombre impair d'octets. – CAF

Répondre

2

Lorsque vous ajoutez imbue() à un nouveau paramètre régional dans le std::wofstream, vous supprimez les paramètres régionaux d'origine. N'utilisez pas locale::empty(), utilisez plutôt su.getloc(), de sorte que le nouveau paramètre régional copie l'ancien paramètre régional avant de le modifier.

En outre, sur une note latérale, le dernier paramètre de modèle de codecvt_utf16 est un masque de bits, donc codecvt_mode(generate_header + little_endian) devrait être plutôt std::generate_header | std::little_endian à la place.

su.imbue(std::locale(su.getloc(), new codecvt_utf16<wchar_t, 0x10ffffUL, 
          std::generate_header | std::little_endian>)); 
+1

Il n'y a pas de différence entre '+' et '|' quand les bits de chaque opérande ne se chevauchent pas, mais votre point est bon. –

+0

Merci de m'avoir montré 'getloc()' - Je suis assez novice dans ce domaine. – lariona

+0

En ce qui concerne le mode codecvt, j'avais '|' à un stade précoce; puis l'a changé en '+' en luttant avec le compilateur 'erreur C2440: 'spécialisation': impossible de convertir 'int' en 'std :: codecvt_mode''; Il a finalement dû ajouter une distribution explicite, mais a négligé de la remplacer par '|'. Merci quand même. – lariona