1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16 ////////////////////////////////////////////////////////////
17 // ScheduleXML.c, by Bret Logan (c) 2006
18 //Bare-bones XML reading for Schedule file.
19 //Goal: take a valid Schedule file and put it's data in to a form acceptable to BinauralBeat.
20 //standalone compile command:
21 // g++ ParserXML.cpp -o ParserXML `pkg-config --cflags --libs gtk+-2.0`
22 //or this for C:
23 //gcc -c -Wall -g ScheduleXML.c -o ScheduleXML.o -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -DSCHEDULEGUI_FREESTANDING `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
24
25 #undef G_DISABLE_ASSERT
26 #undef G_LOG_DOMAIN
27
28 #include <stdio.h>
29 #include <stdlib.h> //for free()
30 #include <ctype.h> //for islanum()
31
32 #include <string.h>
33 #include <glib.h>
34
35 #include "ScheduleXML.h"
36
37 #define DBGOUT_STR(a,b) // fprintf(stderr,"ParserXML: %s %s\n",a, b);
38 #define DBGOUT_INT(a,b) // fprintf(stderr,"ParserXML: %s %d\n",a, b);
39 #define DBGOUT_FLT(a,b) // fprintf(stderr,"ParserXML: %s %g\n",a, b);
40 #define DBGOUT_PNT(a,b) // fprintf(stderr,"ParserXML: %s %p\n",a,b);
41 #define DBGOUT(a) // fprintf(stderr,"ParserXML: %s\n",a);
42 #define ERROUT(a) fprintf(stderr,"ParserXML: #Error# %s\n",a);
43
44 /*
45 This is the old format of the data file:
46 <schedule>
47 <date></date>
48 <gnauralfile_version></gnauralfile_version>
49 <gnaural_version></gnaural_version>
50 <title></title>
51 <description></description>
52 <author></author>
53 <totaltime></totaltime>
54 <voicecount></voicecount>
55 <totalentrycount></totalentrycount>
56 <loops></loops>
57 <voice>
58 <description></description>
59 <id></id>
60 <type></type>
61 <voice_state></voice_state>
62 <entrycount></entrycount>
63 <entries>
64 <entry>
65 <parent></parent>
66 <duration></duration>
67 <volume_left></volume_left>
68 <volume_right></volume_right>
69 <beatfreq></beatfreq> //this will hold different data depending on the voice type
70 <basefreq></basefreq> //this will hold different data depending on the voice type
71 <state></state> //just whether the DP was selected or not
72 </entry>
73 </entries>
74 </voice>
75 </schedule>
76
77 This is the new format:
78 <schedule>
79 <gnauralfile_version>1.20060924</gnauralfile_version>
80 <gnaural_version>N/A [ScheduleGUI]</gnaural_version>
81 <date>Sun Sep 24 14:16:07 2006
82 </date>
83 <title>Very Boring Title</title>
84 <schedule_description>Test Built-in Schedule</schedule_description>
85 <author>Bret Logan</author>
86 <totaltime>300</totaltime>
87 <voicecount>1</voicecount>
88 <totalentrycount>1</totalentrycount>
89 <voice>
90 <description>[none]</description>
91 <id>0</id>
92 <type>1</type>
93 <voice_state>1</voice_state>
94 <entrycount>10</entrycount>
95 <entries>
96 <entry parent="0" duration="0.0492881" volume_left="0.132812" volume_right="0.132812" beatfreq="53.1694" basefreq="1164" state="0"/>
97 </entries>
98 </voice>
99 </schedule>
100 */
101
102 ///////////////////////////////////////////////
103 //Global variables:
104 int depth = 0;
105 gchar ParserXML_CurrentElement[512];
106 int ParserXML_AbortFlag = 0;
107 void (*UserParserXMLHandler)(const gchar *, const gchar *, const gchar *) = DefaultParserXMLHandler;
108 GMarkupParser parser = {
109 ParserXML_start_element_handler,
110 ParserXML_end_element_handler,
111 ParserXML_text_handler,
112 ParserXML_passthrough_handler,
113 ParserXML_error_handler
114 };
115 //End globals
116 ///////////////////////////////////////////////
117
118
119
120
121 ///////////////////////////////////////////////
122 //user calls this to set PaserXML to directly invoke user's internal code:
SetUserParserXMLHandler(void (* NewUserParserXMLHandler)(const gchar *,const gchar *,const gchar *))123 void SetUserParserXMLHandler(void (*NewUserParserXMLHandler)(const gchar *, const gchar *, const gchar *)) {
124 UserParserXMLHandler = NewUserParserXMLHandler;
125 }
126
127
128 ///////////////////////////////////////////////
129 //this is an example of how to implement your local/weird/proprietary code:
DefaultParserXMLHandler(const gchar * CurrentElement,const gchar * Attribute,const gchar * Value)130 void DefaultParserXMLHandler(const gchar * CurrentElement, //this must always be a valid string
131 const gchar * Attribute, //beware: this will equal NULL if there are no Atrributes with this Element
132 const gchar * Value) //beware: this will equal NULL to announce end of Element to user
133 {
134 fprintf(stderr, "ParserXML: Element: %s, ", CurrentElement);
135 if (Attribute != NULL) fprintf(stderr, "Atribute: %s, ", Attribute);
136 if (Value != NULL) fprintf(stderr, "Value: %s\n", Value);
137 }
138
139
140 ///////////////////////////////////////////////
ParserXML_start_element_handler(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)141 void ParserXML_start_element_handler (GMarkupParseContext *context,
142 const gchar *element_name,
143 const gchar **attribute_names,
144 const gchar **attribute_values,
145 gpointer user_data,
146 GError **error) {
147 if (ParserXML_AbortFlag != 0) return;
148 ++depth;
149 strcpy(ParserXML_CurrentElement, element_name);
150 DBGOUT_STR("START ", element_name);
151
152 //Process any attributes in this xml (if there are any):
153 int i = 0;
154 while (attribute_names[i] != NULL) {
155 UserParserXMLHandler(ParserXML_CurrentElement, attribute_names[i], attribute_values[i]);
156 DBGOUT_STR(attribute_names[i], attribute_values[i]);
157 ++i;
158 }
159 }
160
161 ///////////////////////////////////////////////
ParserXML_end_element_handler(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)162 void ParserXML_end_element_handler (GMarkupParseContext *context,
163 const gchar *element_name,
164 gpointer user_data,
165 GError **error) {
166 if (ParserXML_AbortFlag != 0) return;
167 --depth;
168
169 //tell user end of element occurred:
170 //NOTE: it is essential to pass local element_name instead of
171 //ParserXML_CurrentElement, because there is no guarantee that
172 //ParserXML_CurrentElement hadn't changed (many times) since the
173 //particular element ending here is announced for user:
174 UserParserXMLHandler(element_name, NULL, NULL);
175
176 DBGOUT_STR("END ", element_name);
177
178 //Erase CurrentElement's text:
179 ParserXML_CurrentElement[0] = '\0';
180 }
181
182
183
184 ///////////////////////////////////////////////
ParserXML_text_handler(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)185 void ParserXML_text_handler (GMarkupParseContext *context,
186 const gchar *text,
187 gsize text_len,
188 gpointer user_data,
189 GError **error) {
190
191 if (ParserXML_AbortFlag != 0) return;
192
193 if (text == NULL) {
194 ERROUT("ParserXML_text_handler: text == NULL!");
195 return;
196 }
197
198
199 //this is actually a critical line; not sure it is really ready for all platforms as-is:
200 if (text[0] == '\0' ||
201 text[0] == '\n' ||
202 text[0] == '\r' ||
203 text[0] == '\t' ||
204 text[0] == ' ')
205 return ;
206
207 // DBGOUT_STR(ParserXML_CurrentElement, text);
208
209 //==================
210 //send to user handler code:
211 UserParserXMLHandler(ParserXML_CurrentElement, NULL, text);
212 //==================
213 }
214
215
216 ///////////////////////////////////////////////
ParserXML_passthrough_handler(GMarkupParseContext * context,const gchar * passthrough_text,gsize text_len,gpointer user_data,GError ** error)217 void ParserXML_passthrough_handler (GMarkupParseContext *context,
218 const gchar *passthrough_text,
219 gsize text_len,
220 gpointer user_data,
221 GError **error) {
222 if (ParserXML_AbortFlag != 0) return;
223
224 DBGOUT_STR ("[passthrough junk]", passthrough_text);
225 }
226
227
228 ///////////////////////////////////////////////
ParserXML_error_handler(GMarkupParseContext * context,GError * error,gpointer user_data)229 void ParserXML_error_handler (GMarkupParseContext *context,
230 GError *error,
231 gpointer user_data) {
232 if (ParserXML_AbortFlag != 0) return;
233
234 DBGOUT_STR("XML Parsing Error", error->message);
235 }
236
237
238 ///////////////////////////////////////////////
ParserXML_parse_file_xml(const gchar * filename)239 int ParserXML_parse_file_xml (const gchar *filename) {
240 gchar *contents;
241 gsize length;
242 GError *error;
243 GMarkupParseContext *context;
244
245 error = NULL;
246 depth = 0;
247 ParserXML_AbortFlag = 0;
248 ParserXML_CurrentElement[0] = '\0';
249
250 //load entire file in to contents:
251 if (FALSE == g_file_get_contents (filename,
252 &contents,
253 &length,
254 &error)) {
255 fprintf (stderr, "%s\n", error->message);
256 g_error_free (error);
257 return 1;
258 }
259
260 //CHOICE: you can parse the entire file at once (and risk having
261 //it abort at the first error and skip all subsequent data)
262 //OR you can parse it in chunks (meaning it keep trying to
263 //parse more data after errors):
264 //To parse the entire file at once, do this:
265 //create the GMarkup context:
266
267 context = g_markup_parse_context_new (&parser, (GMarkupParseFlags) 0, NULL, NULL);
268
269 if (FALSE == g_markup_parse_context_parse (context, contents, length, NULL)) {
270 g_markup_parse_context_free (context);
271 return 1;
272 }
273
274 if (FALSE == g_markup_parse_context_end_parse (context, NULL)) {
275 g_markup_parse_context_free (context);
276 return 1;
277 }
278
279 g_markup_parse_context_free (context);
280 g_free(contents);
281 /*
282 //To parse the file's contents in chunks:
283 #define chunk_size 2048 // you can pick basically anything for this; basically determines how much you are willing to discard on failure
284 context = g_markup_parse_context_new (&parser, (GMarkupParseFlags) 0, NULL, NULL);
285 unsigned int i = 0;
286 while (i < length)
287 {
288 int this_chunk = MIN (length - i, chunk_size);
289
290 if (FALSE == g_markup_parse_context_parse (context,
291 contents + i,
292 this_chunk,
293 NULL))
294 {
295 g_markup_parse_context_free (context);
296 return 1;
297 }
298 i += this_chunk;
299 }
300
301 if (FALSE == g_markup_parse_context_end_parse (context, NULL))
302 {
303 g_markup_parse_context_free (context);
304 return 1;
305 }
306 g_markup_parse_context_free (context);
307 g_free(contents);
308 */
309
310 if (ParserXML_AbortFlag == 0) {
311 DBGOUT_INT("Net Count: ", depth);
312 }
313 return ParserXML_AbortFlag;
314 }
315
316 ///////////////////////////////////////////////
ParserXML_main(int argc,gchar * argv[])317 int ParserXML_main (int argc, gchar *argv[]) {
318 SetUserParserXMLHandler(DefaultParserXMLHandler); //same as this: UserParserXMLHandler = DefaultParserXMLHandler;
319 if (argc > 1)
320 return ParserXML_parse_file_xml (argv[1]);
321 else {
322 fprintf (stderr, "Give a markup file on the command line\n");
323 return 1;
324 }
325 }
326
327
328 ///////////////////////////////////////////////
329 //added 20070130 to parse an already loaded file or
330 //pre-defined XML array:
ParserXML_parse_gchararray_xml(const char * contents,int length)331 int ParserXML_parse_gchararray_xml (const char *contents, int length) {
332 GMarkupParseContext *context;
333 depth = 0;
334 ParserXML_AbortFlag = 0;
335 ParserXML_CurrentElement[0] = '\0';
336
337 //create the GMarkup context:
338 context = g_markup_parse_context_new (&parser, (GMarkupParseFlags) 0, NULL, NULL);
339
340 if (FALSE == g_markup_parse_context_parse (context, contents, length, NULL)) {
341 g_markup_parse_context_free (context);
342 return 1;
343 }
344
345 if (FALSE == g_markup_parse_context_end_parse (context, NULL)) {
346 g_markup_parse_context_free (context);
347 return 1;
348 }
349
350 g_markup_parse_context_free (context);
351
352 if (ParserXML_AbortFlag == 0) {
353 DBGOUT_INT("Net Count: ", depth);
354 }
355 return ParserXML_AbortFlag;
356 }
357