Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVojtech Kral <vojtech@kral.hk>2018-06-12 13:32:03 +0300
committerbubnikv <bubnikv@gmail.com>2018-06-21 11:44:29 +0300
commit9ee10a877938e371b9200601c53b69b78886d015 (patch)
tree71868ef4b0118d39288d80ac24608c511b5274ae
parent1ba81655e2685c40b5c345684868e8d6d96cee2b (diff)
Octoprint: Fix unicode support
-rw-r--r--xs/src/slic3r/Utils/Http.cpp72
-rw-r--r--xs/src/slic3r/Utils/Http.hpp9
-rw-r--r--xs/src/slic3r/Utils/OctoPrint.cpp31
-rw-r--r--xs/src/slic3r/Utils/OctoPrint.hpp3
4 files changed, 77 insertions, 38 deletions
diff --git a/xs/src/slic3r/Utils/Http.cpp b/xs/src/slic3r/Utils/Http.cpp
index adc8ac816..7c4126633 100644
--- a/xs/src/slic3r/Utils/Http.cpp
+++ b/xs/src/slic3r/Utils/Http.cpp
@@ -3,13 +3,16 @@
#include <cstdlib>
#include <functional>
#include <thread>
-#include <tuple>
+#include <deque>
+#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <curl/curl.h>
#include "../../libslic3r/libslic3r.h"
+namespace fs = boost::filesystem;
+
namespace Slic3r {
@@ -34,7 +37,11 @@ struct Http::priv
::curl_httppost *form;
::curl_httppost *form_end;
::curl_slist *headerlist;
+ // Used for reading the body
std::string buffer;
+ // Used for storing file streams added as multipart form parts
+ // Using a deque here because unlike vector it doesn't ivalidate pointers on insertion
+ std::deque<std::ifstream> form_files;
size_t limit;
bool cancel;
@@ -50,8 +57,9 @@ struct Http::priv
static size_t writecb(void *data, size_t size, size_t nmemb, void *userp);
static int xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
static int xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow);
+ static size_t form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp);
- void form_add_file(const char *name, const char *path, const char* filename);
+ void form_add_file(const char *name, const fs::path &path, const char* filename);
std::string curl_error(CURLcode curlcode);
std::string body_size_error();
@@ -138,21 +146,42 @@ int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double
return xfercb(userp, dltotal, dlnow, ultotal, ulnow);
}
-void Http::priv::form_add_file(const char *name, const char *path, const char* filename)
+size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp)
{
+ auto stream = reinterpret_cast<fs::ifstream*>(userp);
+
+ try {
+ stream->read(buffer, size * nitems);
+ } catch (...) {
+ return CURL_READFUNC_ABORT;
+ }
+
+ return stream->gcount();
+}
+
+void Http::priv::form_add_file(const char *name, const fs::path &path, const char* filename)
+{
+ // We can't use CURLFORM_FILECONTENT, because curl doesn't support Unicode filenames on Windows
+ // and so we use CURLFORM_STREAM with boost ifstream to read the file.
+
+ if (filename == nullptr) {
+ filename = path.string().c_str();
+ }
+
+ fs::ifstream stream(path, std::ios::in | std::ios::binary);
+ stream.seekg(0, std::ios::end);
+ size_t size = stream.tellg();
+ stream.seekg(0);
+ form_files.push_back(std::move(stream));
+ auto stream_ptr = &form_files.back();
+
if (filename != nullptr) {
::curl_formadd(&form, &form_end,
CURLFORM_COPYNAME, name,
- CURLFORM_FILE, path,
CURLFORM_FILENAME, filename,
CURLFORM_CONTENTTYPE, "application/octet-stream",
- CURLFORM_END
- );
- } else {
- ::curl_formadd(&form, &form_end,
- CURLFORM_COPYNAME, name,
- CURLFORM_FILE, path,
- CURLFORM_CONTENTTYPE, "application/octet-stream",
+ CURLFORM_STREAM, static_cast<void*>(stream_ptr),
+ CURLFORM_CONTENTSLENGTH, static_cast<long>(size),
CURLFORM_END
);
}
@@ -177,6 +206,7 @@ void Http::priv::http_perform()
::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb);
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this));
+ ::curl_easy_setopt(curl, CURLOPT_READFUNCTION, form_file_read_cb);
::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
#if LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 32
@@ -206,14 +236,20 @@ void Http::priv::http_perform()
if (res != CURLE_OK) {
if (res == CURLE_ABORTED_BY_CALLBACK) {
- Progress dummyprogress(0, 0, 0, 0);
- bool cancel = true;
- if (progressfn) { progressfn(dummyprogress, cancel); }
+ if (cancel) {
+ // The abort comes from the request being cancelled programatically
+ Progress dummyprogress(0, 0, 0, 0);
+ bool cancel = true;
+ if (progressfn) { progressfn(dummyprogress, cancel); }
+ } else {
+ // The abort comes from the CURLOPT_READFUNCTION callback, which means reading file failed
+ if (errorfn) { errorfn(std::move(buffer), "Error reading file for file upload", http_status); }
+ }
}
else if (res == CURLE_WRITE_ERROR) {
- if (errorfn) { errorfn(std::move(buffer), std::move(body_size_error()), http_status); }
+ if (errorfn) { errorfn(std::move(buffer), body_size_error(), http_status); }
} else {
- if (errorfn) { errorfn(std::move(buffer), std::move(curl_error(res)), http_status); }
+ if (errorfn) { errorfn(std::move(buffer), curl_error(res), http_status); }
};
} else {
if (completefn) {
@@ -288,13 +324,13 @@ Http& Http::form_add(const std::string &name, const std::string &contents)
return *this;
}
-Http& Http::form_add_file(const std::string &name, const std::string &path)
+Http& Http::form_add_file(const std::string &name, const fs::path &path)
{
if (p) { p->form_add_file(name.c_str(), path.c_str(), nullptr); }
return *this;
}
-Http& Http::form_add_file(const std::string &name, const std::string &path, const std::string &filename)
+Http& Http::form_add_file(const std::string &name, const fs::path &path, const std::string &filename)
{
if (p) { p->form_add_file(name.c_str(), path.c_str(), filename.c_str()); }
return *this;
diff --git a/xs/src/slic3r/Utils/Http.hpp b/xs/src/slic3r/Utils/Http.hpp
index 2b8126334..73656bf88 100644
--- a/xs/src/slic3r/Utils/Http.hpp
+++ b/xs/src/slic3r/Utils/Http.hpp
@@ -4,6 +4,7 @@
#include <memory>
#include <string>
#include <functional>
+#include <boost/filesystem/path.hpp>
namespace Slic3r {
@@ -33,6 +34,8 @@ public:
Http(Http &&other);
+ // Note: strings are expected to be UTF-8-encoded
+
// These are the primary constructors that create a HTTP object
// for a GET and a POST request respectively.
static Http get(std::string url);
@@ -55,10 +58,10 @@ public:
Http& ca_file(const std::string &filename);
// Add a HTTP multipart form field
Http& form_add(const std::string &name, const std::string &contents);
- // Add a HTTP multipart form file data contents
- Http& form_add_file(const std::string &name, const std::string &path);
+ // Add a HTTP multipart form file data contents, `name` is the name of the part
+ Http& form_add_file(const std::string &name, const boost::filesystem::path &path);
// Same as above except also override the file's filename with a custom one
- Http& form_add_file(const std::string &name, const std::string &path, const std::string &filename);
+ Http& form_add_file(const std::string &name, const boost::filesystem::path &path, const std::string &filename);
// Callback called on HTTP request complete
Http& on_complete(CompleteFn fn);
diff --git a/xs/src/slic3r/Utils/OctoPrint.cpp b/xs/src/slic3r/Utils/OctoPrint.cpp
index 1794c6024..86049de16 100644
--- a/xs/src/slic3r/Utils/OctoPrint.cpp
+++ b/xs/src/slic3r/Utils/OctoPrint.cpp
@@ -31,7 +31,7 @@ struct SendDialog : public GUI::MsgDialog
SendDialog(const fs::path &path) :
MsgDialog(nullptr, _(L("Send G-Code to printer")), _(L("Upload to OctoPrint with the following filename:")), wxID_NONE),
- txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().string())),
+ txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())),
box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload"))))
{
auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed.")));
@@ -45,15 +45,14 @@ struct SendDialog : public GUI::MsgDialog
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
txt_filename->SetFocus();
- txt_filename->SetSelection(0, path.stem().size());
+ wxString stem(path.stem().wstring());
+ txt_filename->SetSelection(0, stem.Length());
Fit();
}
fs::path filename() const {
- // The buffer object that utf8_str() returns may just point to data owned by the source string
- // so we need to copy the string in any case to be on the safe side.
- return fs::path(txt_filename->GetValue().utf8_str().data());
+ return fs::path(txt_filename->GetValue().wx_str());
}
bool print() const { return box_print->GetValue(); }
@@ -73,7 +72,7 @@ bool OctoPrint::test(wxString &msg) const
// it is ok to refer to `msg` from within the closure
bool res = true;
- auto url = std::move(make_url("api/version"));
+ auto url = make_url("api/version");
BOOST_LOG_TRIVIAL(info) << boost::format("Octoprint: Get version at: %1%") % url;
@@ -99,7 +98,7 @@ bool OctoPrint::send_gcode(const std::string &filename) const
const auto errortitle = _(L("Error while uploading to the OctoPrint server"));
fs::path filepath(filename);
- SendDialog send_dialog(filepath.filename().string());
+ SendDialog send_dialog(filepath.filename());
if (send_dialog.ShowModal() != wxID_OK) { return false; }
const bool print = send_dialog.print();
@@ -125,10 +124,10 @@ bool OctoPrint::send_gcode(const std::string &filename) const
auto url = make_url("api/files/local");
BOOST_LOG_TRIVIAL(info) << boost::format("Octoprint: Uploading file %1% at %2%, filename: %3%, path: %4%, print: %5%")
- % filepath
+ % filepath.string()
% url
- % upload_filename
- % upload_parent_path
+ % upload_filename.string()
+ % upload_parent_path.string()
% print;
auto http = Http::post(std::move(url));
@@ -175,24 +174,24 @@ std::string OctoPrint::make_url(const std::string &path) const
{
if (host.find("http://") == 0 || host.find("https://") == 0) {
if (host.back() == '/') {
- return std::move((boost::format("%1%%2%") % host % path).str());
+ return (boost::format("%1%%2%") % host % path).str();
} else {
- return std::move((boost::format("%1%/%2%") % host % path).str());
+ return (boost::format("%1%/%2%") % host % path).str();
}
} else {
- return std::move((boost::format("http://%1%/%2%") % host % path).str());
+ return (boost::format("http://%1%/%2%") % host % path).str();
}
}
-wxString OctoPrint::format_error(std::string error, unsigned status)
+wxString OctoPrint::format_error(const std::string &error, unsigned status)
{
- const wxString wxerror = error;
+ auto wxerror = wxString::FromUTF8(error.data());
if (status != 0) {
return wxString::Format("HTTP %u: %s", status,
(status == 401 ? _(L("Invalid API key")) : wxerror));
} else {
- return std::move(wxerror);
+ return wxerror;
}
}
diff --git a/xs/src/slic3r/Utils/OctoPrint.hpp b/xs/src/slic3r/Utils/OctoPrint.hpp
index e278c8141..a8599faa9 100644
--- a/xs/src/slic3r/Utils/OctoPrint.hpp
+++ b/xs/src/slic3r/Utils/OctoPrint.hpp
@@ -17,6 +17,7 @@ public:
OctoPrint(DynamicPrintConfig *config);
bool test(wxString &curl_msg) const;
+ // Send gcode file to octoprint, filename is expected to be in UTF-8
bool send_gcode(const std::string &filename) const;
private:
std::string host;
@@ -25,7 +26,7 @@ private:
void set_auth(Http &http) const;
std::string make_url(const std::string &path) const;
- static wxString format_error(std::string error, unsigned status);
+ static wxString format_error(const std::string &error, unsigned status);
};