1%include {
2
3/* dtd_parser.lemon
4 * XML dissector for wireshark
5 * XML's DTD grammar
6 *
7 * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
8 *
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
12 *
13 * SPDX-License-Identifier: GPL-2.0-or-later
14 */
15
16#include "config.h"
17
18#include <stdio.h>
19#include <glib.h>
20#include <assert.h>
21#include "dtd.h"
22#include "dtd_parse.h"
23
24static dtd_named_list_t* dtd_named_list_new(gchar* name, GPtrArray* list) {
25	dtd_named_list_t* nl = g_new(dtd_named_list_t,1);
26
27	nl->name = name;
28	nl->list = list;
29
30	return nl;
31}
32
33static GPtrArray* g_ptr_array_join(GPtrArray* a, GPtrArray* b){
34
35	while(b->len > 0) {
36		g_ptr_array_add(a,g_ptr_array_remove_index_fast(b,0));
37	}
38
39	g_ptr_array_free(b,TRUE);
40
41	return a;
42}
43
44}
45
46%name DtdParse
47
48%extra_argument { dtd_build_data_t *bd }
49
50%token_destructor {
51	(void) bd; /* Mark unused, similar to Q_UNUSED */
52	if ($$) {
53		g_free($$->text);
54		g_free($$->location);
55		g_free($$);
56	}
57}
58
59%syntax_error {
60	if (!TOKEN)
61		g_string_append_printf(bd->error,"syntax error at end of file");
62	else
63		g_string_append_printf(bd->error,"syntax error in %s at or before '%s': \n", TOKEN->location,TOKEN->text);
64}
65
66%parse_failure {
67	g_string_append_printf(bd->error,"DTD parsing failure\n");
68}
69
70%token_prefix TOKEN_
71
72%token_type { dtd_token_data_t* }
73
74dtd ::= doctype.
75dtd ::= dtd_parts.
76
77doctype ::= TAG_START DOCTYPE_KW NAME(Name) OPEN_BRACKET dtd_parts CLOSE_BRACKET TAG_STOP. {
78	dtd_named_list_t* root;
79	GPtrArray* root_elems = g_ptr_array_new();
80	guint i;
81	gchar *name;
82
83	if(! bd->proto_name) {
84		bd->proto_name = Name->text;
85	}
86
87	g_free(bd->proto_root);
88
89	bd->proto_root = Name->text;
90
91	name = g_ascii_strdown(bd->proto_name, -1);
92	g_free(bd->proto_name);
93	bd->proto_name = name;
94
95	for( i = 0; i< bd->elements->len; i++) {
96		dtd_named_list_t* el = (dtd_named_list_t*)g_ptr_array_index(bd->elements,i);
97
98		g_ptr_array_add(root_elems,g_strdup(el->name));
99	}
100
101	root = dtd_named_list_new(g_strdup(Name->text),root_elems);
102
103	g_ptr_array_add(bd->elements,root);
104
105	g_free(Name->location);
106	g_free(Name);
107
108}
109
110dtd_parts ::= dtd_parts element(Element). { g_ptr_array_add(bd->elements,Element); }
111dtd_parts ::= dtd_parts attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
112dtd_parts ::= element(Element). { g_ptr_array_add(bd->elements,Element); }
113dtd_parts ::= attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
114
115%type   attlist				{ dtd_named_list_t* }
116attlist(A) ::= TAG_START ATTLIST_KW NAME(B) attrib_list(TheList) TAG_STOP. {
117	A = dtd_named_list_new(g_ascii_strdown(B->text, -1),TheList);
118	g_free(B->text);
119	g_free(B->location);
120	g_free(B);
121}
122
123%type element { dtd_named_list_t* }
124element(A) ::= TAG_START ELEMENT_KW NAME(B) sub_elements(C) TAG_STOP. {
125	A = dtd_named_list_new(g_ascii_strdown(B->text, -1),C);
126	g_free(B->text);
127	g_free(B->location);
128	g_free(B);
129}
130
131%type   attrib_list			{ GPtrArray* }
132attrib_list(A) ::= attrib_list(B) attrib(C). { g_ptr_array_add(B,C); A = B; }
133attrib_list(A) ::= attrib(B).  { A = g_ptr_array_new(); g_ptr_array_add(A,B);  }
134
135%type   attrib				{ gchar* }
136attrib(A) ::= NAME(B) att_type att_default. {
137	A = g_ascii_strdown(B->text, -1);
138	g_free(B->text);
139	g_free(B->location);
140	g_free(B);
141}
142
143att_type ::= ATT_TYPE.
144att_type ::= enumeration.
145
146att_default ::= ATT_DEF.
147att_default ::= ATT_DEF_WITH_VALUE QUOTED.
148att_default ::= QUOTED.
149att_default ::= IMPLIED_KW.
150att_default ::= REQUIRED_KW.
151
152enumeration ::= OPEN_PARENS enum_list CLOSE_PARENS.
153
154enum_list ::= enum_list PIPE enum_item.
155enum_list ::= enum_item.
156enum_list ::= enumeration.
157enum_list ::= enum_list PIPE enumeration.
158
159enum_item ::= NAME.
160enum_item ::= QUOTED.
161
162
163%type   sub_elements		{ GPtrArray* }
164sub_elements(A) ::= sub_elements(B) STAR. {A=B;}
165sub_elements(A) ::= sub_elements(B) PLUS. {A=B;}
166sub_elements(A) ::= sub_elements(B) QUESTION. {A=B;}
167sub_elements(A) ::= OPEN_PARENS ELEM_DATA CLOSE_PARENS. { A = g_ptr_array_new(); }
168sub_elements(A) ::= OPEN_PARENS element_list(B) COMMA ELEM_DATA CLOSE_PARENS.	{ A = B; }
169sub_elements(A) ::= OPEN_PARENS element_list(B) PIPE ELEM_DATA CLOSE_PARENS.	{ A = B; }
170sub_elements(A) ::= OPEN_PARENS element_list(B) CLOSE_PARENS. { A = B; }
171sub_elements(A) ::= EMPTY_KW. { A = g_ptr_array_new(); }
172
173%type   element_list	{ GPtrArray* }
174element_list(A)	::= element_list(B) COMMA element_child(C).	{ g_ptr_array_add(B,C); A = B; }
175element_list(A)	::= element_list(B) PIPE element_child(C).	{ g_ptr_array_add(B,C); A = B; }
176element_list(A)	::= element_child(B).						{ A = g_ptr_array_new(); g_ptr_array_add(A,B); }
177element_list(A) ::= sub_elements(B).						{ A = B; }
178element_list(A) ::= element_list(B) COMMA sub_elements(C).	{ A = g_ptr_array_join(B,C); }
179element_list(A) ::= element_list(B) PIPE sub_elements(C).	{ A = g_ptr_array_join(B,C); }
180
181%type   element_child		{ gchar* }
182element_child(A) ::= NAME(B).			{
183	A = g_ascii_strdown(B->text, -1);
184	g_free(B->text);
185	g_free(B->location);
186	g_free(B);
187}
188
189element_child(A) ::= NAME(B) STAR.		{
190	A = g_ascii_strdown(B->text, -1);
191	g_free(B->text);
192	g_free(B->location);
193	g_free(B);
194}
195
196element_child(A) ::= NAME(B) QUESTION.	{
197	A = g_ascii_strdown(B->text, -1);
198	g_free(B->text);
199	g_free(B->location);
200	g_free(B);
201}
202
203element_child(A) ::= NAME(B) PLUS.		{
204	A = g_ascii_strdown(B->text, -1);
205	g_free(B->text);
206	g_free(B->location);
207	g_free(B);
208}
209
210