1 /*  cssed (c) Iago Rubio 2003, 2005 - A tiny CSS editor.
2  *
3  *  This program is free software; you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU Library General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16  */
17 
18 /*
19 	This parser is implemented using a subset of the libcroco (the parser)
20 	and using just it's SAC handler. Don't use it as a libcroco example as
21 	the libcroco used IS MODIFIED. Some functions doesn't exists or are private
22 	in the original libcroco.
23 
24 	Download the original libcroco from http://www.freespiders.org/
25 */
26 
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30 
31 #define PLAT_GTK 1
32 
33 #include <stdio.h>
34 #include <gtk/gtk.h>
35 
36 #include "cssedwindow.h"
37 #include "document.h"
38 #include "callbacks.h"
39 #include "interface.h"
40 #include "support.h"
41 #include "utils.h"
42 
43 #include <libcroco.h>
44 #include <string.h>
45 
46 #define OUT_COLOR "navy"
47 #define ERR_COLOR "red"
48 #define SEL_COLOR "blue"
49 #define PRO_COLOR "maroon"
50 #define MED_COLOR "dark green"
51 
52 typedef struct _CssedCssParserData {
53 	CssedDoc *doc;
54 	gchar *current_selector;
55 	gboolean in_media;
56 	gint err_count;
57 	gchar *filename;
58 } CssedCssParserData;
59 
60 /* *** UTILS *** */
61 CssedWindow *
get_window_fom_sac_handler_data(CRDocHandler * a_handler)62 get_window_fom_sac_handler_data (CRDocHandler * a_handler)
63 {
64 	CssedCssParserData* data;
65 	CssedDoc *document;
66 	CssedWindow *win;
67 
68 	data = (CssedCssParserData*) a_handler->app_data;
69 	document = (CssedDoc *) data->doc;
70 	win = document_get_window (document);
71 
72 	return win;
73 }
74 
75 void
change_current_sac_handler_selector(CRDocHandler * a_handler,gchar * selector)76 change_current_sac_handler_selector(CRDocHandler * a_handler,gchar* selector)
77 {
78 	CssedCssParserData* data;
79 	data = (CssedCssParserData*) a_handler->app_data;
80 
81 	if( data->current_selector )
82 		g_free(data->current_selector);
83 
84 	data->current_selector = g_strdup(selector);
85 }
86 
87 /* *** SAC HANDLERS START *** */
88 void
sac_handler_start_document(CRDocHandler * a_handler)89 sac_handler_start_document (CRDocHandler * a_handler)
90 {
91 	CssedWindow* window;
92 	g_return_if_fail (a_handler);
93 
94 	window = get_window_fom_sac_handler_data (a_handler);
95 	cssed_window_output_clear(window);
96 }
97 
98 void
sac_handler_end_document(CRDocHandler * a_handler)99 sac_handler_end_document (CRDocHandler * a_handler)
100 {
101 	g_return_if_fail (a_handler);
102 }
103 
104 void
sac_handler_import_style(CRDocHandler * a_handler,GList * a_media_list,CRString * ar_uri,CRString * ar_uri_default_ns,CRParsingLocation * a_location)105 sac_handler_import_style (CRDocHandler *a_handler,
106 						  GList *a_media_list,
107 						  CRString *ar_uri,
108 						  CRString *ar_uri_default_ns,
109 						  CRParsingLocation *a_location)
110 {
111 	GList *cur = NULL;
112 	guchar *str;
113 	guchar *out;
114 	CssedCssParserData* data;
115 	GString *a_uri, *a_uri_default_ns;
116 
117 
118 	g_return_if_fail (ar_uri);
119 	g_return_if_fail (ar_uri_default_ns);
120 	g_return_if_fail (a_handler);
121 
122 	a_uri = ar_uri->stryng;
123 	a_uri_default_ns = ar_uri_default_ns->stryng;
124 
125 	data = (CssedCssParserData*) a_handler->app_data;
126 
127 	document_write_error_to_program_output ((CssedDoc *) data->doc,
128 						_("Input style from import found."),
129 						OUT_COLOR);
130 
131 	if (a_media_list)
132 	{
133 		document_write_error_to_program_output ((CssedDoc *) data->doc,
134 							_("\tMedia list"),
135 							OUT_COLOR);
136 
137 		for (cur = a_media_list; cur; cur = cur->next)
138 		{
139 			if (cur->data)
140 			{
141 				str = g_strndup
142 					(((GString *) cur->data)->str,
143 					 ((GString *) cur->data)->len);
144 
145 				if (str)
146 				{
147 					out = g_strdup_printf ("\t\t%s", str);
148 					document_write_error_to_program_output((CssedDoc *) data->doc, out, OUT_COLOR);
149 					g_free (str);
150 					g_free (out);
151 					str = NULL;
152 					out = NULL;
153 				}
154 			}
155 		}
156 
157 		document_write_error_to_program_output ((CssedDoc *)data->doc, _("\tDefault namespace"), OUT_COLOR);
158 		if (a_uri_default_ns && a_uri_default_ns->str)
159 		{
160 			str = g_strndup (a_uri_default_ns->str, a_uri_default_ns->len);
161 			if (str)
162 			{
163 				out = g_strdup_printf ("\t\t%s", str);
164 				document_write_error_to_program_output ((CssedDoc *) data->doc, out, OUT_COLOR);
165 				g_free (str);
166 				g_free (out);
167 			}
168 		}
169 	}
170 }
171 
172 
173 void
sac_handler_namespace_declaration(CRDocHandler * a_handler,CRString * ar_prefix,CRString * ar_uri,CRParsingLocation * a_location)174 sac_handler_namespace_declaration (CRDocHandler *a_handler,
175 								   CRString *ar_prefix,
176 								   CRString *ar_uri,
177 								   CRParsingLocation *a_location)
178 
179 {
180 	GString *a_prefix, *a_uri;
181 	guchar *prefix = NULL;
182 	guchar *uri = NULL;
183 	guchar *out = NULL;
184 	CssedCssParserData* data;
185 
186 
187 	g_return_if_fail (ar_uri);
188 	g_return_if_fail (ar_prefix);
189 	g_return_if_fail (a_handler);
190 
191 	data = (CssedCssParserData*) a_handler->app_data;
192 	a_prefix = ar_prefix->stryng;
193 	a_uri = ar_uri->stryng;
194 
195 	document_write_error_to_program_output ((CssedDoc *) data->doc,
196 						_("parser: Namespace declaration"),	OUT_COLOR);
197 
198 	if (a_prefix && a_prefix->str)
199 	{
200 		prefix = g_strndup (a_prefix->str, a_prefix->len);
201 
202 		if (prefix)
203 		{
204 			out = g_strdup_printf (_("\t\tprefix: %s"), prefix);
205 			document_write_error_to_program_output ((CssedDoc *)
206 								data->
207 								doc, out,
208 								OUT_COLOR);
209 			g_free (prefix);
210 			g_free (out);
211 		}
212 	}
213 
214 	if (a_uri && a_uri->str)
215 	{
216 
217 		uri = g_strndup (a_uri->str, a_uri->len);
218 
219 		if (uri)
220 		{
221 			out = g_strdup_printf (_("\t\turi: %s"), uri);
222 			document_write_error_to_program_output ((CssedDoc *)
223 								data->
224 								doc, out,
225 								OUT_COLOR);
226 			g_free (prefix);
227 			g_free (out);
228 		}
229 	}
230 }
231 
232 
233 void
sac_handler_comment(CRDocHandler * a_handler,CRString * ar_comment)234 sac_handler_comment    (CRDocHandler *a_handler,
235 						CRString *ar_comment)
236 {
237 	gchar *out = NULL;
238 	guchar *comment = NULL;
239 	CssedCssParserData* data;
240 	GString * a_comment;
241 
242 	g_return_if_fail (ar_comment);
243 	g_return_if_fail (a_handler);
244 
245 	data = (CssedCssParserData*) a_handler->app_data;
246 	a_comment = ar_comment->stryng;
247 	if (a_comment && a_comment->str)
248 	{
249 		comment = g_strndup (a_comment->str, a_comment->len);
250 
251 		if (comment)
252 		{
253 			out = g_strdup_printf (_("comment -> %s"), comment);
254 			document_write_error_to_program_output ((CssedDoc*) data->doc, out,	OUT_COLOR);
255 			g_free (comment);
256 			g_free (out);
257 			out = NULL;
258 			comment = NULL;
259 		}
260 	}
261 }
262 
263 
264 void
sac_handler_start_selector(CRDocHandler * a_handler,CRSelector * a_selector_list)265 sac_handler_start_selector (CRDocHandler * a_handler,
266 							CRSelector * a_selector_list)
267 {
268 	guchar *tmp_buf = NULL;
269 	gchar *out = NULL;
270 	CssedCssParserData* data;
271 
272 
273 	g_return_if_fail (a_selector_list);
274 	g_return_if_fail (a_handler);
275 
276 	data = (CssedCssParserData*) a_handler->app_data;
277 
278 	if (a_selector_list)
279 	{
280 		tmp_buf = cr_selector_to_string (a_selector_list);
281 		if (tmp_buf)
282 		{
283 			data->current_selector = g_strdup(tmp_buf);
284 			out = g_strdup_printf (_("<span color='black'>%s</span>:<span color='dark green'>%d</span>:\n%s"),
285 															data->filename,
286 															a_selector_list->location.line,
287 															tmp_buf);
288 			document_write_error_to_program_output ((CssedDoc*) data->doc, out, SEL_COLOR);
289 			g_free (out);
290 			g_free (tmp_buf);
291 		}
292 	}
293 }
294 
295 
296 void
sac_handler_end_selector(CRDocHandler * a_handler,CRSelector * a_selector_list)297 sac_handler_end_selector   (CRDocHandler * a_handler,
298 							CRSelector * a_selector_list)
299 {
300 	guchar *tmp_buf = NULL;
301 	gchar *out = NULL;
302 	CssedCssParserData* data;
303 
304 	g_return_if_fail (a_selector_list);
305 	g_return_if_fail (a_handler);
306 
307 	data = (CssedCssParserData*) a_handler->app_data;
308 
309 	if (a_selector_list)
310 	{
311 		tmp_buf = cr_selector_to_string (a_selector_list);
312 		if (tmp_buf)
313 		{
314 			out = g_strdup_printf (_("%s end"), tmp_buf);
315 			document_write_error_to_program_output ((CssedDoc*) data-> doc, out, SEL_COLOR);
316 			g_free (out);
317 			g_free (tmp_buf);
318 			tmp_buf = NULL;
319 			out = NULL;
320 		}
321 	}
322 }
323 
324 void
sac_handler_property(CRDocHandler * a_handler,CRString * ar_name,CRTerm * a_expr,gboolean a_is_important)325 sac_handler_property (CRDocHandler *a_handler,
326 						CRString *ar_name,
327 						CRTerm *a_expr,
328 						gboolean a_is_important)
329 {
330 	gchar *out = NULL;
331 	guchar* val;
332 	guchar *name ;
333 	CssedCssParserData* data;
334 	GString * a_name;
335 
336 	g_return_if_fail (ar_name);
337 	g_return_if_fail (a_expr);
338 	g_return_if_fail (a_handler);
339 
340 	data = (CssedCssParserData*) a_handler->app_data;
341 	a_name = ar_name->stryng;
342 
343 	if (a_name && a_name->str)
344 	{
345 		name = g_strndup (a_name->str, a_name->len);
346 
347 		if (name && a_expr)
348 		{
349 			val = cr_term_to_string (a_expr) ;
350 			out=g_strdup_printf(_("\t%s: %s"), name, val);
351 			document_write_error_to_program_output ((CssedDoc *) data->doc,	out, PRO_COLOR);
352 			g_free(out);
353 			g_free(val);
354 		}
355 		else
356 		{
357 			if( name ){
358 				out=g_strdup_printf(_("\tempty property -> %s"),name);
359 				document_write_error_to_program_output ((CssedDoc *) data->doc, out, ERR_COLOR);
360 				g_free( out );
361 
362 			}
363 			if( a_expr ){
364 				val=g_strdup_printf(_("\tempty value -> %s"),name);
365 				document_write_error_to_program_output ((CssedDoc *) data->doc, val, ERR_COLOR);
366 				g_free( val );
367 			}
368 		}
369 
370 		if (name)
371 			g_free (name);
372 	}
373 }
374 
375 void
sac_handler_start_font_face(CRDocHandler * a_handler,CRParsingLocation * a_location)376 sac_handler_start_font_face (CRDocHandler * a_handler, CRParsingLocation *a_location)
377 {
378 	CssedCssParserData* data;
379 	g_return_if_fail (a_handler);
380 
381 	data = (CssedCssParserData*) a_handler->app_data;
382 	document_write_error_to_program_output ((CssedDoc *)
383 						data->doc, _("Start font face"),
384 						OUT_COLOR);
385 }
386 
387 
388 void
sac_handler_end_font_face(CRDocHandler * a_handler)389 sac_handler_end_font_face (CRDocHandler * a_handler)
390 {
391 	CssedCssParserData* data;
392 	g_return_if_fail (a_handler);
393 
394 	data = (CssedCssParserData*) a_handler->app_data;
395 	document_write_error_to_program_output ((CssedDoc *)
396 						data->doc, _("End font face"),
397 						OUT_COLOR);
398 }
399 
400 void
sac_handler_start_media(CRDocHandler * a_handler,GList * a_media_list,CRParsingLocation * a_location)401 sac_handler_start_media (CRDocHandler * a_handler, GList * a_media_list, CRParsingLocation *a_location)
402 {
403 	CssedCssParserData* data;
404 	gchar *out;
405 
406 	g_return_if_fail (a_handler);
407 	g_return_if_fail (a_location);
408 
409 	data = (CssedCssParserData*) a_handler->app_data	;
410 
411 	out = g_strdup_printf (_("<span color='black'>%s</span>:<span color='dark green'>%d</span>:\nMedia"),
412 															data->filename,
413 															a_location->line);
414 	document_write_error_to_program_output ((CssedDoc *) data->doc, out, MED_COLOR);
415 	g_free(out);
416 }
417 
418 
419 void
sac_handler_end_media(CRDocHandler * a_handler,GList * a_media_list)420 sac_handler_end_media (CRDocHandler * a_handler, GList * a_media_list)
421 {
422 	CssedCssParserData* data;
423 
424 	g_return_if_fail (a_handler);
425 	data = (CssedCssParserData*) a_handler->app_data;
426 
427 	document_write_error_to_program_output ((CssedDoc *) data->doc,
428 											_("End Media"), MED_COLOR);
429 
430 }
431 
432 void
sac_handler_start_page(CRDocHandler * a_handler,CRString * ar_name,CRString * ar_pseudo_page,CRParsingLocation * a_location)433 sac_handler_start_page (CRDocHandler *a_handler,
434 						CRString *ar_name,
435 						CRString *ar_pseudo_page,
436 						CRParsingLocation *a_location)
437 
438 {
439 	CssedCssParserData* data;
440 	gchar *out;
441 
442 	g_return_if_fail (a_handler);
443 	data = (CssedCssParserData*) a_handler->app_data;
444 	out = g_strdup_printf (_("<span color='black'>%s</span>:<span color='dark green'>%d</span>:\nPage"),
445 															data->filename,
446 															a_location->line);
447 	document_write_error_to_program_output ((CssedDoc*) data->doc, out, MED_COLOR);
448 	g_free(out);
449 }
450 
451 void
sac_handler_end_page(CRDocHandler * a_handler,CRString * ar_name,CRString * ar_pseudo_page)452 sac_handler_end_page (CRDocHandler *a_handler,
453 					  CRString *ar_name,
454 					  CRString *ar_pseudo_page)
455 {
456 	CssedCssParserData* data;
457 
458 	g_return_if_fail (a_handler);
459 	data = (CssedCssParserData*) a_handler->app_data;
460 	document_write_error_to_program_output ((CssedDoc*) data->doc, _("End Page"), MED_COLOR);
461 }
462 
463 
464 void
sac_handler_ignorable_at_rule(CRDocHandler * a_handler,CRString * ar_name)465 sac_handler_ignorable_at_rule (CRDocHandler * a_handler,  CRString *ar_name)
466 {
467 	guchar *name = NULL;
468 	GString * a_name;
469 
470 	g_return_if_fail (a_handler);
471 	g_return_if_fail (ar_name);
472 
473 	a_name = ar_name->stryng;
474 
475 	fprintf (stdout, "*********************\n");
476 	fprintf (stdout, "ignorable_at_rule\n");
477 
478 	if (a_name && a_name->str)
479 	{
480 		name = g_strndup (a_name->str, a_name->len);
481 	}
482 
483 	if (name)
484 	{
485 		fprintf (stdout, "%s\n", name);
486 		g_free(name);
487 	}
488 
489 	fprintf (stdout, "*********************\n\n");
490 }
491 
492 void
sac_handler_parse_error(CRDocHandler * a_handler,gint line)493 sac_handler_parse_error (CRDocHandler * a_handler, gint line)
494 {
495 	CssedCssParserData* data;
496 	gchar* err;
497 
498 	data = (CssedCssParserData*) a_handler->app_data	;
499 	data->err_count++;
500 	err = g_strdup_printf(_("%s:%d: syntax error (%d)"), data->filename, line+1, data->err_count);
501 	document_write_error_to_program_output ((CssedDoc *) data->doc, err, ERR_COLOR);
502 	g_free(err);
503 }
504 
505 void
sac_handler_fatal_error(CRDocHandler * a_handler)506 sac_handler_fatal_error (CRDocHandler * a_handler)
507 {
508 	CssedCssParserData* data;
509 	data = (CssedCssParserData*) a_handler->app_data	;
510 
511 	document_write_error_to_program_output ((CssedDoc *) data->doc,	_("FATAL error"), ERR_COLOR);
512 }
513 
514 void
init_sac_handler(CRDocHandler * a_handler)515 init_sac_handler (CRDocHandler * a_handler)
516 {
517 	a_handler->start_document = sac_handler_start_document;
518 	a_handler->end_document = sac_handler_end_document;
519 	a_handler->import_style = sac_handler_import_style;
520 	a_handler->namespace_declaration = sac_handler_namespace_declaration;
521 	a_handler->comment = sac_handler_comment;
522 	a_handler->start_selector = sac_handler_start_selector;
523 	a_handler->end_selector = sac_handler_end_selector;
524 	a_handler->property = sac_handler_property;
525 	a_handler->start_font_face = sac_handler_start_font_face;
526 	a_handler->end_font_face = sac_handler_end_font_face;
527 	a_handler->start_media = sac_handler_start_media;
528 	a_handler->end_media = sac_handler_end_media;
529 	a_handler->start_page = sac_handler_start_page;
530 	a_handler->end_page = sac_handler_end_page;
531 	a_handler->ignorable_at_rule = sac_handler_ignorable_at_rule;
532 	a_handler->error = sac_handler_parse_error;
533 	a_handler->unrecoverable_error = sac_handler_fatal_error;
534 }
535 
536 void
init_no_dump_sac_handler(CRDocHandler * a_handler)537 init_no_dump_sac_handler (CRDocHandler * a_handler)
538 {
539 	a_handler->start_document = sac_handler_start_document; // clean previous output
540 	a_handler->end_document = NULL;
541 	a_handler->import_style = NULL;
542 	a_handler->namespace_declaration = NULL;
543 	a_handler->comment = NULL;
544 	a_handler->start_selector = NULL;
545 	a_handler->end_selector = NULL;
546 	a_handler->property = NULL;
547 	a_handler->start_font_face = NULL;
548 	a_handler->end_font_face = NULL;
549 	a_handler->start_media = NULL;
550 	a_handler->end_media = NULL;
551 	a_handler->start_page = NULL;
552 	a_handler->end_page = NULL;
553 	a_handler->ignorable_at_rule = NULL;
554 	a_handler->error = sac_handler_parse_error;
555 	a_handler->unrecoverable_error = NULL;
556 }
557 /* *** SAC HANDLERS END *** */
558 
559 
560 
561 
562 void
cssed_cr_parser_parse_buffer(CssedDoc * doc,gchar * buffer,gint len,gboolean dump)563 cssed_cr_parser_parse_buffer (CssedDoc * doc, gchar * buffer, gint len, gboolean dump)
564 {
565 	enum CRStatus status = CR_OK;
566 	CRDocHandler *handler = { 0 };
567 	CRParser *parser = NULL;
568 	CssedCssParserData* data;
569 	gchar* val_buf;
570 	gchar *filename;
571 	GList* err_list;
572 	CRParserError* cr_err;
573 	CssedCodePage codepage;
574 
575 	data = g_malloc(sizeof(CssedCssParserData));
576 	data->doc = doc;
577 	data->err_count = 0;
578 	data->current_selector = NULL;
579 	data->in_media = FALSE;
580 
581 	filename = document_get_filename(doc);
582 	if( !filename )
583 		filename = g_strdup(_("Untitled"));
584 	data->filename = filename;
585 
586 	codepage = document_get_codepage(doc);
587 
588 	switch( codepage ){
589 		case CSSED_CODEPAGE_DEFAULT:
590 				parser = cr_parser_new_from_buf (buffer, len, CR_ISO_8859_1, FALSE);
591 			break;
592 		case CSSED_CODEPAGE_UTF8:
593 			parser = cr_parser_new_from_buf (buffer, len, CR_UTF_8, FALSE);
594 			break;
595 		case CSSED_CODEPAGE_DBCS:
596 			parser = cr_parser_new_from_buf (buffer, len, CR_UCS_4, FALSE);
597 			break;
598 		default:
599 			parser = cr_parser_new_from_buf (buffer, len, CR_AUTO, FALSE);
600 	}
601 
602 	handler = cr_doc_handler_new ();
603 
604 	if( dump )
605 		init_sac_handler (handler);
606 	else
607 		init_no_dump_sac_handler (handler);
608 
609 	handler->app_data = data;
610 	status = cr_parser_set_sac_handler (parser, handler);
611 
612 	if (status != CR_OK)
613 	{//FIXME say somethig to user
614 		cr_parser_destroy (parser);
615 		g_free(data);
616 		g_free(filename);
617 		return;
618 	}
619 
620 	//g_print("validating buffer: %s\n", buffer);
621 	status = cr_parser_parse (parser);
622 	switch( status ){
623 		case CR_OK:
624 			if( data->err_count > 0 ){
625 				cssed_error_message(_("Validation result ok with errors"),
626 									_("The CSS document can be parsed, but has syntax errors (%d).\nCheck the program output window."),
627 									data->err_count);
628 			}else{
629 				cssed_error_message(_("Validation result ok"),
630 									_("The CSS document is well formed and\ncan be parsed by a browser."));
631 			}
632 			break;
633 		case  CR_ERROR:
634 			cssed_error_message(_("Validation fails"), _("The CSS document is not well formed"));
635 			break;
636 		case  CR_BAD_PARAM_ERROR:
637 		case  CR_INSTANCIATION_FAILED_ERROR:
638 		case  CR_EMPTY_PARSER_INPUT_ERROR:
639 		case  CR_ENCODING_ERROR:
640 		case  CR_ENCODING_NOT_FOUND_ERROR:
641 			cssed_error_message(_("Validation fails"),
642 								_("The validator found an internal error\nand is unable to continue."));
643 			break;
644 		default:
645 			cssed_error_message(_("Validation fails"),
646 								_("The CSS document is not well formed"));
647 			break;
648 	}
649 
650 	err_list = cr_parser_get_error_stack(parser);
651 
652     for ( ;err_list;err_list = err_list->next )
653     {
654 		cr_err = (CRParserError*) err_list->data;
655 		if ( cr_err != NULL ){
656 			val_buf = g_strdup_printf("%s:%d: %s ", filename, ((int) cr_err->line + 1) ,cr_err->msg	);
657 			document_write_error_to_program_output(doc,val_buf,ERR_COLOR);
658 			g_free(val_buf);
659 		}
660 	}
661 
662 	if( err_list ) g_list_free( err_list );
663 	cr_parser_destroy (parser);
664 
665 	if( data->current_selector ) g_free(data->current_selector);
666 	g_free(data);
667 	g_free(filename);
668 }
669 
670