Commit f069db91 authored by Dāvis Mosāns's avatar Dāvis Mosāns Committed by Brad King

Encoding: Fix conversion of strings that contain null bytes

The `std::string` and `std::wstring` types are allowed to contain null
(`0`) bytes.  Teach Encoding::{ToNarrow,ToWide} to preserve them.

Change-Id: If9ddb77d275c1365016f2f1fa811d0c06e46d5f2
parent d94f92f7
......@@ -879,7 +879,7 @@ ENDIF()
IF(KWSYS_USE_Encoding)
# Set default 8 bit encoding in "EndcodingC.c".
SET_PROPERTY(SOURCE EncodingC.c APPEND PROPERTY COMPILE_DEFINITIONS
SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS
KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
ENDIF()
......
......@@ -125,12 +125,68 @@ char const* const* Encoding::CommandLineArguments::argv() const
std::wstring Encoding::ToWide(const std::string& str)
{
return ToWide(str.c_str());
std::wstring wstr;
#if defined(_WIN32)
const int wlength = MultiByteToWideChar(
KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), int(str.size()), NULL, 0);
if (wlength > 0) {
wchar_t* wdata = new wchar_t[wlength];
int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(),
int(str.size()), wdata, wlength);
if (r > 0) {
wstr = std::wstring(wdata, wlength);
}
delete[] wdata;
}
#else
size_t pos = 0;
size_t nullPos = 0;
do {
if (pos < str.size() && str.at(pos) != '\0') {
wstr += ToWide(str.c_str() + pos);
}
nullPos = str.find('\0', pos);
if (nullPos != str.npos) {
pos = nullPos + 1;
wstr += wchar_t('\0');
}
} while (nullPos != str.npos);
#endif
return wstr;
}
std::string Encoding::ToNarrow(const std::wstring& str)
{
return ToNarrow(str.c_str());
std::string nstr;
#if defined(_WIN32)
int length =
WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
int(str.size()), NULL, 0, NULL, NULL);
if (length > 0) {
char* data = new char[length];
int r =
WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(),
int(str.size()), data, length, NULL, NULL);
if (r > 0) {
nstr = std::string(data, length);
}
delete[] data;
}
#else
size_t pos = 0;
size_t nullPos = 0;
do {
if (pos < str.size() && str.at(pos) != '\0') {
nstr += ToNarrow(str.c_str() + pos);
}
nullPos = str.find(wchar_t('\0'), pos);
if (nullPos != str.npos) {
pos = nullPos + 1;
nstr += '\0';
}
} while (nullPos != str.npos);
#endif
return nstr;
}
std::wstring Encoding::ToWide(const char* cstr)
......
......@@ -9,6 +9,7 @@
#include KWSYS_HEADER(Encoding.hxx)
#include KWSYS_HEADER(Encoding.h)
#include <algorithm>
#include <iostream>
#include <locale.h>
#include <stdlib.h>
......@@ -124,6 +125,35 @@ static int testRobustEncoding()
return ret;
}
static int testWithNulls()
{
int ret = 0;
std::vector<std::string> strings;
strings.push_back(std::string("ab") + '\0' + 'c');
strings.push_back(std::string("d") + '\0' + '\0' + 'e');
strings.push_back(std::string() + '\0' + 'f');
strings.push_back(std::string() + '\0' + '\0' + "gh");
strings.push_back(std::string("ij") + '\0');
strings.push_back(std::string("k") + '\0' + '\0');
strings.push_back(std::string("\0\0\0\0", 4) + "lmn" +
std::string("\0\0\0\0", 4));
for (std::vector<std::string>::iterator it = strings.begin();
it != strings.end(); ++it) {
std::wstring wstr = kwsys::Encoding::ToWide(*it);
std::string str = kwsys::Encoding::ToNarrow(wstr);
std::string s(*it);
std::replace(s.begin(), s.end(), '\0', ' ');
std::cout << "'" << s << "' (" << it->size() << ")" << std::endl;
if (str != *it) {
std::replace(str.begin(), str.end(), '\0', ' ');
std::cout << "string with null was different: '" << str << "' ("
<< str.size() << ")" << std::endl;
ret++;
}
}
return ret;
}
static int testCommandLineArguments()
{
int status = 0;
......@@ -165,6 +195,7 @@ int testEncoding(int, char* [])
ret |= testHelloWorldEncoding();
ret |= testRobustEncoding();
ret |= testCommandLineArguments();
ret |= testWithNulls();
return ret;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment