Unicode handling:

Removed the Perl dependencies on Encode, Encode::Locale and Unicode::Normalize.
Added dependency on boost::locale.
Added encode_path, decode_path, normalize_utf8 functions to Slic3r.xs

Slic3r.xs has been made mostly utf8 safe by using the boost::nowide library,
thanks to @alexrj for the idea.

Simplified the encode_path / decode_path stuff:
wxWidgets are unicode already, so there is no need to decode_path() from it.
Perl / win32 interfacing is non-unicode, so decode_path() is executed
on ARGV just at the beginning of the perl scripts.
This commit is contained in:
bubnikv 2017-08-03 17:31:31 +02:00
parent 31085fb1d7
commit 1385018724
33 changed files with 236 additions and 186 deletions

View file

@ -3,6 +3,8 @@
#include <string>
#include <expat/expat.h>
#include <boost/nowide/cstdio.hpp>
#include "../libslic3r.h"
#include "../Model.hpp"
#include "AMF.hpp"
@ -480,7 +482,7 @@ bool load_amf(const char *path, Model *model)
return false;
}
FILE *pFile = ::fopen(path, "rt");
FILE *pFile = boost::nowide::fopen(path, "rt");
if (pFile == nullptr) {
printf("Cannot open file %s\n", path);
return false;
@ -522,7 +524,7 @@ bool load_amf(const char *path, Model *model)
bool store_amf(const char *path, Model *model)
{
FILE *file = ::fopen(path, "wb");
FILE *file = boost::nowide::fopen(path, "wb");
if (file == nullptr)
return false;

View file

@ -2,6 +2,8 @@
#include <string.h>
#include <boost/nowide/convert.hpp>
#include <wx/string.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
@ -119,7 +121,14 @@ bool load_prus(const char *path, Model *model)
{
// To receive the content of the zipped 'scene.xml' file.
std::vector<char> scene_xml_data;
wxFFileInputStream in(path);
wxFFileInputStream in(
#ifdef WIN32
// On Windows, convert to a 16bit unicode string.
boost::nowide::widen(path).c_str()
#else
path
#endif
);
wxZipInputStream zip(in);
std::unique_ptr<wxZipEntry> entry;
size_t num_models = 0;

View file

@ -1,6 +1,8 @@
#include <stdlib.h>
#include <string.h>
#include <boost/nowide/cstdio.hpp>
#include "objparser.hpp"
namespace ObjParser {
@ -318,7 +320,7 @@ static bool obj_parseline(const char *line, ObjData &data)
bool objparse(const char *path, ObjData &data)
{
FILE *pFile = ::fopen(path, "rt");
FILE *pFile = boost::nowide::fopen(path, "rt");
if (pFile == 0)
return false;
@ -446,7 +448,7 @@ bool loadvectornameidx(FILE *pFile, std::vector<T> &v)
bool objbinsave(const char *path, const ObjData &data)
{
FILE *pFile = ::fopen(path, "wb");
FILE *pFile = boost::nowide::fopen(path, "wb");
if (pFile == 0)
return false;
@ -471,7 +473,7 @@ bool objbinsave(const char *path, const ObjData &data)
bool objbinload(const char *path, ObjData &data)
{
FILE *pFile = ::fopen(path, "rb");
FILE *pFile = boost::nowide::fopen(path, "rb");
if (pFile == 0)
return false;

View file

@ -13,6 +13,10 @@
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/foreach.hpp>
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/cstdlib.hpp>
#include "SVG.hpp"
#if 0
@ -306,7 +310,33 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
return layers_to_print;
}
bool GCode::do_export(FILE *file, Print &print)
bool GCode::do_export(Print *print, const char *path)
{
// Remove the old g-code if it exists.
boost::nowide::remove(path);
std::string path_tmp(path);
path_tmp += ".tmp";
FILE *file = boost::nowide::fopen(path_tmp.c_str(), "wb");
if (file == nullptr)
return false;
bool result = this->_do_export(*print, file);
fclose(file);
if (result && boost::nowide::rename(path_tmp.c_str(), path) != 0) {
boost::nowide::cerr << "Failed to remove the output G-code file from " << path_tmp << " to " << path
<< ". Is " << path_tmp << " locked?" << std::endl;
result = false;
}
if (! result)
boost::nowide::remove(path_tmp.c_str());
return result;
}
bool GCode::_do_export(Print &print, FILE *file)
{
// How many times will be change_layer() called?
// change_layer() in turn increments the progress bar status.

View file

@ -126,7 +126,7 @@ public:
{}
~GCode() {}
bool do_export(FILE *file, Print &print);
bool do_export(Print *print, const char *path);
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
const Pointf& origin() const { return m_origin; }
@ -146,6 +146,8 @@ public:
void apply_print_config(const PrintConfig &print_config);
protected:
bool _do_export(Print &print, FILE *file);
// Object and support extrusions of the same PrintObject at the same print_z.
struct LayerToPrint
{

View file

@ -10,6 +10,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/nowide/iostream.hpp>
namespace Slic3r {
@ -739,7 +740,7 @@ void ModelObject::print_info() const
{
using namespace std;
cout << fixed;
cout << "[" << boost::filesystem::path(this->input_file).filename().string() << "]" << endl;
boost::nowide::cout << "[" << boost::filesystem::path(this->input_file).filename().string() << "]" << endl;
TriangleMesh mesh = this->raw_mesh();
mesh.check_topology();

View file

@ -1,6 +1,8 @@
#include "SVG.hpp"
#include <iostream>
#include <boost/nowide/cstdio.hpp>
#define COORD(x) ((float)unscale((x))*10)
namespace Slic3r {
@ -8,7 +10,7 @@ namespace Slic3r {
bool SVG::open(const char* afilename)
{
this->filename = afilename;
this->f = fopen(afilename, "w");
this->f = boost::nowide::fopen(afilename, "w");
if (this->f == NULL)
return false;
fprintf(this->f,
@ -27,7 +29,7 @@ bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbo
this->filename = afilename;
this->origin = bbox.min - Point(bbox_offset, bbox_offset);
this->flipY = aflipY;
this->f = ::fopen(afilename, "w");
this->f = boost::nowide::fopen(afilename, "w");
if (f == NULL)
return false;
float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset);

View file

@ -6,6 +6,10 @@ namespace Slic3r {
extern void set_logging_level(unsigned int level);
extern void trace(unsigned int level, const char *message);
extern std::string encode_path(const char *src);
extern std::string decode_path(const char *src);
extern std::string normalize_utf8_nfc(const char *src);
// Compute the next highest power of 2 of 32-bit v
// http://graphics.stanford.edu/~seander/bithacks.html
template<typename T>

View file

@ -1,7 +1,21 @@
#include <locale>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/locale.hpp>
#include <boost/nowide/integration/filesystem.hpp>
#include <boost/nowide/convert.hpp>
#ifdef WIN32
extern "C" {
__declspec(dllimport) int WideCharToMultiByte(unsigned int, unsigned long, wchar_t const *, int, char *, int, char const *, int *);
__declspec(dllimport) int MultiByteToWideChar(unsigned int, unsigned long, char const *, int, wchar_t *, int);
}
#endif /* WIN32 */
namespace Slic3r {
static boost::log::trivial::severity_level logSeverity = boost::log::trivial::error;
@ -30,9 +44,13 @@ void set_logging_level(unsigned int level)
}
// Force set_logging_level(<=error) after loading of the DLL.
static struct SetLoggingLevelOnInit {
SetLoggingLevelOnInit() { set_logging_level(1); }
} g_SetLoggingLevelOnInit;
// Switch boost::filesystem to utf8.
static struct RunOnInit {
RunOnInit() {
boost::nowide::nowide_filesystem();
set_logging_level(1);
}
} g_RunOnInit;
void trace(unsigned int level, const char *message)
{
@ -56,6 +74,46 @@ void trace(unsigned int level, const char *message)
(::boost::log::keywords::severity = severity)) << message;
}
std::string encode_path(const char *src)
{
#ifdef WIN32
// Convert the source utf8 encoded string to a wide string.
std::wstring wstr_src = boost::nowide::widen(src);
if (wstr_src.length() == 0)
return std::string();
// Convert a wide string to a local code page.
int size_needed = ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), nullptr, 0, nullptr, nullptr);
std::string str_dst(size_needed, 0);
::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), const_cast<char*>(str_dst.data()), size_needed, nullptr, nullptr);
return str_dst;
#else /* WIN32 */
return src;
#endif /* WIN32 */
}
std::string decode_path(const char *src)
{
#ifdef WIN32
int len = strlen(src);
if (len == 0)
return std::string();
// Convert the string encoded using the local code page to a wide string.
int size_needed = ::MultiByteToWideChar(0, 0, src, len, nullptr, 0);
std::wstring wstr_dst(size_needed, 0);
::MultiByteToWideChar(0, 0, src, len, const_cast<wchar_t*>(wstr_dst.data()), size_needed);
// Convert a wide string to utf8.
return boost::nowide::narrow(wstr_dst.c_str());
#else /* WIN32 */
return src;
#endif /* WIN32 */
}
std::string normalize_utf8_nfc(const char *src)
{
static std::locale locale_utf8("en_US.UTF-8");
return boost::locale::normalize(src, boost::locale::norm_nfc, locale_utf8);
}
} // namespace Slic3r
#ifdef SLIC3R_HAS_BROKEN_CROAK