wcout, VS2008 and UTF-16
Greetings.
I'm am currently trying to output wchar_t (== UTF-16) to the windows
console. (The console can display UTF_16 just fine if you change the
font to lucida console - easiest verified with adding a filename with
some greek or cyrillic characters in it and calling dir)
Now, my problem is, that the default wcout stream on windows will
convert wchar_t characters to multibyte.
One can overcome this by adding codecvt like described here:
http://www.ddj.com/cpp/184403638;jsessionid=ADO5UI2ASFTGBQE1GHOSKHWATMY32JVN?pgno=1
However, this only works for binary streams.
The reason that it does not work with wcout is that
basic_filebuf<wchar_t, ..> , on which wcout is based will use fputwc(..)
internally. This function will still try to convert the wchar_t to
multibyte unless the stream is opened in binary mode.
So ... is it possible at all to get wcout to send full UTF-16 to the
console?
thanks,
Martin
Test code:
main.cpp
########
#include "stdafx.h"
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <locale>
using std::codecvt ;
typedef codecvt < wchar_t , char , mbstate_t > NullCodecvtBase ;
class NullCodecvt : public NullCodecvtBase
{
public:
typedef wchar_t elem_t;
typedef char outp_t;
typedef mbstate_t state_t;
explicit NullCodecvt(size_t r=0 ) : NullCodecvtBase(r) { }
protected:
virtual result do_in(state_t& /* conversion state */,
const outp_t* /* begin convert */,
const outp_t* /* end convert */,
const outp_t*& /* next convert */,
elem_t* /* begin converted */,
elem_t* /* end converted */,
elem_t*& /* next converted */) const {
return noconv ;
}
virtual result do_out(state_t& ,
const elem_t* ,
const elem_t* ,
const elem_t*& ,
outp_t* ,
elem_t* ,
outp_t*& ) const {
return noconv ;
}
virtual result do_unshift(state_t& ,
outp_t* ,
outp_t* ,
outp_t*& ) const {
return noconv ;
}
virtual int do_length(state_t& ,
const outp_t* _F1,
const outp_t* _L1,
size_t _N2) const _THROW0() {
return (_N2 < (size_t)(_L1 - _F1)) ? _N2 : _L1 - _F1 ;
}
virtual bool do_always_noconv() const _THROW0() {
return true ;
}
virtual int do_max_length() const _THROW0() {
return 2 ;
}
virtual int do_encoding() const _THROW0() {
return 2 ;
}
};
int main()
{
using namespace std;
try {
// --- init locale ---
const char* locale_id = "german_Germany";
setlocale(LC_ALL, locale_id); // Need to set C locale for fputwc
conversions
std::locale newloc(std::locale(locale_id), new NullCodecvt());
std::locale::global( newloc );
// --- try with wofstream ---
wofstream f;
f.exceptions( ios::badbit | ios::failbit | ios::eofbit );
f.imbue( newloc );
// wchar_t output requires binary output !! (otherwise fputwc fails to
write non-basic wchar_t characters)
f.open("testuni.txt", ios_base::out | ios_base::binary);
// Output works just fine on a Latin1 Windows (e.g. german)
// (But note that we need to supply \r\n for a binary file)
f << L"aAbB ... ???? ... ? ? ? ...\r\n";
f << L"\u03C9 (greek omega) \r\n";
f.close();
// --- try with wcout ---
wcout.exceptions( ios::badbit | ios::failbit | ios::eofbit );
wcout.imbue( newloc );
wcout << L"aAbB ... ???? ... ? ? ? ...\n"; // Works just fine on
(Latin1 charset)
wcout << L"\u03C9 (greek omega) \n"; // Will set badbit, since fputwc
fails
} catch(std::exception const& e) {
cerr << "X!: " << e.what() << endl;
return 1;
}
return 0;
}