diff --git a/src/lib/src/fwts_log_html.c b/src/lib/src/fwts_log_html.c
index 1ca79b8..a040b43 100644
--- a/src/lib/src/fwts_log_html.c
+++ b/src/lib/src/fwts_log_html.c
@@ -34,6 +34,133 @@ typedef struct {
 	const char *name;
 } fwts_log_html_stack_t;
 
+typedef struct {
+	unsigned char	ch;	/* ASCII */
+	char *		html;	/* HTML equivalent */
+} fwts_log_html_ascii_t;
+
+/*
+ * ASCII to HTML conversion table:
+ * ISO 10646, ISO 8879, ISO 8859-1 Latin alphabet No. 1
+ * Browser support: All browsers
+ */
+static fwts_log_html_ascii_t fwts_log_html_ascii_table[] = {
+	{ '"',	"&quot;" },
+	{ '&', 	"&amp;" },
+	{ '<', 	"&lt;" },
+	{ '>',	"&gt;" },
+	{ '{',	"&#123;" },
+	{ '|',	"&#124;" },
+	{ '}',	"&#125;" },
+	{ '~',	"&#126;" },
+
+	{ 160,	"&nbsp;" },
+	{ 161,	"&iexl;" },
+	{ 162,	"&cent;" },
+	{ 163,	"&pound;" },
+	{ 164,	"&curren;" },
+	{ 165,	"&yen;" },
+	{ 166,	"&brvbar;" },
+	{ 167,	"&sect;" },
+	{ 168,	"&uml;" },
+	{ 169,	"&copy;" },
+	{ 170,	"&ordf;" },
+	{ 171,	"&laquo;" },
+	{ 172,	"&not;" },
+	{ 173,	"&shy;" },
+	{ 174,	"&reg;" },
+	{ 175,	"&macr;" },
+
+	{ 176,	"&deg;" },
+	{ 177,	"&plusmn;" },
+	{ 178,	"&sup2;" },
+	{ 179,	"&sup3;" },
+	{ 180,	"&acute;" },
+	{ 181,	"&micro;" },
+	{ 182,	"&para;" },
+	{ 183,	"&middot;" },
+	{ 184,	"&cedil;" },
+	{ 185,	"&sup1;" },
+	{ 186,	"&ordm;" },
+	{ 187,	"&raquo;" },
+	{ 187,	"&frac14;" },
+	{ 189,	"&frac12;" },
+	{ 190,	"&frac34;" },
+	{ 191,	"&iquest;" },
+
+	/* Probably never used, but here in case */
+
+	{ 192,	"&Agrave;" },
+	{ 193,	"&Aacute;" },
+	{ 194,	"&Acirc;" },
+	{ 195,	"&Atilde;" },
+	{ 196,	"&Auml;" },
+	{ 197,	"&Aring;" },
+	{ 198,	"&AElig;" },
+	{ 199,	"&Ccedil;" },
+	{ 200,	"&Egrave;" },
+	{ 201,	"&Eacute;" },
+	{ 202,	"&Ecirc;" },
+	{ 203,	"&Euml;" },
+	{ 204,	"&lgrave;" },
+	{ 205,	"&lacute;" },
+	{ 206,	"&lcirc;" },
+	{ 207,	"&luml;" },
+
+	{ 208,	"&ETH;" },
+	{ 209,	"&Ntilde;" },
+	{ 210,	"&Ograve;" },
+	{ 211,	"&Oacute;" },
+	{ 212,	"&Ocirc;" },
+	{ 213,	"&Otilde;" },
+	{ 214,	"&Ouml;" },
+	{ 215,	"&times;" },
+	{ 216,	"&Oslash;" },
+	{ 217,	"&Ugrave;" },
+	{ 218,	"&Uacute;" },
+	{ 219,	"&Ucirc;" },
+	{ 220,	"&Uuml;" },
+	{ 221,	"&Yacute;" },
+	{ 222,	"&THORN;" },
+	{ 223,	"&szlig;" },
+
+	{ 224,	"&agrave;" },
+	{ 225,	"&aacute;" },
+	{ 226,	"&acirc;" },
+	{ 227,	"&atilde;" },
+	{ 228,	"&auml;" },
+	{ 229,	"&aring;" },
+	{ 230,	"&aelig;" },
+	{ 231,	"&ccedil;" },
+	{ 232,	"&egrave;" },
+	{ 233,	"&eacute;" },
+	{ 234,	"&ecirc;" },
+	{ 235,	"&emuml;" },
+	{ 236,	"&igrave;" },
+	{ 237,	"&iacute;" },
+	{ 238,	"&icirc;" },
+	{ 239,	"&iuml;" },
+
+	{ 240,	"&eth;" },
+	{ 241,	"&ntilde;" },
+	{ 242,	"&ograve;" },
+	{ 243,	"&oacute;" },
+	{ 244,	"&ocirc;" },
+	{ 245,	"&otilde;" },
+	{ 246,	"&ouml;" },
+	{ 247,	"&divide;" },
+	{ 248,	"&oslash;" },
+	{ 249,	"&ugrave;" },
+	{ 250,	"&uacute;" },
+	{ 251,	"&ucirc;" },
+	{ 252,	"&uuml;" },
+	{ 253,	"&yacute;" },
+	{ 254,	"&thorn;" },
+	{ 255,	"&yuml;" },
+
+	{ 0, 	NULL },
+};
+
 static fwts_log_html_stack_t html_stack[MAX_HTML_STACK];
 static int html_stack_index = 0;
 
@@ -49,6 +176,58 @@ static void fwts_log_html(fwts_log_file *log_file, const char *fmt, ...)
 	va_end(args);
 }
 
+/*
+ *  fwts_log_html_convert_ascii()
+ *	return a static string containing any convertion from ASCII to a
+ *	HTML representation of char ch.  If no conversion needed, just
+ *	return a string containing the ch.
+ */
+static char *fwts_log_html_convert_ascii(const char ch)
+{
+	int i;
+	static char buf[2];
+
+	for (i = 0; fwts_log_html_ascii_table[i].html != NULL; i++) {
+		if (fwts_log_html_ascii_table[i].ch == ch)
+			return fwts_log_html_ascii_table[i].html;
+	}
+
+	/* No mapping, just return string containing ch */
+	buf[0] = ch;
+	buf[1] = '\0';
+
+	return buf;
+}
+
+/*
+ *  fwts_log_html_convert_ascii_str()
+ *	convert an ASCII string into a HTML encoded string. The returned
+ *	string needs free'ing once finished with.
+ */
+static char *fwts_log_html_convert_ascii_str(const char *buffer)
+{
+	const char *str1;
+	char *converted;
+	size_t len = 0;
+
+	/* Step 1, figure out how much space we need */
+	for (str1 = buffer; *str1; str1++) {
+		char *str = fwts_log_html_convert_ascii(*str1);
+		len += strlen(str);
+	}
+
+	if ((converted = calloc(len + 1, 1)) == NULL)
+		return NULL;
+
+	/* Step 2, convert */
+	for (str1 = buffer; *str1; str1++) {
+		char *str = fwts_log_html_convert_ascii(*str1);
+		strcat(converted, str);
+	}
+
+	return converted;
+}
+
 
 /*
  *  fwts_log_print_html()
@@ -67,6 +246,7 @@ static int fwts_log_print_html(
 	char *style;
 	char *code_start;
 	char *code_end;
+	char *html_converted;
 
 	if (!((field & LOG_FIELD_MASK) & fwts_log_filter))
 		return 0;
@@ -74,6 +254,12 @@ static int fwts_log_print_html(
 	if (field & (LOG_NEWLINE | LOG_SEPARATOR | LOG_DEBUG))
 		return 0;
 
+	if ((html_converted = fwts_log_html_convert_ascii_str(buffer)) == NULL) {
+		/* We can't report an error via the logging mechanism in case we loop */
+		fprintf(stderr, "Out of memory converting html.\n");
+		exit(EXIT_FAILURE);
+	}
+
 	fwts_log_html(log_file, "<TR>\n");
 
 	if (field & LOG_VERBATUM) {
@@ -87,23 +273,24 @@ static int fwts_log_print_html(
 	switch (field & LOG_FIELD_MASK) {
 	case LOG_ERROR:
 		fwts_log_html(log_file, "  <TD class=style_error>Error</TD>"
-			"<TD COLSPAN=2>%s</TD>\n", buffer);
+			"<TD COLSPAN=2>%s</TD>\n", html_converted);
 		break;
 	case LOG_WARNING:
 		fwts_log_html(log_file, "  <TD class=style_error>Warning</TD>"
 			"<TD COLSPAN=2 class=style_advice_info>%s%s%s</TD>\n",
-			code_start, buffer, code_end);
+			code_start, html_converted, code_end);
 		break;
 	case LOG_HEADING:
 		fwts_log_html(log_file, "<TD COLSPAN=2 class=style_heading>%s%s%s</TD>\n",
-			code_start, buffer, code_end);
+			code_start, html_converted, code_end);
 		break;
 	case LOG_INFO:
 		fwts_log_html(log_file, "  <TD></TD><TD COLSPAN=2 class=style_infos>%s%s%s</TD>\n",
-			code_start, buffer, code_end);
+			code_start, html_converted, code_end);
 		break;
 	case LOG_PASSED:
-		fwts_log_html(log_file, "<TD class=style_passed>PASSED</TD><TD>%s</TD>\n", buffer);
+		fwts_log_html(log_file, "<TD class=style_passed>PASSED</TD><TD>%s</TD>\n",
+			html_converted);
 		break;
 	case LOG_FAILED:
 		switch (level) {
@@ -128,30 +315,32 @@ static int fwts_log_print_html(
 		str = fwts_log_level_to_str(level);
 
 		fwts_log_html(log_file, "  <TD%s>%s [%s]</TD>\n", style, *status ? status : "", str);
-		fwts_log_html(log_file, "  <TD>%s</TD>\n", buffer);
+		fwts_log_html(log_file, "  <TD>%s</TD>\n", html_converted);
 		break;
 
 	case LOG_SKIPPED:
 		fwts_log_html(log_file, "<TD class=style_skipped>Skipped</TD>"
-			"<TD>%s%s%s</TD>\n", code_start, buffer, code_end);
+			"<TD>%s%s%s</TD>\n", code_start, html_converted, code_end);
 		break;
 
 	case LOG_SUMMARY:
 		fwts_log_html(log_file, "  <TD></TD>"
 			"<TD COLSPAN=2 class=style_summary>%s%s%s</TD>\n",
-			code_start, buffer, code_end);
+			code_start, html_converted, code_end);
 		break;
 
 	case LOG_ADVICE:
 		fwts_log_html(log_file, "  <TD class=style_advice>Advice</TD>"
 			"<TD COLSPAN=2 class=style_advice_info>%s%s%s</TD>\n",
-			code_start, buffer, code_end);
+			code_start, html_converted, code_end);
 		break;
 
 	default:
 		break;
 	}
 
+	free(html_converted);
+
 	fwts_log_html(log_file, "</TR>\n");
 	fflush(log_file->fp);
 
