Updated nowide to fix crashing on Windows (#523)

This was apparent on calling nowide:cout to null device
This commit is contained in:
Radek Dutkiewicz
2018-12-20 22:17:15 -08:00
committed by Andrew Mickelson
parent 1cb3b9d6e1
commit f08fb014ec
12 changed files with 149 additions and 148 deletions
+3 -3
View File
@@ -77,12 +77,12 @@ namespace details {
wchar_t *out = wbuffer_;
uf::code_point c;
size_t decoded = 0;
while(p < e && (c = uf::utf_traits<char>::decode(p,e))!=uf::illegal && c!=uf::incomplete) {
while(p < e && (c = uf::utf_traits<char>::decode(p,e))!=uf::incomplete) {
if(c == uf::illegal)
c = NOWIDE_REPLACEMENT_CHARACTER;
out = uf::utf_traits<wchar_t>::encode(c,out);
decoded = p-b;
}
if(c==uf::illegal)
return -1;
if(!WriteConsoleW(handle_,wbuffer_,out - wbuffer_,&size,0))
return -1;
return decoded;
+11 -17
View File
@@ -95,13 +95,8 @@ namespace nowide {
try{
args_.resize(wargc+1,0);
arg_values_.resize(wargc);
for(int i=0;i<wargc;i++) {
if(!arg_values_[i].convert(wargv[i])) {
wargc = i;
break;
}
args_[i] = arg_values_[i].c_str();
}
for(int i=0;i<wargc;i++)
args_[i] = arg_values_[i].convert(wargv[i]);
argc = wargc;
argv = &args_[0];
}
@@ -123,17 +118,16 @@ namespace nowide {
int count = 0;
for(wstrings_end = wstrings;*wstrings_end;wstrings_end+=wcslen(wstrings_end)+1)
count++;
if(env_.convert(wstrings,wstrings_end)) {
envp_.resize(count+1,0);
char *p=env_.c_str();
int pos = 0;
for(int i=0;i<count;i++) {
if(*p!='=')
envp_[pos++] = p;
p+=strlen(p)+1;
}
en = &envp_[0];
env_.convert(wstrings,wstrings_end);
envp_.resize(count+1,0);
char *p=env_.c_str();
int pos = 0;
for(int i=0;i<count;i++) {
if(*p!='=')
envp_[pos++] = p;
p+=strlen(p)+1;
}
en = &envp_[0];
}
catch(...) {
FreeEnvironmentStringsW(wstrings);
+8 -19
View File
@@ -36,9 +36,7 @@ namespace nowide {
{
static stackstring value;
wshort_stackstring name;
if(!name.convert(key))
return 0;
wshort_stackstring name(key);
static const size_t buf_size = 64;
wchar_t buf[buf_size];
@@ -55,8 +53,7 @@ namespace nowide {
return 0;
ptr = &tmp[0];
}
if(!value.convert(ptr))
return 0;
value.convert(ptr);
return value.c_str();
}
///
@@ -67,17 +64,13 @@ namespace nowide {
///
inline int setenv(char const *key,char const *value,int override)
{
wshort_stackstring name;
if(!name.convert(key))
return -1;
wshort_stackstring name(key);
if(!override) {
wchar_t unused[2];
if(!(GetEnvironmentVariableW(name.c_str(),unused,2)==0 && GetLastError() == 203)) // ERROR_ENVVAR_NOT_FOUND
return 0;
}
wstackstring wval;
if(!wval.convert(value))
return -1;
wstackstring wval(value);
if(SetEnvironmentVariableW(name.c_str(),wval.c_str()))
return 0;
return -1;
@@ -87,9 +80,7 @@ namespace nowide {
///
inline int unsetenv(char const *key)
{
wshort_stackstring name;
if(!name.convert(key))
return -1;
wshort_stackstring name(key);
if(SetEnvironmentVariableW(name.c_str(),0))
return 0;
return -1;
@@ -106,12 +97,10 @@ namespace nowide {
if(*key_end == '\0')
return -1;
wshort_stackstring wkey;
if(!wkey.convert(key,key_end))
return -1;
wstackstring wvalue;
if(!wvalue.convert(key_end+1))
return -1;
wkey.convert(key,key_end);
wvalue.convert(key_end+1);
if(SetEnvironmentVariableW(wkey.c_str(),wvalue.c_str()))
return 0;
-10
View File
@@ -17,16 +17,6 @@
#define NOWIDE_MSVC
#endif
#ifdef NOWIDE_WINDOWS
# if defined(DLL_EXPORT) || defined(NOWIDE_EXPORT)
# ifdef NOWIDE_SOURCE
# define NOWIDE_DECL __declspec(dllexport)
# else
# define NOWIDE_DECL __declspec(dllimport)
# endif //NOWIDE_SOURCE
# endif // DYN_LINK
#endif
#ifndef NOWIDE_DECL
# define NOWIDE_DECL
#endif
+63 -12
View File
@@ -10,6 +10,7 @@
#include <string>
#include <nowide/encoding_utf.hpp>
#include <nowide/replacement.hpp>
namespace nowide {
@@ -19,8 +20,8 @@ namespace nowide {
///
/// In case of success a NULL terminated string is returned (buffer), otherwise 0 is returned.
///
/// If there is not enough room in the buffer or the source sequence contains invalid UTF,
/// 0 is returned, and the contents of the buffer are undefined.
/// If there is not enough room in the buffer 0 is returned, and the contents of the buffer are undefined.
/// Any illegal sequences are replaced with U+FFFD substutution charracter
///
template<typename CharOut,typename CharIn>
CharOut *basic_convert(CharOut *buffer,size_t buffer_size,CharIn const *source_begin,CharIn const *source_end)
@@ -33,8 +34,7 @@ namespace nowide {
using namespace nowide::utf;
code_point c = utf_traits<CharIn>::template decode<CharIn const *>(source_begin,source_end);
if(c==illegal || c==incomplete) {
rv = 0;
break;
c = NOWIDE_REPLACEMENT_CHARACTER;
}
size_t width = utf_traits<CharOut>::width(c);
if(buffer_size < width) {
@@ -48,6 +48,32 @@ namespace nowide {
return rv;
}
///
/// \brief Template function that converts a buffer of UTF sequences in range [source_begin,source_end) and returns a string containing converted value
///
/// Any illegal sequences are replaced with U+FFFD substutution charracter
///
template<typename CharOut,typename CharIn>
std::basic_string<CharOut>
basic_convert(CharIn const *begin,CharIn const *end)
{
std::basic_string<CharOut> result;
result.reserve(end-begin);
typedef std::back_insert_iterator<std::basic_string<CharOut> > inserter_type;
inserter_type inserter(result);
using namespace nowide::utf;
code_point c;
while(begin!=end) {
c=utf_traits<CharIn>::template decode<CharIn const *>(begin,end);
if(c==illegal || c==incomplete) {
c=NOWIDE_REPLACEMENT_CHARACTER;
}
utf_traits<CharOut>::template encode<inserter_type>(c,inserter);
}
return result;
}
/// \cond INTERNAL
namespace details {
//
@@ -62,6 +88,31 @@ namespace nowide {
}
}
/// \endcond
///
/// \brief Template function that converts a string \a s from one type of UTF to another UTF and returns a string containing converted value
///
/// Any illegal sequences are replaced with U+FFFD substutution charracter
///
template<typename CharOut,typename CharIn>
std::basic_string<CharOut>
basic_convert(std::basic_string<CharIn> const &s)
{
return basic_convert<CharOut>(s.c_str(),s.c_str()+s.size());
}
///
/// \brief Template function that converts a string \a s from one type of UTF to another UTF and returns a string containing converted value
///
/// Any illegal sequences are replaced with U+FFFD substutution charracter
///
template<typename CharOut,typename CharIn>
std::basic_string<CharOut>
basic_convert(CharIn const *s)
{
return basic_convert<CharOut>(s,details::basic_strend(s));
}
///
/// Convert NULL terminated UTF source string to NULL terminated \a output string of size at
@@ -112,38 +163,38 @@ namespace nowide {
///
/// Convert between Wide - UTF-16/32 string and UTF-8 string.
///
/// nowide::conv::conversion_error is thrown in a case of a error
/// boost::locale::conv::conversion_error is thrown in a case of a error
///
inline std::string narrow(wchar_t const *s)
{
return nowide::conv::utf_to_utf<char>(s);
return basic_convert<char>(s);
}
///
/// Convert between UTF-8 and UTF-16 string, implemented only on Windows platform
///
/// nowide::conv::conversion_error is thrown in a case of a error
/// boost::locale::conv::conversion_error is thrown in a case of a error
///
inline std::wstring widen(char const *s)
{
return nowide::conv::utf_to_utf<wchar_t>(s);
return basic_convert<wchar_t>(s);
}
///
/// Convert between Wide - UTF-16/32 string and UTF-8 string
///
/// nowide::conv::conversion_error is thrown in a case of a error
/// boost::locale::conv::conversion_error is thrown in a case of a error
///
inline std::string narrow(std::wstring const &s)
{
return nowide::conv::utf_to_utf<char>(s);
return basic_convert<char>(s);
}
///
/// Convert between UTF-8 and UTF-16 string, implemented only on Windows platform
///
/// nowide::conv::conversion_error is thrown in a case of a error
/// boost::locale::conv::conversion_error is thrown in a case of a error
///
inline std::wstring widen(std::string const &s)
{
return nowide::conv::utf_to_utf<wchar_t>(s);
return basic_convert<wchar_t>(s);
}
} // nowide
+6 -30
View File
@@ -33,59 +33,35 @@ namespace nowide {
///
/// \brief Same as freopen but file_name and mode are UTF-8 strings
///
/// If invalid UTF-8 given, NULL is returned and errno is set to EINVAL
///
inline FILE *freopen(char const *file_name,char const *mode,FILE *stream)
{
wstackstring wname;
wshort_stackstring wmode;
if(!wname.convert(file_name) || !wmode.convert(mode)) {
errno = EINVAL;
return 0;
}
wstackstring wname(file_name);
wshort_stackstring wmode(mode);
return _wfreopen(wname.c_str(),wmode.c_str(),stream);
}
///
/// \brief Same as fopen but file_name and mode are UTF-8 strings
///
/// If invalid UTF-8 given, NULL is returned and errno is set to EINVAL
///
inline FILE *fopen(char const *file_name,char const *mode)
{
wstackstring wname;
wshort_stackstring wmode;
if(!wname.convert(file_name) || !wmode.convert(mode)) {
errno = EINVAL;
return 0;
}
wstackstring wname(file_name);
wshort_stackstring wmode(mode);
return _wfopen(wname.c_str(),wmode.c_str());
}
///
/// \brief Same as rename but old_name and new_name are UTF-8 strings
///
/// If invalid UTF-8 given, -1 is returned and errno is set to EINVAL
///
inline int rename(char const *old_name,char const *new_name)
{
wstackstring wold,wnew;
if(!wold.convert(old_name) || !wnew.convert(new_name)) {
errno = EINVAL;
return -1;
}
wstackstring wold(old_name),wnew(new_name);
return _wrename(wold.c_str(),wnew.c_str());
}
///
/// \brief Same as rename but name is UTF-8 string
///
/// If invalid UTF-8 given, -1 is returned and errno is set to EINVAL
///
inline int remove(char const *name)
{
wstackstring wname;
if(!wname.convert(name)) {
errno = EINVAL;
return -1;
}
wstackstring wname(name);
return _wremove(wname.c_str());
}
#endif
+10 -11
View File
@@ -50,7 +50,7 @@ namespace nowide {
/// Creates new filebuf
///
basic_filebuf() :
buffer_size_(4),
buffer_size_(BUFSIZ),
buffer_(0),
file_(0),
own_(true),
@@ -93,11 +93,9 @@ namespace nowide {
wchar_t const *smode = get_mode(mode);
if(!smode)
return 0;
wstackstring name;
if(!name.convert(s))
return 0;
wstackstring name(s);
#ifdef NOWIDE_FSTREAM_TESTS
FILE *f = ::fopen(s,nowide::convert(smode).c_str());
FILE *f = ::fopen(s,nowide::narrow(smode).c_str());
#else
FILE *f = ::_wfopen(name.c_str(),smode);
#endif
@@ -260,13 +258,14 @@ namespace nowide {
}
last_char_ = c;
setg(&last_char_,&last_char_,&last_char_ + 1);
return c;
}
make_buffer();
size_t n = ::fread(buffer_,1,buffer_size_,file_);
setg(buffer_,buffer_,buffer_+n);
if(n == 0)
return EOF;
else {
make_buffer();
size_t n = ::fread(buffer_,1,buffer_size_,file_);
setg(buffer_,buffer_,buffer_+n);
if(n == 0)
return EOF;
}
return std::char_traits<char>::to_int_type(*gptr());
}
+16
View File
@@ -0,0 +1,16 @@
//
// Copyright (c) 2018 Artyom Beilis (Tonkikh)
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef NOWIDE_REPLACEMENT_HPP_INCLUDED
#define NOWIDE_REPLACEMENT_HPP_INCLUDED
#ifndef NOWIDE_REPLACEMENT_CHARACTER
#define NOWIDE_REPLACEMENT_CHARACTER 0xFFFD
#endif
#endif // boost/nowide/replacement.hpp
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
+14 -14
View File
@@ -20,6 +20,8 @@ namespace nowide {
///
/// It uses on stack buffer of the string is short enough
/// and allocated a buffer on the heap if the size of the buffer is too small
///
/// If invalid UTF charracters are detected they are replaced with U+FFFD substutution charracter
///
template<typename CharOut=wchar_t,typename CharIn = char,size_t BufferSize = 256>
class basic_stackstring {
@@ -30,7 +32,7 @@ public:
typedef CharIn input_char;
basic_stackstring(basic_stackstring const &other) :
mem_buffer_(0)
mem_buffer_(0)
{
clear();
if(other.mem_buffer_) {
@@ -63,30 +65,28 @@ public:
basic_stackstring() : mem_buffer_(0)
{
}
bool convert(input_char const *input)
basic_stackstring(input_char const *input) : mem_buffer_(0)
{
return convert(input,details::basic_strend(input));
convert(input);
}
bool convert(input_char const *begin,input_char const *end)
output_char *convert(input_char const *input)
{
convert(input,details::basic_strend(input));
return c_str();
}
output_char *convert(input_char const *begin,input_char const *end)
{
clear();
size_t space = get_space(sizeof(input_char),sizeof(output_char),end - begin) + 1;
if(space <= buffer_size) {
if(basic_convert(buffer_,buffer_size,begin,end))
return true;
clear();
return false;
basic_convert(buffer_,buffer_size,begin,end);
}
else {
mem_buffer_ = new output_char[space];
if(!basic_convert(mem_buffer_,space,begin,end)) {
clear();
return false;
}
return true;
basic_convert(mem_buffer_,space,begin,end);
}
return c_str();
}
output_char *c_str()
{
+1 -7
View File
@@ -23,17 +23,11 @@ using ::system;
///
/// Same as std::system but cmd is UTF-8.
///
/// If the input is not valid UTF-8, -1 returned and errno set to EINVAL
///
inline int system(char const *cmd)
{
if(!cmd)
return _wsystem(0);
wstackstring wcmd;
if(!wcmd.convert(cmd)) {
errno = EINVAL;
return -1;
}
wstackstring wcmd(cmd);
return _wsystem(wcmd.c_str());
}
+17 -18
View File
@@ -10,6 +10,7 @@
#include <nowide/utf.hpp>
#include <nowide/cstdint.hpp>
#include <nowide/replacement.hpp>
#include <nowide/static_assert.hpp>
#include <locale>
@@ -84,7 +85,10 @@ protected:
while(max > 0 && from < from_end){
char const *prev_from = from;
nowide::uint32_t ch=nowide::utf::utf_traits<char>::decode(from,from_end);
if(ch==nowide::utf::incomplete || ch==nowide::utf::illegal) {
if(ch==nowide::utf::illegal) {
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
else if(ch==nowide::utf::incomplete) {
from = prev_from;
break;
}
@@ -136,11 +140,9 @@ protected:
uint32_t ch=nowide::utf::utf_traits<char>::decode(from,from_end);
if(ch==nowide::utf::illegal) {
from = from_saved;
r=std::codecvt_base::error;
break;
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
if(ch==nowide::utf::incomplete) {
else if(ch==nowide::utf::incomplete) {
from = from_saved;
r=std::codecvt_base::partial;
break;
@@ -241,9 +243,7 @@ protected:
ch=((uint32_t(vh) << 10) | vl) + 0x10000;
}
else {
// Invalid surrogate
r=std::codecvt_base::error;
break;
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
}
else {
@@ -261,8 +261,7 @@ protected:
// if we observe second surrogate pair and
// first only may be expected we should break from the loop with error
// as it is illegal input
r=std::codecvt_base::error;
break;
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
}
if(!nowide::utf::is_valid_codepoint(ch)) {
@@ -354,10 +353,13 @@ protected:
while(max > 0 && from < from_end){
char const *save_from = from;
nowide::uint32_t ch=nowide::utf::utf_traits<char>::decode(from,from_end);
if(ch==nowide::utf::incomplete || ch==nowide::utf::illegal) {
if(ch==nowide::utf::incomplete) {
from = save_from;
break;
}
else if(ch == nowide::utf::illegal) {
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
max--;
}
#ifndef NOWIDE_DO_LENGTH_MBSTATE_CONST
@@ -396,11 +398,9 @@ protected:
uint32_t ch=nowide::utf::utf_traits<char>::decode(from,from_end);
if(ch==nowide::utf::illegal) {
r=std::codecvt_base::error;
from = from_saved;
break;
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
if(ch==nowide::utf::incomplete) {
else if(ch==nowide::utf::incomplete) {
r=std::codecvt_base::partial;
from=from_saved;
break;
@@ -434,7 +434,7 @@ protected:
}
virtual std::codecvt_base::result
do_out( std::mbstate_t &std_state,
do_out( std::mbstate_t &/*std_state*/,
uchar const *from,
uchar const *from_end,
uchar const *&from_next,
@@ -453,8 +453,7 @@ protected:
nowide::uint32_t ch=0;
ch = *from;
if(!nowide::utf::is_valid_codepoint(ch)) {
r=std::codecvt_base::error;
break;
ch = NOWIDE_REPLACEMENT_CHARACTER;
}
int len = nowide::utf::utf_traits<char>::width(ch);
if(to_end - to < len) {
-7
View File
@@ -10,10 +10,6 @@
#include <stddef.h>
#ifdef NOWIDE_USE_WINDOWS_H
#include <windows.h>
#else
//
// These are function prototypes... Allow to to include windows.h
//
@@ -30,9 +26,6 @@ __declspec(dllimport) unsigned long __stdcall GetEnvironmentVariableW(wchar_t
}
#endif
#endif
///