mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-26 05:45:35 +00:00
Fix possibly invalid utf-8 data before showing it to the user (GscTextWindow,
GscExecutorLogWindow).
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <gtkmm.h>
|
||||
#include <gtk/gtk.h> // gtk_* stuff
|
||||
#include <vector>
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "app_gtkmm_features.h" // APP_GTKMM_OLD_TOOLTIPS
|
||||
|
||||
@@ -193,7 +194,6 @@ void gtkmm_set_iconview_tooltip_column(Gtk::IconView* iconview,
|
||||
|
||||
|
||||
|
||||
|
||||
bool app_gtkmm_icon_theme_has_icon(Glib::RefPtr<Gtk::IconTheme> theme,
|
||||
const Glib::ustring& icon_name, int size)
|
||||
{
|
||||
@@ -212,6 +212,81 @@ bool app_gtkmm_icon_theme_has_icon(Glib::RefPtr<Gtk::IconTheme> theme,
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/// This has been copied from _g_utf8_make_valid() (glib-2.20.4).
|
||||
/// _g_utf8_make_valid() is GLib's private function for auto-correcting
|
||||
/// the potentially invalid utf-8 data.
|
||||
inline gchar* gsc_g_utf8_make_valid (const gchar* name)
|
||||
{
|
||||
GString* string;
|
||||
const gchar* remainder, *invalid;
|
||||
gint remaining_bytes, valid_bytes;
|
||||
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
string = NULL;
|
||||
remainder = name;
|
||||
remaining_bytes = gint(strlen(name));
|
||||
|
||||
while (remaining_bytes != 0) {
|
||||
if (g_utf8_validate (remainder, remaining_bytes, &invalid))
|
||||
break;
|
||||
|
||||
valid_bytes = gint(invalid - remainder);
|
||||
|
||||
if (string == NULL)
|
||||
string = g_string_sized_new (remaining_bytes);
|
||||
|
||||
g_string_append_len (string, remainder, valid_bytes);
|
||||
/* append U+FFFD REPLACEMENT CHARACTER */
|
||||
g_string_append (string, "\357\277\275");
|
||||
|
||||
remaining_bytes -= valid_bytes + 1;
|
||||
remainder = invalid + 1;
|
||||
}
|
||||
|
||||
if (string == NULL)
|
||||
return g_strdup (name);
|
||||
|
||||
g_string_append (string, remainder);
|
||||
|
||||
g_assert (g_utf8_validate (string->str, -1, NULL));
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Glib::ustring app_utf8_make_valid(const Glib::ustring& str)
|
||||
{
|
||||
char* s = gsc_g_utf8_make_valid(str.c_str());
|
||||
if (!s) {
|
||||
return Glib::ustring();
|
||||
}
|
||||
Glib::ustring res(s);
|
||||
g_free(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Glib::ustring app_output_make_valid(const Glib::ustring& str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
return app_utf8_make_valid(Glib::locale_to_utf8(str));
|
||||
} catch (Glib::ConvertError& e) {
|
||||
// nothing, try to fix as it is
|
||||
}
|
||||
#endif
|
||||
return app_utf8_make_valid(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,17 @@ bool app_gtkmm_icon_theme_has_icon(Glib::RefPtr<Gtk::IconTheme> theme,
|
||||
const Glib::ustring& icon_name, int size);
|
||||
|
||||
|
||||
/// Convert a possibly invalid utf-8 string to valid utf-8.
|
||||
/// \param str string to test and fix.
|
||||
/// \param in_locale If true, \c str will be converted from locale charset to utf-8 first.
|
||||
Glib::ustring app_utf8_make_valid(const Glib::ustring& str);
|
||||
|
||||
|
||||
/// Make command output a valid utf-8 string. Essentially, this calls app_utf8_make_valid(),
|
||||
/// supplying true for \c in_locale under Win32, and false under other systems.
|
||||
/// The reason for this is that in Win32 we can't execute commands under C locale,
|
||||
/// but we do execute them under C in other systems.
|
||||
Glib::ustring app_output_make_valid(const Glib::ustring& str);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -86,18 +86,7 @@ void gsc_no_info_dialog_show(const std::string& message, const std::string& sec_
|
||||
|
||||
if (response == Gtk::RESPONSE_HELP) {
|
||||
GscTextWindow<SmartctlOutputInstance>* win = GscTextWindow<SmartctlOutputInstance>::create();
|
||||
// make save visible and enable monospace font
|
||||
|
||||
std::string buf_text = output;
|
||||
// We receive locale'd thousands separators in win32, so convert them.
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
buf_text = Glib::locale_to_utf8(buf_text);
|
||||
} catch (Glib::ConvertError& e) {
|
||||
buf_text = ""; // inserting invalid utf8 may trigger a segfault, so empty is better.
|
||||
}
|
||||
#endif
|
||||
win->set_text(output_window_title, buf_text, true, true);
|
||||
win->set_text(output_window_title, output, true, true);
|
||||
|
||||
if (!default_save_filename.empty())
|
||||
win->set_save_filename(default_save_filename);
|
||||
|
||||
@@ -322,25 +322,7 @@ void GscExecutorLogWindow::on_tree_selection_changed()
|
||||
if (output_textview) {
|
||||
Glib::RefPtr<Gtk::TextBuffer> buffer = output_textview->get_buffer();
|
||||
if (buffer) {
|
||||
|
||||
// Under win32, we can't execute smartctl under C locale. Smartctl
|
||||
// uses locale information only for thousands separator in User Capacity.
|
||||
// We can parse that, but we need to insert that text into a textarea
|
||||
// widget, which may error out on invalid utf8 char.
|
||||
// So, we convert the whole output to utf8, hoping that the result is ok.
|
||||
// Note that a separator converted to utf8 may be a different sequence
|
||||
// of chars, so we parse it as original charset, but insert into a textarea
|
||||
// as utf8.
|
||||
std::string buf_text = entry->std_output;
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
buf_text = Glib::locale_to_utf8(buf_text);
|
||||
} catch (Glib::ConvertError& e) {
|
||||
buf_text = ""; // inserting invalid utf8 may trigger a segfault, so empty better.
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer->set_text(buf_text);
|
||||
buffer->set_text(app_output_make_valid(entry->std_output));
|
||||
|
||||
Glib::RefPtr<Gtk::TextTag> tag;
|
||||
Glib::RefPtr<Gtk::TextTagTable> table = buffer->get_tag_table();
|
||||
@@ -354,15 +336,11 @@ void GscExecutorLogWindow::on_tree_selection_changed()
|
||||
}
|
||||
}
|
||||
|
||||
// Hide in win32 because it is known to cause segfaults there (see above).
|
||||
// Not anymore...
|
||||
// #ifndef _WIN32
|
||||
Gtk::Entry* command_entry = this->lookup_widget<Gtk::Entry*>("command_entry");
|
||||
if (command_entry) {
|
||||
std::string cmd_text = entry->command + " " + entry->parameters;
|
||||
command_entry->set_text(cmd_text);
|
||||
command_entry->set_text(app_output_make_valid(cmd_text));
|
||||
}
|
||||
// #endif
|
||||
|
||||
Gtk::Button* window_save_current_button = this->lookup_widget<Gtk::Button*>("window_save_current_button");
|
||||
if (window_save_current_button)
|
||||
|
||||
@@ -1261,22 +1261,12 @@ bool GscInfoWindow::on_delete_event_before(GdkEventAny* e)
|
||||
|
||||
|
||||
|
||||
|
||||
void GscInfoWindow::on_view_output_button_clicked()
|
||||
{
|
||||
GscTextWindow<SmartctlOutputInstance>* win = GscTextWindow<SmartctlOutputInstance>::create();
|
||||
// make save visible and enable monospace font
|
||||
|
||||
std::string buf_text = this->drive->get_full_output();
|
||||
// We receive locale'd thousands separators in win32, so convert them.
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
buf_text = Glib::locale_to_utf8(buf_text);
|
||||
} catch (Glib::ConvertError& e) {
|
||||
buf_text = ""; // inserting invalid utf8 may trigger a segfault, so empty better.
|
||||
}
|
||||
#endif
|
||||
win->set_text("Smartctl Output", buf_text, true, true);
|
||||
win->set_text("Smartctl Output", this->drive->get_full_output(), true, true);
|
||||
|
||||
std::string filename = drive->get_save_filename();
|
||||
if (!filename.empty())
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "hz/fs_file.h"
|
||||
|
||||
#include "applib/app_ui_res_utils.h"
|
||||
#include "applib/app_gtkmm_utils.h"
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +88,7 @@ class GscTextWindow : public AppUIResWidget<GscTextWindow<InstanceSwitch>, Insta
|
||||
Gtk::TextView* textview = this->template lookup_widget<Gtk::TextView*>("main_textview");
|
||||
if (textview) {
|
||||
Glib::RefPtr<Gtk::TextBuffer> buffer = textview->get_buffer();
|
||||
buffer->set_text(contents);
|
||||
buffer->set_text(app_output_make_valid(contents));
|
||||
|
||||
if (use_monospace) {
|
||||
Glib::RefPtr<Gtk::TextTag> tag = buffer->create_tag();
|
||||
|
||||
Reference in New Issue
Block a user