1
/* Copyright (C) 2010 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
* Paul McCullagh (H&G2JCtL)
39
#include <boost/algorithm/string.hpp>
40
#define STRCASESTR(s1, s2) boost::ifind_first(s1, s2)
42
#define STRCASESTR(s1, s2) strcasestr(s1, s2)
47
#define ISSPACE(ch) (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
48
#define ISSINGLE(ch) (ch == '*' || ch == '+' || ch == '(' || ch == ')' || ch == ',' || ch == '|' || ch == '[' || ch == ']' || ch == '?' || ch == '/')
50
#define SET_CHAR(x, ch) { x->buffer[0] = ch; x->count = 1; }
51
#define ADD_CHAR(x, ch) { if (x->count < PARSE_BUFFER_SIZE) { x->buffer[x->count] = ch; x->count++; } else x->buffer[PARSE_BUFFER_SIZE-1] = ch; }
53
bool CSXMLParser::match_string(const char *ch)
57
for (i=0; i<this->count; i++) {
58
if (this->buffer[i] != *ch)
64
return(i == this->count);
67
void CSXMLParser::increment_nesting(wchar_t ch)
69
if (this->nesting < PARSE_STACK_SIZE) {
72
this->end_type[this->nesting] = XML_OP_1_END_CLOSE_TAG;
75
this->end_type[this->nesting] = XML_OP_1_END_PI_TAG;
78
this->end_type[this->nesting] = XML_OP_1_END_ENTITY_TAG;
81
this->end_type[this->nesting] = XML_OP_1_END_BRACKET_TAG;
85
this->end_type[this->nesting] = XML_OP_1_END_UNKNOWN_TAG;
87
this->end_type[this->nesting] = XML_OP_1_END_TAG;
94
int32_t CSXMLParser::parseChar(wchar_t ch)
95
/* This function does the actual work of parsing. It is expects
96
* "complete" characters as input. This could be 4 byte characters
97
* as long as it is able to recognize the characters that are
98
* relevant to parsing.
99
* The function outputs processing instructions, and indicates
100
* how the output data is to be understood.
103
switch (this->state) {
104
case XML_BEFORE_CDATA:
106
/* This is the initial state! */
108
this->state = XML_LT;
109
this->type = XML_noop;
112
this->state = XML_IN_CDATA;
113
this->type = XML_CDATA_CH;
119
this->state = XML_LT;
120
this->type = XML_noop;
123
this->type = XML_CDATA_CH;
129
this->state = XML_BEFORE_ATTR;
130
if (this->step == XML_STEP_TAG)
131
this->type = XML_start_tag_TAG_CH;
132
else if (this->step == XML_STEP_NESTED)
133
this->type = XML_TAG_CH;
134
else if (this->step == XML_STEP_NONE)
135
this->type = XML_end_cdata_TAG_CH;
137
this->type = XML_add_attr_TAG_CH;
138
this->step = XML_STEP_TAG;
139
increment_nesting(ch);
143
this->state = XML_IN_CDATA;
144
this->type = XML_CDATA_CH;
148
else if (ch == '!') {
149
this->state = XML_LT_BANG;
150
this->type = XML_noop;
154
this->state = XML_IN_TAG_NAME;
155
if (this->step == XML_STEP_TAG)
156
this->type = XML_start_tag_TAG_CH;
157
else if (this->step == XML_STEP_NESTED)
158
this->type = XML_TAG_CH;
159
else if (this->step == XML_STEP_NONE)
160
this->type = XML_end_cdata_TAG_CH;
162
this->type = XML_add_attr_TAG_CH;
163
this->step = XML_STEP_TAG;
164
increment_nesting(ch);
170
this->state = XML_LT_BANG_DASH;
171
this->type = XML_noop;
173
else if (ch == '[') {
174
this->state = XML_LT_BANG_SQR;
175
this->type = XML_noop;
178
this->state = XML_IN_TAG_NAME;
179
if (this->step == XML_STEP_TAG)
180
this->type = XML_start_tag_TAG_CH;
181
else if (this->step == XML_STEP_NESTED)
182
this->type = XML_TAG_CH;
183
else if (this->step == XML_STEP_NONE)
184
this->type = XML_end_cdata_TAG_CH;
186
this->type = XML_add_attr_TAG_CH;
187
this->step = XML_STEP_TAG;
188
increment_nesting('!');
193
case XML_LT_BANG_DASH:
195
this->state = XML_IN_COMMENT;
196
if (this->step == XML_STEP_TAG)
197
this->type = XML_start_tag_start_comment;
198
else if (this->step == XML_STEP_NESTED)
199
this->type = XML_start_comment;
200
else if (this->step == XML_STEP_NONE)
201
this->type = XML_end_cdata_start_comment;
203
this->type = XML_add_attr_start_comment;
204
increment_nesting(' ');
207
this->state = XML_IN_CDATA;
208
this->type = XML_CDATA_CH;
212
case XML_LT_BANG_SQR:
214
this->type = XML_noop;
215
else if (ch == '[') {
216
this->state = XML_BEFORE_ATTR;
217
if (this->step == XML_STEP_TAG)
218
this->type = XML_start_tag_TAG_CH;
219
else if (this->step == XML_STEP_NESTED)
220
this->type = XML_TAG_CH;
221
else if (this->step == XML_STEP_NONE)
222
this->type = XML_end_cdata_TAG_CH;
224
this->type = XML_add_attr_TAG_CH;
225
this->step = XML_STEP_TAG;
226
increment_nesting('[');
231
this->state = XML_LT_BANG_SQR_IN_NAME;
232
this->type = XML_noop;
238
case XML_LT_BANG_SQR_IN_NAME:
240
this->state = XML_LT_BANG_SQR_AFTER_NAME;
241
this->type = XML_noop;
243
else if (ch == '[') {
244
if (match_string("![CDATA")) {
245
this->state = XML_IN_CDATA_TAG;
246
if (this->step == XML_STEP_TAG)
247
this->type = XML_start_tag_start_cdata_tag;
248
else if (this->step == XML_STEP_NESTED)
249
this->type = XML_start_cdata_tag;
250
else if (this->step == XML_STEP_NONE)
251
this->type = XML_end_cdata_start_cdata_tag;
253
this->type = XML_add_attr_start_cdata_tag;
254
this->step = XML_STEP_TAG;
255
increment_nesting('[');
258
this->state = XML_BEFORE_ATTR;
259
if (this->step == XML_STEP_TAG)
260
this->type = XML_start_tag_TAG_CH;
261
else if (this->step == XML_STEP_NESTED)
262
this->type = XML_TAG_CH;
263
else if (this->step == XML_STEP_NONE)
264
this->type = XML_end_cdata_TAG_CH;
266
this->type = XML_add_attr_TAG_CH;
267
this->step = XML_STEP_TAG;
268
increment_nesting('[');
272
this->type = XML_noop;
276
case XML_LT_BANG_SQR_AFTER_NAME:
278
if (match_string("![CDATA")) {
279
this->state = XML_IN_CDATA_TAG;
280
if (this->step == XML_STEP_TAG)
281
this->type = XML_start_tag_start_cdata_tag;
282
else if (this->step == XML_STEP_NESTED)
283
this->type = XML_start_cdata_tag;
284
else if (this->step == XML_STEP_NONE)
285
this->type = XML_end_cdata_start_cdata_tag;
287
this->type = XML_add_attr_start_cdata_tag;
288
increment_nesting('[');
291
this->state = XML_BEFORE_ATTR;
292
if (this->step == XML_STEP_TAG)
293
this->type = XML_start_tag_TAG_CH;
294
else if (this->step == XML_STEP_NESTED)
295
this->type = XML_TAG_CH;
296
else if (this->step == XML_STEP_NONE)
297
this->type = XML_end_cdata_TAG_CH;
299
this->type = XML_add_attr_TAG_CH;
300
this->step = XML_STEP_TAG;
301
increment_nesting('[');
305
/* Ignore data until the '['!!! */
306
this->type = XML_noop;
308
case XML_IN_TAG_NAME:
310
this->state = XML_BEFORE_ATTR;
311
this->type = XML_noop;
313
else if (ch == '<') {
314
this->state = XML_LT;
315
this->type = XML_noop;
317
else if (ch == '>') {
318
if (this->step == XML_STEP_TAG)
319
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
320
else if (this->step == XML_STEP_NESTED)
321
this->type = XML_end_tag(END_TAG_TYPE(this));
323
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
326
this->step = XML_STEP_NESTED;
327
this->state = XML_BEFORE_ATTR;
330
this->step = XML_STEP_NONE;
331
this->state = XML_IN_CDATA;
334
else if (ch == '"' || ch == '\'') {
335
this->state = XML_QUOTE_BEFORE_VALUE;
337
this->type = XML_noop;
339
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
340
this->state = XML_SLASH;
341
this->type = XML_noop;
343
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
344
this->state = XML_QMARK;
345
this->type = XML_noop;
347
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
348
this->state = XML_SQR;
349
this->type = XML_noop;
351
else if (ISSINGLE(ch)) {
352
this->state = XML_BEFORE_ATTR;
353
if (this->step == XML_STEP_TAG)
354
this->type = XML_start_tag_ATTR_CH;
355
else if (this->step == XML_STEP_NESTED)
356
this->type = XML_ATTR_CH;
358
this->type = XML_add_attr_ATTR_CH;
359
this->step = XML_STEP_ATTR;
363
this->type = XML_TAG_CH;
367
case XML_BEFORE_ATTR:
369
this->type = XML_noop;
370
else if (ch == '<') {
371
this->state = XML_LT;
372
this->type = XML_noop;
374
else if (ch == '>') {
375
if (this->step == XML_STEP_TAG)
376
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
377
else if (this->step == XML_STEP_NESTED)
378
this->type = XML_end_tag(END_TAG_TYPE(this));
380
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
383
this->step = XML_STEP_NESTED;
384
this->state = XML_BEFORE_ATTR;
387
this->step = XML_STEP_NONE;
388
this->state = XML_IN_CDATA;
391
else if (ch == '"' || ch == '\'') {
392
this->state = XML_QUOTE_BEFORE_VALUE;
394
this->type = XML_noop;
396
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
397
this->state = XML_SLASH;
398
this->type = XML_noop;
400
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
401
this->state = XML_QMARK;
402
this->type = XML_noop;
404
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
405
this->state = XML_SQR;
406
this->type = XML_noop;
408
else if (ISSINGLE(ch)) {
409
if (this->step == XML_STEP_TAG)
410
this->type = XML_start_tag_ATTR_CH;
411
else if (this->step == XML_STEP_NESTED)
412
this->type = XML_ATTR_CH;
414
this->type = XML_add_attr_ATTR_CH;
415
this->step = XML_STEP_ATTR;
419
this->state = XML_IN_ATTR;
420
if (this->step == XML_STEP_TAG)
421
this->type = XML_start_tag_ATTR_CH;
422
else if (this->step == XML_STEP_NESTED)
423
this->type = XML_ATTR_CH;
425
this->type = XML_add_attr_ATTR_CH;
426
this->step = XML_STEP_ATTR;
432
this->state = XML_BEFORE_EQUAL;
433
this->type = XML_noop;
435
else if (ch == '<') {
436
this->state = XML_LT;
437
this->type = XML_noop;
439
else if (ch == '>') {
440
if (this->step == XML_STEP_TAG)
441
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
442
else if (this->step == XML_STEP_NESTED)
443
this->type = XML_end_tag(END_TAG_TYPE(this));
445
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
448
this->step = XML_STEP_NESTED;
449
this->state = XML_BEFORE_ATTR;
452
this->step = XML_STEP_NONE;
453
this->state = XML_IN_CDATA;
456
else if (ch == '"' || ch == '\'') {
457
this->state = XML_QUOTE_BEFORE_VALUE;
459
this->type = XML_noop;
461
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
462
this->state = XML_SLASH;
463
this->type = XML_noop;
465
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
466
this->state = XML_QMARK;
467
this->type = XML_noop;
469
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
470
this->state = XML_SQR;
471
this->type = XML_noop;
473
else if (ISSINGLE(ch)) {
474
this->state = XML_BEFORE_ATTR;
475
if (this->step == XML_STEP_TAG)
476
this->type = XML_start_tag_ATTR_CH;
477
else if (this->step == XML_STEP_NESTED)
478
this->type = XML_ATTR_CH;
480
this->type = XML_add_attr_ATTR_CH;
481
this->step = XML_STEP_ATTR;
484
else if (ch == '=') {
485
this->state = XML_AFTER_EQUAL;
486
this->type = XML_noop;
489
this->type = XML_ATTR_CH;
493
case XML_BEFORE_EQUAL:
495
this->type = XML_noop;
496
else if (ch == '<') {
497
this->state = XML_LT;
498
this->type = XML_noop;
500
else if (ch == '>') {
501
if (this->step == XML_STEP_TAG)
502
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
503
else if (this->step == XML_STEP_NESTED)
504
this->type = XML_end_tag(END_TAG_TYPE(this));
506
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
509
this->step = XML_STEP_NESTED;
510
this->state = XML_BEFORE_ATTR;
513
this->step = XML_STEP_NONE;
514
this->state = XML_IN_CDATA;
517
else if (ch == '"' || ch == '\'') {
518
this->state = XML_QUOTE_BEFORE_VALUE;
520
this->type = XML_noop;
522
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
523
this->state = XML_SLASH;
524
this->type = XML_noop;
526
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
527
this->state = XML_QMARK;
528
this->type = XML_noop;
530
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
531
this->state = XML_SQR;
532
this->type = XML_noop;
534
else if (ISSINGLE(ch)) {
535
this->state = XML_BEFORE_ATTR;
536
if (this->step == XML_STEP_TAG)
537
this->type = XML_start_tag_ATTR_CH;
538
else if (this->step == XML_STEP_NESTED)
539
this->type = XML_ATTR_CH;
541
this->type = XML_add_attr_ATTR_CH;
542
this->step = XML_STEP_ATTR;
545
else if (ch == '=') {
546
this->state = XML_AFTER_EQUAL;
547
this->type = XML_noop;
550
this->state = XML_IN_ATTR;
551
if (this->step == XML_STEP_TAG)
552
this->type = XML_start_tag_ATTR_CH;
553
else if (this->step == XML_STEP_NESTED)
554
this->type = XML_ATTR_CH;
556
this->type = XML_add_attr_ATTR_CH;
557
this->step = XML_STEP_ATTR;
561
case XML_AFTER_EQUAL:
563
this->state = XML_AFTER_EQUAL;
564
this->type = XML_noop;
566
else if (ch == '<') {
567
this->state = XML_LT;
568
this->type = XML_noop;
570
else if (ch == '>') {
571
if (this->step == XML_STEP_TAG)
572
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
573
else if (this->step == XML_STEP_NESTED)
574
this->type = XML_end_tag(END_TAG_TYPE(this));
576
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
579
this->step = XML_STEP_NESTED;
580
this->state = XML_BEFORE_ATTR;
583
this->step = XML_STEP_NONE;
584
this->state = XML_IN_CDATA;
587
else if (ch == '"' || ch == '\'') {
588
this->state = XML_QUOTE_BEFORE_VALUE;
590
this->type = XML_noop;
592
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
593
this->state = XML_SLASH;
594
this->type = XML_noop;
596
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
597
this->state = XML_QMARK;
598
this->type = XML_noop;
600
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
601
this->state = XML_SQR;
602
this->type = XML_noop;
604
else if (ISSINGLE(ch)) {
605
this->state = XML_BEFORE_ATTR;
606
if (this->step == XML_STEP_TAG)
607
this->type = XML_start_tag_ATTR_CH;
608
else if (this->step == XML_STEP_NESTED)
609
this->type = XML_ATTR_CH;
611
this->type = XML_add_attr_ATTR_CH;
612
this->step = XML_STEP_ATTR;
616
this->state = XML_IN_VALUE;
618
if (this->step == XML_STEP_TAG)
619
this->type = XML_start_tag_VALUE_CH;
620
else if (this->step == XML_STEP_VALUE)
621
this->type = XML_add_attr_VALUE_CH;
623
this->type = XML_VALUE_CH;
624
this->step = XML_STEP_VALUE;
628
case XML_QUOTE_BEFORE_VALUE:
629
if (ch == this->quote) {
630
this->state = XML_QUOTE_AFTER_VALUE;
632
if (this->step == XML_STEP_TAG)
633
this->type = XML_start_tag_VALUE_CH;
634
else if (this->step == XML_STEP_VALUE)
635
this->type = XML_add_attr_VALUE_CH;
637
this->type = XML_VALUE_CH;
638
this->step = XML_STEP_VALUE;
642
this->state = XML_IN_VALUE;
643
if (this->step == XML_STEP_TAG)
644
this->type = XML_start_tag_VALUE_CH;
645
else if (this->step == XML_STEP_VALUE)
646
this->type = XML_add_attr_VALUE_CH;
648
this->type = XML_VALUE_CH;
649
this->step = XML_STEP_VALUE;
655
if (ch == this->quote) {
656
this->state = XML_QUOTE_AFTER_VALUE;
657
this->type = XML_noop;
660
this->type = XML_VALUE_CH;
665
/* A value without quotes (for HTML!) */
667
this->state = XML_BEFORE_ATTR;
668
this->type = XML_noop;
670
else if (ch == '<') {
671
this->state = XML_LT;
672
this->type = XML_noop;
674
else if (ch == '>') {
675
if (this->step == XML_STEP_TAG)
676
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
677
else if (this->step == XML_STEP_NESTED)
678
this->type = XML_end_tag(END_TAG_TYPE(this));
680
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
683
this->step = XML_STEP_NESTED;
684
this->state = XML_BEFORE_ATTR;
687
this->step = XML_STEP_NONE;
688
this->state = XML_IN_CDATA;
691
else if (ch == '"' || ch == '\'') {
692
this->state = XML_QUOTE_BEFORE_VALUE;
694
this->type = XML_noop;
697
this->type = XML_VALUE_CH;
702
case XML_QUOTE_AFTER_VALUE:
704
this->state = XML_BEFORE_ATTR;
705
this->type = XML_noop;
707
else if (ch == '<') {
708
this->state = XML_LT;
709
this->type = XML_noop;
711
else if (ch == '>') {
712
if (this->step == XML_STEP_TAG)
713
this->type = XML_start_tag_end_tag(END_TAG_TYPE(this));
714
else if (this->step == XML_STEP_NESTED)
715
this->type = XML_end_tag(END_TAG_TYPE(this));
717
this->type = XML_add_attr_end_tag(END_TAG_TYPE(this));
720
this->step = XML_STEP_NESTED;
721
this->state = XML_BEFORE_ATTR;
724
this->step = XML_STEP_NONE;
725
this->state = XML_IN_CDATA;
728
else if (ch == '"' || ch == '\'') {
729
this->state = XML_QUOTE_BEFORE_VALUE;
731
this->type = XML_noop;
733
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
734
this->state = XML_SLASH;
735
this->type = XML_noop;
737
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
738
this->state = XML_QMARK;
739
this->type = XML_noop;
741
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
742
this->state = XML_SQR;
743
this->type = XML_noop;
745
else if (ISSINGLE(ch)) {
746
this->state = XML_BEFORE_ATTR;
747
if (this->step == XML_STEP_TAG)
748
this->type = XML_start_tag_ATTR_CH;
749
else if (this->step == XML_STEP_NESTED)
750
this->type = XML_ATTR_CH;
752
this->type = XML_add_attr_ATTR_CH;
753
this->step = XML_STEP_ATTR;
757
this->state = XML_IN_ATTR;
758
if (this->step == XML_STEP_TAG)
759
this->type = XML_start_tag_ATTR_CH;
760
else if (this->step == XML_STEP_NESTED)
761
this->type = XML_ATTR_CH;
763
this->type = XML_add_attr_ATTR_CH;
764
this->step = XML_STEP_ATTR;
778
this->state = XML_BEFORE_ATTR;
779
if (this->step == XML_STEP_TAG)
780
this->type = XML_start_tag_TAG_CH;
781
else if (this->step == XML_STEP_NESTED)
782
this->type = XML_TAG_CH;
783
else if (this->step == XML_STEP_NONE)
784
this->type = XML_end_cdata_TAG_CH;
786
this->type = XML_add_attr_TAG_CH;
787
this->step = XML_STEP_ATTR;
789
else if (ch == '<') {
790
this->state = XML_LT;
791
if (this->step == XML_STEP_TAG)
792
this->type = XML_start_tag_TAG_CH;
793
else if (this->step == XML_STEP_NESTED)
794
this->type = XML_TAG_CH;
795
else if (this->step == XML_STEP_NONE)
796
this->type = XML_end_cdata_TAG_CH;
798
this->type = XML_add_attr_TAG_CH;
799
this->step = XML_STEP_TAG;
801
else if (ch == '>') {
802
if (this->state == XML_SLASH) {
803
if (this->step == XML_STEP_TAG)
804
this->type = XML_start_tag_end_empty_tag;
805
else if (this->step == XML_STEP_NESTED)
806
this->type = XML_end_empty_tag;
808
this->type = XML_add_attr_end_empty_tag;
810
else if (this->state == XML_SQR) {
811
if (this->step == XML_STEP_TAG)
812
this->type = XML_start_tag_end_tag(XML_OP_1_END_BRACKET_TAG);
813
else if (this->step == XML_STEP_NESTED)
814
this->type = XML_end_tag(XML_OP_1_END_BRACKET_TAG);
816
this->type = XML_add_attr_end_tag(XML_OP_1_END_BRACKET_TAG);
819
if (this->step == XML_STEP_TAG)
820
this->type = XML_start_tag_end_pi_tag;
821
else if (this->step == XML_STEP_NESTED)
822
this->type = XML_end_pi_tag;
824
this->type = XML_add_attr_end_pi_tag;
828
this->step = XML_STEP_NESTED;
829
this->state = XML_BEFORE_ATTR;
832
this->step = XML_STEP_NONE;
833
this->state = XML_IN_CDATA;
836
else if (ch == '"' || ch == '\'') {
837
this->state = XML_QUOTE_BEFORE_VALUE;
839
if (this->step == XML_STEP_TAG)
840
this->type = XML_start_tag_TAG_CH;
841
else if (this->step == XML_STEP_NESTED)
842
this->type = XML_TAG_CH;
843
else if (this->step == XML_STEP_NONE)
844
this->type = XML_end_cdata_TAG_CH;
846
this->type = XML_add_attr_TAG_CH;
847
this->step = XML_STEP_ATTR;
849
else if (ch == '/' && (END_TAG_TYPE(this) == XML_OP_1_END_TAG)) {
850
this->state = XML_SLASH;
851
if (this->step == XML_STEP_TAG)
852
this->type = XML_start_tag_TAG_CH;
853
else if (this->step == XML_STEP_NESTED)
854
this->type = XML_TAG_CH;
855
else if (this->step == XML_STEP_NONE)
856
this->type = XML_end_cdata_TAG_CH;
858
this->type = XML_add_attr_TAG_CH;
859
this->step = XML_STEP_ATTR;
861
else if (ch == '?' && (END_TAG_TYPE(this) == XML_OP_1_END_PI_TAG)) {
862
this->state = XML_QMARK;
863
if (this->step == XML_STEP_TAG)
864
this->type = XML_start_tag_TAG_CH;
865
else if (this->step == XML_STEP_NESTED)
866
this->type = XML_TAG_CH;
867
else if (this->step == XML_STEP_NONE)
868
this->type = XML_end_cdata_TAG_CH;
870
this->type = XML_add_attr_TAG_CH;
871
this->step = XML_STEP_ATTR;
873
else if (ch == ']' && (END_TAG_TYPE(this) == XML_OP_1_END_BRACKET_TAG)) {
874
this->state = XML_SQR;
875
if (this->step == XML_STEP_TAG)
876
this->type = XML_start_tag_TAG_CH;
877
else if (this->step == XML_STEP_NESTED)
878
this->type = XML_TAG_CH;
879
else if (this->step == XML_STEP_NONE)
880
this->type = XML_end_cdata_TAG_CH;
882
this->type = XML_add_attr_TAG_CH;
883
this->step = XML_STEP_ATTR;
885
else if (ISSINGLE(ch)) {
886
this->state = XML_BEFORE_ATTR;
887
if (this->step == XML_STEP_TAG)
888
this->type = XML_start_tag_TAG_CH;
889
else if (this->step == XML_STEP_NESTED)
890
this->type = XML_TAG_CH;
891
else if (this->step == XML_STEP_NONE)
892
this->type = XML_end_cdata_TAG_CH;
894
this->type = XML_add_attr_TAG_CH;
895
this->step = XML_STEP_ATTR;
899
this->state = XML_IN_ATTR;
900
if (this->step == XML_STEP_TAG)
901
this->type = XML_start_tag_TAG_CH;
902
else if (this->step == XML_STEP_NESTED)
903
this->type = XML_TAG_CH;
904
else if (this->step == XML_STEP_NONE)
905
this->type = XML_end_cdata_TAG_CH;
907
this->type = XML_add_attr_TAG_CH;
908
this->step = XML_STEP_ATTR;
914
this->state = XML_IN_COMMENT_DASH;
915
this->type = XML_noop;
918
this->type = XML_COMMENT_CH;
921
case XML_IN_COMMENT_DASH:
923
this->state = XML_IN_COMMENT_DASH_DASH;
924
this->type = XML_noop;
927
this->state = XML_IN_COMMENT;
928
this->type = XML_COMMENT_CH;
932
case XML_IN_COMMENT_DASH_DASH:
934
this->state = XML_IN_COMMENT_3_DASH;
935
this->type = XML_COMMENT_CH;
938
else if (ch == '>') {
939
this->type = XML_end_comment;
942
this->step = XML_STEP_NESTED;
943
this->state = XML_BEFORE_ATTR;
946
this->step = XML_STEP_NONE;
947
this->state = XML_IN_CDATA;
951
this->state = XML_IN_COMMENT;
952
this->type = XML_COMMENT_CH;
956
case XML_IN_COMMENT_3_DASH:
958
this->type = XML_COMMENT_CH;
961
else if (ch == '>') {
962
this->type = XML_end_comment;
965
this->step = XML_STEP_NESTED;
966
this->state = XML_BEFORE_ATTR;
969
this->step = XML_STEP_NONE;
970
this->state = XML_IN_CDATA;
974
this->state = XML_IN_COMMENT;
975
this->type = XML_COMMENT_CH;
981
case XML_IN_CDATA_TAG:
983
this->state = XML_IN_CDATA_TAG_SQR;
984
this->type = XML_noop;
987
this->type = XML_CDATA_TAG_CH;
990
case XML_IN_CDATA_TAG_SQR:
992
this->state = XML_IN_CDATA_TAG_SQR_SQR;
993
this->type = XML_noop;
996
this->state = XML_IN_CDATA_TAG;
997
this->type = XML_CDATA_TAG_CH;
1001
case XML_IN_CDATA_TAG_SQR_SQR:
1003
this->state = XML_IN_CDATA_TAG_3_SQR;
1004
this->type = XML_CDATA_TAG_CH;
1007
else if (ch == '>') {
1008
this->type = XML_end_cdata_tag;
1010
if (this->nesting) {
1011
this->step = XML_STEP_NESTED;
1012
this->state = XML_BEFORE_ATTR;
1015
this->step = XML_STEP_NONE;
1016
this->state = XML_IN_CDATA;
1020
this->state = XML_IN_CDATA_TAG;
1021
this->type = XML_CDATA_TAG_CH;
1025
case XML_IN_CDATA_TAG_3_SQR:
1027
this->type = XML_CDATA_TAG_CH;
1030
else if (ch == '>') {
1031
this->type = XML_end_cdata_tag;
1033
if (this->nesting) {
1034
this->step = XML_STEP_NESTED;
1035
this->state = XML_BEFORE_ATTR;
1038
this->step = XML_STEP_NONE;
1039
this->state = XML_IN_CDATA;
1043
this->state = XML_IN_CDATA_TAG;
1044
this->type = XML_CDATA_TAG_CH;
1045
SET_CHAR(this, ']');
1046
ADD_CHAR(this, ']');
1054
/* ------------------------------------------------------------------- */
1055
/* CSXMLProcessor */
1057
bool CSXMLProcessor::buildConversionTable()
1061
/* By default we don't know how to convert any charset
1062
* other tha ISO-1 to unicode!
1064
if (strcasecmp(charset, "ISO-8859-1") == 0) {
1065
for (i=0; i<128; i++)
1066
conversion_table[i] = (wchar_t) (i + 128);
1069
for (i=0; i<128; i++)
1070
conversion_table[i] = '?';
1075
// Private use are: E000 - F8FF
1077
int32_t CSXMLProcessor::capture_initializer(wchar_t ch)
1078
/* We capture tag and attribute data for the parsing purposes.
1079
* The buffers are initialized here (at the lowest level)
1080
* of processing after parsing.
1086
switch (op & XML_OP_1_MASK) {
1087
case XML_OP_1_START_TAG:
1090
case XML_OP_1_ADD_ATTR:
1098
int32_t CSXMLProcessor::entity_translator(wchar_t ch)
1099
/* This function handles entities.
1100
* Certain entities are translated into UNICODE characters.
1101
* Strictly speaking, these enties are only recognised by HTML.
1102
* The few entities that are recognised by XML are first translated
1103
* into some reserved characters for the parser. This is to ensure
1104
* that the parser does not recognize them as characters with special
1105
* meaning! This includes '&', '<' and '>'.
1110
op = capture_initializer(ch);
1115
* This function translates the input character stream into UNICODE.
1117
int32_t CSXMLProcessor::charset_transformer(wchar_t ch)
1121
// Do transformation according to the charset.
1122
switch (this->charset_type) {
1124
if (ch > 127 && ch < 256) {
1126
uint8_t utf_ch = (uint8_t)ch;
1128
if ((utf_ch & 0xC0) != 0x80)
1129
this->utf8_count = 0;
1130
if ((utf_ch & 0x80) == 0x00)
1131
this->utf8_length = 1;
1132
else if ((utf_ch & 0xE0) == 0xC0)
1133
this->utf8_length = 2;
1134
else if ((utf_ch & 0xF0) == 0xE0)
1135
this->utf8_length = 3;
1136
else if ((utf_ch & 0xF8) == 0xF0)
1137
this->utf8_length = 4;
1138
else if ((utf_ch & 0xFC) == 0xF8)
1139
this->utf8_length = 5;
1140
else if ((utf_ch & 0xFE) == 0xFC)
1141
this->utf8_length = 6;
1142
this->utf8_buffer[this->utf8_count] = (uint32_t) utf_ch;
1144
if (this->utf8_count < this->utf8_length) {
1145
// I need more bytes!
1146
setDataType(XML_noop);
1150
switch (this->utf8_length) {
1152
utf_value = this->utf8_buffer[0] & 0x0000007F;
1155
utf_value = ((this->utf8_buffer[0] & 0x0000001F) << 6) |
1156
(this->utf8_buffer[1] & 0x0000003F);
1157
if (utf_value < 0x00000080)
1161
utf_value = ((this->utf8_buffer[0] & 0x0000000F) << 12) |
1162
((this->utf8_buffer[1] & 0x0000003F) << 6) |
1163
(this->utf8_buffer[2] & 0x0000003F);
1164
if (utf_value < 0x000000800)
1168
utf_value = ((this->utf8_buffer[0] & 0x00000007) << 18) |
1169
((this->utf8_buffer[1] & 0x0000003F) << 12) |
1170
((this->utf8_buffer[2] & 0x0000003F) << 6) |
1171
(this->utf8_buffer[3] & 0x0000003F);
1172
if (utf_value < 0x00010000)
1176
utf_value = ((this->utf8_buffer[0] & 0x00000003) << 24) |
1177
((this->utf8_buffer[1] & 0x0000003F) << 18) |
1178
((this->utf8_buffer[2] & 0x0000003F) << 12) |
1179
((this->utf8_buffer[3] & 0x0000003F) << 6) |
1180
(this->utf8_buffer[4] & 0x0000003F);
1181
if (utf_value < 0x00200000)
1185
utf_value = ((this->utf8_buffer[0] & 0x00000001) << 30) |
1186
((this->utf8_buffer[1] & 0x0000003F) << 24) |
1187
((this->utf8_buffer[2] & 0x0000003F) << 18) |
1188
((this->utf8_buffer[3] & 0x0000003F) << 12) |
1189
((this->utf8_buffer[4] & 0x0000003F) << 6) |
1190
(this->utf8_buffer[5] & 0x0000003F);
1191
if (utf_value < 0x04000000)
1195
if (utf_value > 0x0000FFFF)
1201
case CHARSET_TO_CONVERT_8_BIT:
1202
if (ch > 127 && ch < 256)
1203
ch = this->conversion_table[((unsigned char) ch) - 128];
1207
op = entity_translator(ch);
1209
// Determine the characters set:
1210
switch (op & XML_OP_1_MASK) {
1211
case XML_OP_1_START_TAG:
1212
if (strcmp(this->pr_tag, "?xml") == 0)
1217
case XML_OP_1_ADD_ATTR:
1219
if (strcasecmp(this->pr_name, "encoding") == 0) {
1220
strcpy(this->charset, this->pr_value);
1221
if (STRCASESTR(this->charset, "utf-8"))
1222
this->charset_type = CHARSET_UTF_8;
1223
else if (STRCASESTR(this->charset, "ucs-2") ||
1224
STRCASESTR(this->charset, "ucs-4") ||
1225
STRCASESTR(this->charset, "unicode"))
1226
this->charset_type = CHARSET_STANDARD;
1228
this->charset_type = CHARSET_TO_CONVERT_8_BIT;
1229
buildConversionTable();
1238
void CSXMLProcessor::appendWCharToString(char *dstr, size_t *dlen, size_t dsize, wchar_t *schars, size_t slen)
1240
for (size_t i=0; i < slen; i++) {
1241
if (*dlen < dsize-1) {
1245
dstr[*dlen] = (char)*schars;
1253
int32_t CSXMLProcessor::processChar(wchar_t ch)
1257
op = charset_transformer(ch);
1260
* Capture output tag and attribute data.
1261
* This must be done at the highest level, after
1264
switch (op & XML_DATA_MASK) {
1266
appendWCharToString(this->pr_tag, &this->tlength, CS_MAX_XML_NAME_SIZE, this->getDataPtr(), this->getDataLen());
1269
appendWCharToString(this->pr_name, &this->nlength, CS_MAX_XML_NAME_SIZE, this->getDataPtr(), this->getDataLen());
1271
case XML_DATA_VALUE:
1272
appendWCharToString(this->pr_value, &this->vlength, CS_MAX_XML_NAME_SIZE, this->getDataPtr(), this->getDataLen());
1278
bool CSXMLProcessor::getError(int32_t *err, char **msg)
1285
void CSXMLProcessor::setError(int32_t err, char *msg)
1289
strncpy(err_message, msg, CS_XML_ERR_MSG_SIZE);
1290
err_message[CS_XML_ERR_MSG_SIZE-1] = 0;
1295
case CS_XML_ERR_OUT_OF_MEMORY:
1296
snprintf(err_message, CS_XML_ERR_MSG_SIZE, "AES parse error- insufficient memory");
1298
case CS_XML_ERR_CHAR_TOO_LARGE:
1299
snprintf(err_message, CS_XML_ERR_MSG_SIZE, "AES parse error- UNICODE character too large to be encoded as UTF-8");
1302
snprintf(err_message, CS_XML_ERR_MSG_SIZE, "AES parse error- %s", strerror(err));
1307
void CSXMLProcessor::printError(char *prefix)
1309
printf("%s%s", prefix, err_message);
1312
/* ------------------------------------------------------------------- */
1316
#define EXTRA_SIZE 2
1318
#define EXTRA_SIZE 100
1321
bool CSXMLString::addChar(char ch, CSXMLProcessor *xml)
1325
if (stringLen + 2 > stringSize) {
1326
if (!(ptr = (char *) realloc(stringPtr, stringLen + 2 + EXTRA_SIZE))) {
1327
xml->setError(CS_XML_ERR_OUT_OF_MEMORY, NULL);
1331
stringSize = stringLen + 2 + EXTRA_SIZE;
1333
stringPtr[stringLen] = ch;
1334
stringPtr[stringLen+1] = 0;
1339
bool CSXMLString::addChars(size_t size, wchar_t *buffer, bool to_lower, CSXMLProcessor *xml)
1345
for (i=0; i<size; i++) {
1346
uni_char = (uint32_t) buffer[i];
1348
/* Convertion to lower only done for ASCII! */
1349
if (to_lower && uni_char <= 127)
1350
uni_char = (uint32_t) tolower((int32_t) uni_char);
1352
// Convert to UTF-8!
1353
if (uni_char <= 0x0000007F) {
1354
if (!addChar((char) uni_char, xml))
1358
else if (uni_char <= 0x000007FF) {
1359
if (!addChar((char) ((0x000000C0) | ((uni_char >> 6) & 0x0000001F)), xml))
1363
else if (uni_char <= 0x00000FFFF) {
1364
if (!addChar((char) ((0x000000E0) | ((uni_char >> 12) & 0x0000000F)), xml))
1368
else if (uni_char <= 0x001FFFFF) {
1369
if (!addChar((char) ((0x000000F0) | ((uni_char >> 18) & 0x00000007)), xml))
1373
else if (uni_char <= 0x003FFFFFF) {
1374
if (!addChar((char) ((0x000000F0) | ((uni_char >> 24) & 0x00000003)), xml))
1378
else if (uni_char <= 0x07FFFFFFF) {
1379
if (!addChar((char) ((0x000000F0) | ((uni_char >> 30) & 0x00000001)), xml))
1384
xml->setError(CS_XML_ERR_CHAR_TOO_LARGE, NULL);
1388
while (shift >= 0) {
1389
if (!addChar((char) ((0x00000080) | ((uni_char >> shift) & 0x0000003F)), xml))
1397
bool CSXMLString::addString(const char *string, CSXMLProcessor *xml)
1401
while (*string && ok) {
1402
ok = addChar(*string, xml);
1408
void CSXMLString::setEmpty()
1415
void CSXMLString::setNull()
1423
char *CSXMLString::lastComponent()
1430
ptr = stringPtr + stringLen - 1;
1431
while (ptr > stringPtr && *ptr != '/')
1436
/* We assume comp begins with a '/' */
1437
char *CSXMLString::findTrailingComponent(const char *comp)
1439
char *ptr, *last_slash;
1444
ptr = stringPtr + stringLen - 1;
1448
/* Find the next '/' */
1449
while (ptr > stringPtr && *ptr != '/')
1453
if (strcmp(ptr, comp) == 0) {
1463
while (ptr > stringPtr);
1467
void CSXMLString::truncate(char *ptr)
1470
stringLen = ptr - stringPtr;
1473
/* ------------------------------------------------------------------- */
1476
#define IS_XML_CDATA 0
1477
#define IS_XML_CDATA_TAG 1
1478
#define IS_XML_TAG 2
1479
#define IS_XML_CLOSE_TAG 3
1480
#define IS_XML_COMMENT 4
1481
#define IS_XML_DTD 5
1483
#define IS_XML_PI_XML 7
1484
#define IS_XML_IN_EX 8
1485
#define IS_XML_OPEN_BRACKET 9
1486
#define IS_XML_CLOSE_BRACKET 10
1488
int32_t CSXML::nodeType(char *name)
1493
return IS_XML_CDATA;
1495
if (strlen(name) == 1)
1496
return IS_XML_OPEN_BRACKET;
1499
if (strlen(name) == 1)
1500
return IS_XML_CLOSE_BRACKET;
1503
return IS_XML_CLOSE_TAG;
1505
if (strlen(name) > 1) {
1506
if (strcasecmp(name, "!--") == 0)
1507
return IS_XML_COMMENT;
1508
if (name[1] == '[') {
1509
if (strcasecmp(name, "![CDATA[") == 0)
1510
return IS_XML_CDATA_TAG;
1511
return IS_XML_IN_EX;
1516
if (strcasecmp(name, "?xml") == 0)
1517
return IS_XML_PI_XML;
1522
return IS_XML_CDATA;
1525
bool CSXML::internalCloseNode(const char *name, bool single)
1531
if ((ptr = xml_path.lastComponent())) {
1532
ok = closeNode(xml_path.stringPtr);
1533
xml_path.truncate(ptr);
1536
else if ((ptr = xml_path.findTrailingComponent(name))) {
1537
/* Close the node that is named above. If the XML is
1538
* correct, then the node should be at the top of the
1539
* node stack (last element of the path).
1541
* If not found, "ignore" the close.
1543
* If not found on the top of the node stack, then
1544
* we close serveral nodes.
1547
if (!(ptr = xml_path.lastComponent()))
1549
if (!(ok = closeNode(xml_path.stringPtr)))
1551
if (strcmp(ptr, name) == 0) {
1552
xml_path.truncate(ptr);
1555
xml_path.truncate(ptr);
1561
bool CSXML::internalOpenNode(const char *name)
1565
ok = xml_path.addString("/", this);
1568
ok = xml_path.addString(name, this);
1571
return openNode(this->xml_path.stringPtr, this->xml_value.stringPtr);
1574
bool CSXML::parseXML(int32_t my_flags)
1581
this->flags = my_flags;
1582
ok = xml_path.addChars(0, NULL, false, this);
1585
ok = xml_name.addChars(0, NULL, false, this);
1588
ok = xml_value.addChars(0, NULL, false, this);
1593
while (ch != CS_XML_EOF_CHAR && ok) {
1594
op = processChar(ch);
1595
switch (op & XML_OP_1_MASK) {
1598
case XML_OP_1_END_TAG:
1600
case XML_OP_1_END_CLOSE_TAG:
1602
case XML_OP_1_END_EMPTY_TAG:
1603
ok = internalCloseNode("/>", true);
1605
case XML_OP_1_END_PI_TAG:
1606
ok = internalCloseNode("?>", true);
1608
case XML_OP_1_END_ENTITY_TAG:
1609
ok = internalCloseNode(">", true);
1611
case XML_OP_1_END_BRACKET_TAG:
1612
ok = internalCloseNode("]>", true);
1614
case XML_OP_1_END_UNKNOWN_TAG:
1615
ok = internalCloseNode(">", true);
1617
case XML_OP_1_START_CDATA_TAG:
1619
case XML_OP_1_START_COMMENT:
1621
case XML_OP_1_START_TAG:
1622
if (nodeType(xml_name.stringPtr) == IS_XML_CLOSE_TAG)
1623
ok = internalCloseNode(xml_name.stringPtr, false);
1625
ok = internalOpenNode(xml_name.stringPtr);
1626
xml_name.setEmpty();
1627
xml_value.setEmpty();
1629
case XML_OP_1_ADD_ATTR:
1630
tagtype = nodeType(xml_name.stringPtr);
1631
if (tagtype != IS_XML_OPEN_BRACKET && tagtype != IS_XML_CLOSE_BRACKET)
1632
ok = addAttribute(xml_path.stringPtr, xml_name.stringPtr, xml_value.stringPtr);
1633
xml_name.setEmpty();
1634
xml_value.setEmpty();
1636
case XML_OP_1_END_CDATA:
1637
if (xml_value.stringLen || (my_flags & XML_KEEP_EMPTY_CDATA)) {
1638
ok = internalOpenNode("");
1639
xml_name.setEmpty();
1640
xml_value.setEmpty();
1641
ok = internalCloseNode("", true);
1644
case XML_OP_1_END_CDATA_TAG:
1645
ok = internalOpenNode("![CDATA[");
1646
xml_name.setEmpty();
1647
xml_value.setEmpty();
1649
ok = internalCloseNode("]]>", true);
1651
case XML_OP_1_END_COMMENT:
1652
ok = internalOpenNode("!--");
1653
xml_name.setEmpty();
1654
xml_value.setEmpty();
1656
ok = internalCloseNode("-->", true);
1661
switch (op & XML_DATA_MASK) {
1664
ok = xml_name.addChars(getDataLen(), getDataPtr(), true, this);
1666
case XML_DATA_CDATA:
1667
case XML_DATA_CDATA_TAG:
1669
case XML_DATA_VALUE:
1670
ok = xml_value.addChars(getDataLen(), getDataPtr(), false, this);
1675
switch (op & XML_OP_2_MASK) {
1678
case XML_OP_2_END_TAG:
1680
case XML_OP_2_END_CLOSE_TAG:
1682
case XML_OP_2_END_EMPTY_TAG:
1683
ok = internalCloseNode("/>", true);
1685
case XML_OP_2_END_PI_TAG:
1686
ok = internalCloseNode("?>", true);
1688
case XML_OP_2_END_ENTITY_TAG:
1689
ok = internalCloseNode(">", true);
1691
case XML_OP_2_END_BRACKET_TAG:
1692
ok = internalCloseNode("]>", true);
1694
case XML_OP_2_END_UNKNOWN_TAG:
1695
ok = internalCloseNode(">", true);
1697
case XML_OP_2_START_CDATA_TAG:
1699
case XML_OP_2_START_COMMENT:
1708
xml_value.setNull();
1712
/* ------------------------------------------------------------------- */
1715
bool CSXMLPrint::openNode(char *path, char *value)
1717
printf("OPEN %s\n", path);
1718
if (value && *value)
1719
printf(" %s\n", value);
1723
bool CSXMLPrint::closeNode(char *path)
1725
printf("close %s\n", path);
1729
bool CSXMLPrint::addAttribute(char *path, char *name, char *value)
1732
printf("attr %s %s=%s\n", path, name, value);
1734
printf("attr %s %s\n", path, name);
1738
/* ------------------------------------------------------------------- */
1741
bool CSXMLBuffer::parseString(const char *data, int32_t my_flags)
1744
dataLen = strlen(data);
1746
return parseXML(my_flags);
1749
bool CSXMLBuffer::parseData(const char *data, size_t len, int32_t my_flags)
1754
return parseXML(my_flags);
1757
bool CSXMLBuffer::getChar(wchar_t *ch)
1759
if (dataPos == dataLen)
1760
*ch = CS_XML_EOF_CHAR;
1762
*ch = (wchar_t) (unsigned char) charData[dataPos];
1768
/* ------------------------------------------------------------------- */
1771
bool CSXMLFile::parseFile(char *file_name, int32_t my_flags)
1775
if (!(this->file = fopen(file_name, "r"))) {
1776
setError(errno, NULL);
1779
ok = parseXML(my_flags);
1784
bool CSXMLFile::getChar(wchar_t *ch)
1788
next_ch = fgetc(file);
1789
if (next_ch == EOF) {
1791
setError(errno, NULL);
1794
*ch = CS_XML_EOF_CHAR;
1797
*ch = (wchar_t) next_ch;