Fix possibly invalid utf-8 data before showing it to the user (GscTextWindow,

GscExecutorLogWindow).
This commit is contained in:
Alexander Shaduri
2011-12-15 16:58:06 +00:00
parent daf98009d4
commit 13d83949c4
6 changed files with 93 additions and 49 deletions
+76 -1
View File
@@ -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);
+2 -24
View File
@@ -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)
+1 -11
View File
@@ -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())
+2 -1
View File
@@ -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();