ObjFW  Check-in [218c819b39]

Overview
Comment:OFXMLParser: Make private methods static functions
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 218c819b3982a2345e509daf0638f94a16a98cbb900caf09cff588f499f21388
User & Date: js on 2020-06-27 13:30:42
Other Links: manifest | tags
Context
2020-06-28
15:03
Use OF_DIRECT(_MEMBERS) where appropriate check-in: b6cb3addd0 user: js tags: trunk
2020-06-27
13:30
OFXMLParser: Make private methods static functions check-in: 218c819b39 user: js tags: trunk
2020-06-25
21:51
Add OF_DIRECT and OF_DIRECT_MEMBERS check-in: f9236a1d6c user: js tags: trunk
Changes

Modified src/OFXMLParser.h from [5c2cc1a7e0] to [12985c0c38].

149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
149
150
151
152
153
154
155

156

157
158
159
160
161
162
163







-
+
-







		OF_XMLPARSER_EXPECT_SPACE_OR_TAG_CLOSE,
		OF_XMLPARSER_IN_EXCLAMATION_MARK,
		OF_XMLPARSER_IN_CDATA_OPENING,
		OF_XMLPARSER_IN_CDATA,
		OF_XMLPARSER_IN_COMMENT_OPENING,
		OF_XMLPARSER_IN_COMMENT_1,
		OF_XMLPARSER_IN_COMMENT_2,
		OF_XMLPARSER_IN_DOCTYPE,
		OF_XMLPARSER_IN_DOCTYPE
		OF_XMLPARSER_NUM_STATES
	} _state;
	size_t _i, _last;
	const char *_Nullable _data;
	OFMutableData *_buffer;
	OFString *_Nullable _name, *_Nullable _prefix;
	OFMutableArray
	    OF_GENERIC(OFMutableDictionary OF_GENERIC(OFString *, OFString *) *)

Modified src/OFXMLParser.m from [7ad1f08170] to [51abbe68ac].

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69















































70
71
72
73
74
75
76
37
38
39
40
41
42
43




44




















45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99







-
-
-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#import "OFInvalidArgumentException.h"
#import "OFInvalidEncodingException.h"
#import "OFInvalidFormatException.h"
#import "OFMalformedXMLException.h"
#import "OFOutOfRangeException.h"
#import "OFUnboundPrefixException.h"

typedef void (*state_function_t)(id, SEL);
static SEL selectors[OF_XMLPARSER_NUM_STATES];
static state_function_t lookupTable[OF_XMLPARSER_NUM_STATES];

@interface OFXMLParser () <OFStringXMLUnescapingDelegate>
- (void)of_inByteOrderMarkState;
- (void)of_outsideTagState;
- (void)of_tagOpenedState;
- (void)of_inProcessingInstructionsState;
- (void)of_inTagNameState;
- (void)of_inCloseTagNameState;
- (void)of_inTagState;
- (void)of_inAttributeNameState;
- (void)of_expectAttributeEqualSignState;
- (void)of_expectAttributeDelimiterState;
- (void)of_inAttributeValueState;
- (void)of_expectTagCloseState;
- (void)of_expectSpaceOrTagCloseState;
- (void)of_inExclamationMarkState;
- (void)of_inCDATAOpeningState;
- (void)of_inCDATAState;
- (void)of_inCommentOpeningState;
- (void)of_inCommentState1;
- (void)of_inCommentState2;
- (void)of_inDOCTYPEState;
@end

static void inByteOrderMarkState(OFXMLParser *);
static void outsideTagState(OFXMLParser *);
static void tagOpenedState(OFXMLParser *);
static void inProcessingInstructionsState(OFXMLParser *);
static void inTagNameState(OFXMLParser *);
static void inCloseTagNameState(OFXMLParser *);
static void inTagState(OFXMLParser *);
static void inAttributeNameState(OFXMLParser *);
static void expectAttributeEqualSignState(OFXMLParser *);
static void expectAttributeDelimiterState(OFXMLParser *);
static void inAttributeValueState(OFXMLParser *);
static void expectTagCloseState(OFXMLParser *);
static void expectSpaceOrTagCloseState(OFXMLParser *);
static void inExclamationMarkState(OFXMLParser *);
static void inCDATAOpeningState(OFXMLParser *);
static void inCDATAState(OFXMLParser *);
static void inCommentOpeningState(OFXMLParser *);
static void inCommentState1(OFXMLParser *);
static void inCommentState2(OFXMLParser *);
static void inDOCTYPEState(OFXMLParser *);
typedef void (*state_function_t)(OFXMLParser *);
static state_function_t lookupTable[] = {
	[OF_XMLPARSER_IN_BYTE_ORDER_MARK] = inByteOrderMarkState,
	[OF_XMLPARSER_OUTSIDE_TAG] = outsideTagState,
	[OF_XMLPARSER_TAG_OPENED] = tagOpenedState,
	[OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS] =
	    inProcessingInstructionsState,
	[OF_XMLPARSER_IN_TAG_NAME] = inTagNameState,
	[OF_XMLPARSER_IN_CLOSE_TAG_NAME] = inCloseTagNameState,
	[OF_XMLPARSER_IN_TAG] = inTagState,
	[OF_XMLPARSER_IN_ATTRIBUTE_NAME] = inAttributeNameState,
	[OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN] =
	    expectAttributeEqualSignState,
	[OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER] =
	    expectAttributeDelimiterState,
	[OF_XMLPARSER_IN_ATTRIBUTE_VALUE] = inAttributeValueState,
	[OF_XMLPARSER_EXPECT_TAG_CLOSE] = expectTagCloseState,
	[OF_XMLPARSER_EXPECT_SPACE_OR_TAG_CLOSE] = expectSpaceOrTagCloseState,
	[OF_XMLPARSER_IN_EXCLAMATION_MARK] = inExclamationMarkState,
	[OF_XMLPARSER_IN_CDATA_OPENING] = inCDATAOpeningState,
	[OF_XMLPARSER_IN_CDATA] = inCDATAState,
	[OF_XMLPARSER_IN_COMMENT_OPENING] = inCommentOpeningState,
	[OF_XMLPARSER_IN_COMMENT_1] = inCommentState1,
	[OF_XMLPARSER_IN_COMMENT_2] = inCommentState2,
	[OF_XMLPARSER_IN_DOCTYPE] = inDOCTYPEState
};

static OF_INLINE void
appendToBuffer(OFMutableData *buffer, const char *string,
    of_string_encoding_t encoding, size_t length)
{
	if (OF_LIKELY(encoding == OF_STRING_ENCODING_UTF_8))
		[buffer addItems: string
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
186
187
188
189
190
191
192




































193
194
195
196
197
198
199







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







	[attribute->_namespace release];
	attribute->_namespace = [attributeNS retain];
}

@implementation OFXMLParser
@synthesize delegate = _delegate, depthLimit = _depthLimit;

+ (void)initialize
{
	const SEL selectors_[OF_XMLPARSER_NUM_STATES] = {
		@selector(of_inByteOrderMarkState),
		@selector(of_outsideTagState),
		@selector(of_tagOpenedState),
		@selector(of_inProcessingInstructionsState),
		@selector(of_inTagNameState),
		@selector(of_inCloseTagNameState),
		@selector(of_inTagState),
		@selector(of_inAttributeNameState),
		@selector(of_expectAttributeEqualSignState),
		@selector(of_expectAttributeDelimiterState),
		@selector(of_inAttributeValueState),
		@selector(of_expectTagCloseState),
		@selector(of_expectSpaceOrTagCloseState),
		@selector(of_inExclamationMarkState),
		@selector(of_inCDATAOpeningState),
		@selector(of_inCDATAState),
		@selector(of_inCommentOpeningState),
		@selector(of_inCommentState1),
		@selector(of_inCommentState2),
		@selector(of_inDOCTYPEState)
	};
	memcpy(selectors, selectors_, sizeof(selectors_));

	for (size_t i = 0; i < OF_XMLPARSER_NUM_STATES; i++) {
		if (![self instancesRespondToSelector: selectors[i]])
			@throw [OFInitializationFailedException
			    exceptionWithClass: self];

		lookupTable[i] = (state_function_t)
		    [self instanceMethodForSelector: selectors[i]];
	}
}

+ (instancetype)parser
{
	return [[[self alloc] init] autorelease];
}

- (instancetype)init
{
259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260







-
+







	     length: (size_t)length
{
	_data = buffer;

	for (_i = _last = 0; _i < length; _i++) {
		size_t j = _i;

		lookupTable[_state](self, selectors[_state]);
		lookupTable[_state](self);

		/* Ensure we don't count this character twice */
		if (_i != j)
			continue;

		if (_data[_i] == '\r' || (_data[_i] == '\n' &&
		    !_lastCarriageReturn))
315
316
317
318
319
320
321
322
323
324
325
326
327
328


329
330
331
332
333




334
335
336
337
338
339
340
341


342
343

344
345
346

347

348
349
350
351
352
353




354
355
356

357
358
359
360



361
362

363
364


365
366

367
368
369


370
371
372
373
374

375
376
377


378
379
380

381

382
383


384
385
386

387
388
389
390



391
392
393
394
395



396
397
398
399
400



401
402
403


404
405
406
407
408



409
410
411
412
413

414

415
416
417
418
419
420
421
422
423
424

425
426
427

428
429
430
431
432
433
434
302
303
304
305
306
307
308







309
310
311




312
313
314
315
316
317
318
319
320
321


322
323
324

325
326
327
328
329

330
331
332
333



334
335
336
337
338
339

340
341
342


343
344
345
346

347
348

349
350
351

352
353


354
355
356
357
358
359

360
361


362
363
364
365
366
367

368
369

370
371
372
373

374
375



376
377
378
379
380



381
382
383
384
385



386
387
388
389
390

391
392
393
394



395
396
397
398
399
400
401
402
403

404
405
406
407
408
409
410
411
412
413

414
415
416

417
418
419
420
421
422
423
424







-
-
-
-
-
-
-
+
+

-
-
-
-
+
+
+
+






-
-
+
+

-
+



+
-
+



-
-
-
+
+
+
+


-
+


-
-
+
+
+

-
+

-
+
+

-
+

-
-
+
+




-
+

-
-
+
+



+
-
+

-
+
+


-
+

-
-
-
+
+
+


-
-
-
+
+
+


-
-
-
+
+
+


-
+
+


-
-
-
+
+
+





+
-
+









-
+


-
+







		[self parseStream: file];
	} @finally {
		[file release];
	}
}
#endif

/*
 * The following methods handle the different states of the parser. They are
 * looked up in +[initialize] and put in a lookup table to speed things up.
 * One dispatch for every character would be way too slow!
 */

- (void)of_inByteOrderMarkState
static void
inByteOrderMarkState(OFXMLParser *self)
{
	if (_data[_i] != "\xEF\xBB\xBF"[_level]) {
		if (_level == 0) {
			_state = OF_XMLPARSER_OUTSIDE_TAG;
			_i--;
	if (self->_data[self->_i] != "\xEF\xBB\xBF"[self->_level]) {
		if (self->_level == 0) {
			self->_state = OF_XMLPARSER_OUTSIDE_TAG;
			self->_i--;
			return;
		}

		@throw [OFMalformedXMLException exceptionWithParser: self];
	}

	if (_level++ == 2)
		_state = OF_XMLPARSER_OUTSIDE_TAG;
	if (self->_level++ == 2)
		self->_state = OF_XMLPARSER_OUTSIDE_TAG;

	_last = _i + 1;
	self->_last = self->_i + 1;
}

/* Not in a tag */
static void
- (void)of_outsideTagState
outsideTagState(OFXMLParser *self)
{
	size_t length;

	if ((_finishedParsing || _previous.count < 1) && _data[_i] != ' ' &&
	    _data[_i] != '\t' && _data[_i] != '\n' && _data[_i] != '\r' &&
	    _data[_i] != '<')
	if ((self->_finishedParsing || self->_previous.count < 1) &&
	    self->_data[self->_i] != ' '  && self->_data[self->_i] != '\t' &&
	    self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r' &&
	    self->_data[self->_i] != '<')
		@throw [OFMalformedXMLException exceptionWithParser: self];

	if (_data[_i] != '<')
	if (self->_data[self->_i] != '<')
		return;

	if ((length = _i - _last) > 0)
		appendToBuffer(_buffer, _data + _last, _encoding, length);
	if ((length = self->_i - self->_last) > 0)
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, length);

	if (_buffer.count > 0) {
	if (self->_buffer.count > 0) {
		void *pool = objc_autoreleasePoolPush();
		OFString *characters = transformString(self, _buffer, 0, true);
		OFString *characters = transformString(self, self->_buffer, 0,
		    true);

		if ([_delegate respondsToSelector:
		if ([self->_delegate respondsToSelector:
		    @selector(parser:foundCharacters:)])
			[_delegate parser: self
			  foundCharacters: characters];
			[self->_delegate parser: self
				foundCharacters: characters];

		objc_autoreleasePoolPop(pool);
	}

	[_buffer removeAllItems];
	[self->_buffer removeAllItems];

	_last = _i + 1;
	_state = OF_XMLPARSER_TAG_OPENED;
	self->_last = self->_i + 1;
	self->_state = OF_XMLPARSER_TAG_OPENED;
}

/* Tag was just opened */
static void
- (void)of_tagOpenedState
tagOpenedState(OFXMLParser *self)
{
	if (_finishedParsing && _data[_i] != '!' && _data[_i] != '?')
	if (self->_finishedParsing && self->_data[self->_i] != '!' &&
	    self->_data[self->_i] != '?')
		@throw [OFMalformedXMLException exceptionWithParser: self];

	switch (_data[_i]) {
	switch (self->_data[self->_i]) {
	case '?':
		_last = _i + 1;
		_state = OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS;
		_level = 0;
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS;
		self->_level = 0;
		break;
	case '/':
		_last = _i + 1;
		_state = OF_XMLPARSER_IN_CLOSE_TAG_NAME;
		_acceptProlog = false;
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_IN_CLOSE_TAG_NAME;
		self->_acceptProlog = false;
		break;
	case '!':
		_last = _i + 1;
		_state = OF_XMLPARSER_IN_EXCLAMATION_MARK;
		_acceptProlog = false;
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_IN_EXCLAMATION_MARK;
		self->_acceptProlog = false;
		break;
	default:
		if (_depthLimit > 0 && _previous.count >= _depthLimit)
		if (self->_depthLimit > 0 &&
		    self->_previous.count >= self->_depthLimit)
			@throw [OFOutOfRangeException exception];

		_state = OF_XMLPARSER_IN_TAG_NAME;
		_acceptProlog = false;
		_i--;
		self->_state = OF_XMLPARSER_IN_TAG_NAME;
		self->_acceptProlog = false;
		self->_i--;
		break;
	}
}

/* <?xml […]?> */
static bool
- (bool)of_parseXMLProcessingInstructions: (OFString *)pi
parseXMLProcessingInstructions(OFXMLParser *self, OFString *pi)
{
	const char *cString;
	size_t length, last;
	int PIState = 0;
	OFString *attribute = nil;
	OFMutableString *value = nil;
	char piDelimiter = 0;
	bool hasVersion = false;

	if (!_acceptProlog)
	if (!self->_acceptProlog)
		return false;

	_acceptProlog = false;
	self->_acceptProlog = false;

	pi = [pi substringWithRange: of_range(3, pi.length - 3)];
	pi = pi.stringByDeletingEnclosingWhitespaces;

	cString = pi.UTF8String;
	length = pi.UTF8StringLength;

447
448
449
450
451
452
453
454

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475

476
477
478
479
480
481
482
483
484
485
486
487

488
489
490
491
492
493
494
437
438
439
440
441
442
443

444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

465
466
467
468
469
470
471
472
473
474
475
476

477
478
479
480
481
482
483
484







-
+




















-
+











-
+







			break;
		case 1:
			if (cString[i] != '=')
				continue;

			attribute = [OFString
			    stringWithCString: cString + last
				     encoding: _encoding
				     encoding: self->_encoding
				       length: i - last];
			last = i + 1;
			PIState = 2;

			break;
		case 2:
			if (cString[i] != '\'' && cString[i] != '"')
				return false;

			piDelimiter = cString[i];
			last = i + 1;
			PIState = 3;

			break;
		case 3:
			if (cString[i] != piDelimiter)
				continue;

			value = [OFMutableString
			    stringWithCString: cString + last
				     encoding: _encoding
				     encoding: self->_encoding
				       length: i - last];

			if ([attribute isEqual: @"version"]) {
				if (![value hasPrefix: @"1."])
					return false;

				hasVersion = true;
			}

			if ([attribute isEqual: @"encoding"]) {
				@try {
					_encoding =
					self->_encoding =
					    of_string_parse_encoding(value);
				} @catch (OFInvalidArgumentException *e) {
					@throw [OFInvalidEncodingException
					    exception];
				}
			}

502
503
504
505
506
507
508

509

510
511
512
513



514
515
516
517
518



519
520
521
522
523

524
525
526
527

528
529

530
531
532
533
534

535
536
537


538
539

540
541
542

543

544
545
546
547
548
549

550
551


552
553
554
555



556
557
558
559
560


561
562
563
564
565

566
567
568
569

570
571
572
573
574


575
576
577

578
579
580


581
582

583
584

585
586
587

588
589
590
591
592
593





594
595
596


597
598
599
600
601




602
603
604


605
606

607
608
609
610



611
612

613
614
615
616

617
618
619


620
621
622
623
624


625
626
627

628

629
630
631
632
633
634

635
636


637
638
639
640



641
642
643
644
645


646
647
648
649
650

651
652
653
654

655
656
657
658
659


660
661
662

663
664
665

666
667

668
669
670
671
672





673
674

675
676
677
678
679




680
681
682
683
684
685
686




687
688
689


690
691
692
693
694


695
696
697

698

699
700
701
702
703
704
705
706
707
708
709
710








711
712
713
714
715
716
717


718
719

720
721
722
723




724
725
726
727


728
729
730
731

732
733
734
735
736
737





738
739
740


741
742
743
744
745




746
747
748


749
750
751
752
753
754





755
756

757
758
759
760
761
762
763




764
765
766


767
768
769
770
771

772

773
774
775
776
777
778

779
780


781
782
783
784



785
786
787
788
789


790
791
792
793
794
795

796
797
798
799

800
801
802
803
804


805
806
807
808
809

810
811
812


813
814
815
816
817

818

819
820
821
822



823
824
825
826
827


828
829
830
831

832

833
834

835
836
837


838
839
840

841
842
843
844


845
846
847

848

849
850
851
852
853
854
855

856
857
858
859



860
861
862

863

864
865
866
867
868
869






870
871
872


873
874
875


876
877
878
879
880
881
882




883
884
885


886
887
888

889

890
891
892
893



894
895
896
897
898

899

900
901
902
903
904
905






906
907
908
909

910

911
912

913
914
915
916
917
918
919
920
921
922








923
924
925
926

927
928
929

930

931
932

933
934
935
936
937



938
939
940

941
942

943

944
945

946
947
948


949
950
951
952
953



954
955

956
957
958


959
960
961
962

963
964
965


966
967

968
969
970

971

972
973

974
975
976
977
978



979
980

981

982
983
984


985
986

987
988
989


990
991

992

993
994
995
996
997

998
999
1000
1001
1002
1003



1004

1005
1006
1007



1008
1009
1010
1011

1012
1013
1014


1015
1016
1017

1018

1019
1020
1021
1022





1023
1024
1025

1026
1027
1028


1029
1030

1031
1032
1033
1034
1035
1036
1037
492
493
494
495
496
497
498
499

500
501



502
503
504
505
506
507


508
509
510
511
512
513
514

515
516
517
518

519
520

521
522
523
524
525

526
527


528
529
530

531
532
533
534
535

536
537
538
539
540
541
542
543


544
545
546
547


548
549
550
551
552
553


554
555
556
557
558
559

560
561
562
563

564
565
566
567


568
569
570
571

572
573
574

575
576
577

578
579

580
581
582

583
584





585
586
587
588
589
590


591
592
593




594
595
596
597
598


599
600
601

602
603



604
605
606
607

608
609
610
611

612
613


614
615
616
617
618


619
620
621
622
623
624

625
626
627
628
629
630
631
632


633
634
635
636


637
638
639
640
641
642


643
644
645
646
647
648

649
650
651
652

653
654
655
656


657
658
659
660

661
662
663

664
665

666
667




668
669
670
671
672
673

674
675




676
677
678
679
680
681
682




683
684
685
686
687


688
689
690
691
692


693
694
695
696
697
698

699
700
701
702
703
704
705






706
707
708
709
710
711
712
713
714
715
716
717
718


719
720
721

722
723



724
725
726
727
728
729


730
731
732
733
734

735
736





737
738
739
740
741
742


743
744
745




746
747
748
749
750


751
752
753





754
755
756
757
758
759

760
761
762
763




764
765
766
767
768


769
770
771
772
773
774
775
776

777
778
779
780
781
782
783
784


785
786
787
788


789
790
791
792
793
794


795
796
797
798
799
800
801

802
803
804
805

806
807
808
809


810
811
812
813
814
815

816
817


818
819
820
821
822
823
824
825

826
827



828
829
830
831
832
833


834
835
836
837
838
839
840

841
842

843
844


845
846
847
848

849
850
851


852
853
854
855
856
857

858
859
860
861
862
863
864

865
866
867


868
869
870
871
872

873
874
875






876
877
878
879
880
881
882


883
884
885


886
887
888
889
890




891
892
893
894
895


896
897
898
899
900
901

902
903



904
905
906
907
908
909
910
911
912

913
914





915
916
917
918
919
920
921
922
923
924
925

926
927

928
929
930








931
932
933
934
935
936
937
938
939
940
941

942
943
944
945
946

947
948

949
950
951



952
953
954
955
956

957
958
959
960

961
962

963



964
965
966
967
968


969
970
971
972

973
974


975
976
977
978
979

980
981


982
983
984

985
986
987
988
989

990
991

992
993
994



995
996
997
998
999
1000

1001
1002


1003
1004
1005

1006
1007


1008
1009
1010
1011
1012

1013
1014
1015
1016
1017

1018
1019
1020
1021
1022


1023
1024
1025
1026
1027



1028
1029
1030
1031
1032
1033

1034
1035


1036
1037
1038
1039
1040
1041

1042
1043



1044
1045
1046
1047
1048
1049
1050

1051
1052


1053
1054
1055

1056
1057
1058
1059
1060
1061
1062
1063







+
-
+

-
-
-
+
+
+



-
-
+
+
+




-
+



-
+

-
+




-
+

-
-
+
+

-
+



+
-
+






+
-
-
+
+


-
-
+
+
+



-
-
+
+




-
+



-
+



-
-
+
+


-
+


-
+
+

-
+

-
+


-
+

-
-
-
-
-
+
+
+
+
+

-
-
+
+

-
-
-
-
+
+
+
+

-
-
+
+

-
+

-
-
-
+
+
+

-
+



-
+

-
-
+
+



-
-
+
+



+
-
+






+
-
-
+
+


-
-
+
+
+



-
-
+
+




-
+



-
+



-
-
+
+


-
+


-
+

-
+

-
-
-
-
+
+
+
+
+

-
+

-
-
-
-
+
+
+
+



-
-
-
-
+
+
+
+

-
-
+
+



-
-
+
+



+
-
+






-
-
-
-
-
-
+
+
+
+
+
+
+
+





-
-
+
+

-
+

-
-
-
+
+
+
+


-
-
+
+



-
+

-
-
-
-
-
+
+
+
+
+

-
-
+
+

-
-
-
-
+
+
+
+

-
-
+
+

-
-
-
-
-
+
+
+
+
+

-
+



-
-
-
-
+
+
+
+

-
-
+
+





+
-
+






+
-
-
+
+


-
-
+
+
+



-
-
+
+





-
+



-
+



-
-
+
+




-
+

-
-
+
+





+
-
+

-
-
-
+
+
+



-
-
+
+




+
-
+

-
+

-
-
+
+


-
+


-
-
+
+



+
-
+






-
+


-
-
+
+
+


-
+

+
-
-
-
-
-
-
+
+
+
+
+
+

-
-
+
+

-
-
+
+



-
-
-
-
+
+
+
+

-
-
+
+



+
-
+

-
-
-
+
+
+





+
-
+

-
-
-
-
-
+
+
+
+
+
+




+
-
+

-
+


-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+



-
+



+
-
+

-
+


-
-
-
+
+
+


-
+


+
-
+

-
+
-
-
-
+
+



-
-
+
+
+

-
+

-
-
+
+



-
+

-
-
+
+

-
+



+
-
+

-
+


-
-
-
+
+
+


+
-
+

-
-
+
+

-
+

-
-
+
+


+
-
+




-
+




-
-
+
+
+

+
-
-
-
+
+
+



-
+

-
-
+
+



+
-
+

-
-
-
+
+
+
+
+


-
+

-
-
+
+

-
+







	if (PIState != 0 || !hasVersion)
		return false;

	return true;
}

/* Inside processing instructions */
static void
- (void)of_inProcessingInstructionsState
inProcessingInstructionsState(OFXMLParser *self)
{
	if (_data[_i] == '?')
		_level = 1;
	else if (_level == 1 && _data[_i] == '>') {
	if (self->_data[self->_i] == '?')
		self->_level = 1;
	else if (self->_level == 1 && self->_data[self->_i] == '>') {
		void *pool = objc_autoreleasePoolPush();
		OFString *PI;

		appendToBuffer(_buffer, _data + _last, _encoding, _i - _last);
		PI = transformString(self, _buffer, 1, false);
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, self->_i - self->_last);
		PI = transformString(self, self->_buffer, 1, false);

		if ([PI isEqual: @"xml"] || [PI hasPrefix: @"xml "] ||
		    [PI hasPrefix: @"xml\t"] || [PI hasPrefix: @"xml\r"] ||
		    [PI hasPrefix: @"xml\n"])
			if (![self of_parseXMLProcessingInstructions: PI])
			if (!parseXMLProcessingInstructions(self, PI))
				@throw [OFMalformedXMLException
				    exceptionWithParser: self];

		if ([_delegate respondsToSelector:
		if ([self->_delegate respondsToSelector:
		    @selector(parser:foundProcessingInstructions:)])
			[_delegate		 parser: self
			[self->_delegate	 parser: self
			    foundProcessingInstructions: PI];

		objc_autoreleasePoolPop(pool);

		[_buffer removeAllItems];
		[self->_buffer removeAllItems];

		_last = _i + 1;
		_state = OF_XMLPARSER_OUTSIDE_TAG;
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_OUTSIDE_TAG;
	} else
		_level = 0;
		self->_level = 0;
}

/* Inside a tag, no name yet */
static void
- (void)of_inTagNameState
inTagNameState(OFXMLParser *self)
{
	void *pool;
	const char *bufferCString, *tmp;
	size_t length, bufferLength;
	OFString *bufferString;

	if (self->_data[self->_i] != ' '  && self->_data[self->_i] != '\t' &&
	if (_data[_i] != ' ' && _data[_i] != '\t' && _data[_i] != '\n' &&
	    _data[_i] != '\r' && _data[_i] != '>' && _data[_i] != '/')
	    self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r' &&
	    self->_data[self->_i] != '>'  && self->_data[self->_i] != '/')
		return;

	if ((length = _i - _last) > 0)
		appendToBuffer(_buffer, _data + _last, _encoding, length);
	if ((length = self->_i - self->_last) > 0)
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, length);

	pool = objc_autoreleasePoolPush();

	bufferCString = _buffer.items;
	bufferLength = _buffer.count;
	bufferCString = self->_buffer.items;
	bufferLength = self->_buffer.count;
	bufferString = [OFString stringWithUTF8String: bufferCString
					       length: bufferLength];

	if ((tmp = memchr(bufferCString, ':', bufferLength)) != NULL) {
		_name = [[OFString alloc]
		self->_name = [[OFString alloc]
		    initWithUTF8String: tmp + 1
				length: bufferLength -
					(tmp - bufferCString) - 1];
		_prefix = [[OFString alloc]
		self->_prefix = [[OFString alloc]
		    initWithUTF8String: bufferCString
				length: tmp - bufferCString];
	} else {
		_name = [bufferString copy];
		_prefix = nil;
		self->_name = [bufferString copy];
		self->_prefix = nil;
	}

	if (_data[_i] == '>' || _data[_i] == '/') {
	if (self->_data[self->_i] == '>' || self->_data[self->_i] == '/') {
		OFString *namespace;

		namespace = namespaceForPrefix(_prefix, _namespaces);
		namespace = namespaceForPrefix(self->_prefix,
		    self->_namespaces);

		if (_prefix != nil && namespace == nil)
		if (self->_prefix != nil && namespace == nil)
			@throw [OFUnboundPrefixException
			    exceptionWithPrefix: _prefix
			    exceptionWithPrefix: self->_prefix
					 parser: self];

		if ([_delegate respondsToSelector: @selector(parser:
		if ([self->_delegate respondsToSelector: @selector(parser:
		    didStartElement:prefix:namespace:attributes:)])
			[_delegate parser: self
			  didStartElement: _name
				   prefix: _prefix
				namespace: namespace
			       attributes: nil];
			[self->_delegate parser: self
				didStartElement: self->_name
					 prefix: self->_prefix
				      namespace: namespace
				     attributes: nil];

		if (_data[_i] == '/') {
			if ([_delegate respondsToSelector:
		if (self->_data[self->_i] == '/') {
			if ([self->_delegate respondsToSelector:
			    @selector(parser:didEndElement:prefix:namespace:)])
				[_delegate parser: self
				    didEndElement: _name
					   prefix: _prefix
					namespace: namespace];
				[self->_delegate parser: self
					  didEndElement: self->_name
						 prefix: self->_prefix
					      namespace: namespace];

			if (_previous.count == 0)
				_finishedParsing = true;
			if (self->_previous.count == 0)
				self->_finishedParsing = true;
		} else
			[_previous addObject: bufferString];
			[self->_previous addObject: bufferString];

		[_name release];
		[_prefix release];
		_name = _prefix = nil;
		[self->_name release];
		[self->_prefix release];
		self->_name = self->_prefix = nil;

		_state = (_data[_i] == '/'
		self->_state = (self->_data[self->_i] == '/'
		    ? OF_XMLPARSER_EXPECT_TAG_CLOSE
		    : OF_XMLPARSER_OUTSIDE_TAG);
	} else
		_state = OF_XMLPARSER_IN_TAG;
		self->_state = OF_XMLPARSER_IN_TAG;

	if (_data[_i] != '/')
		[_namespaces addObject: [OFMutableDictionary dictionary]];
	if (self->_data[self->_i] != '/')
		[self->_namespaces addObject: [OFMutableDictionary dictionary]];

	objc_autoreleasePoolPop(pool);

	[_buffer removeAllItems];
	_last = _i + 1;
	[self->_buffer removeAllItems];
	self->_last = self->_i + 1;
}

/* Inside a close tag, no name yet */
static void
- (void)of_inCloseTagNameState
inCloseTagNameState(OFXMLParser *self)
{
	void *pool;
	const char *bufferCString, *tmp;
	size_t length, bufferLength;
	OFString *bufferString, *namespace;

	if (self->_data[self->_i] != ' '  && self->_data[self->_i] != '\t' &&
	if (_data[_i] != ' ' && _data[_i] != '\t' && _data[_i] != '\n' &&
	    _data[_i] != '\r' && _data[_i] != '>')
	    self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r' &&
	    self->_data[self->_i] != '>')
		return;

	if ((length = _i - _last) > 0)
		appendToBuffer(_buffer, _data + _last, _encoding, length);
	if ((length = self->_i - self->_last) > 0)
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, length);

	pool = objc_autoreleasePoolPush();

	bufferCString = _buffer.items;
	bufferLength = _buffer.count;
	bufferCString = self->_buffer.items;
	bufferLength = self->_buffer.count;
	bufferString = [OFString stringWithUTF8String: bufferCString
					       length: bufferLength];

	if ((tmp = memchr(bufferCString, ':', bufferLength)) != NULL) {
		_name = [[OFString alloc]
		self->_name = [[OFString alloc]
		    initWithUTF8String: tmp + 1
				length: bufferLength -
					(tmp - bufferCString) - 1];
		_prefix = [[OFString alloc]
		self->_prefix = [[OFString alloc]
		    initWithUTF8String: bufferCString
				length: tmp - bufferCString];
	} else {
		_name = [bufferString copy];
		_prefix = nil;
		self->_name = [bufferString copy];
		self->_prefix = nil;
	}

	if (![_previous.lastObject isEqual: bufferString])
	if (![self->_previous.lastObject isEqual: bufferString])
		@throw [OFMalformedXMLException exceptionWithParser: self];

	[_previous removeLastObject];
	[self->_previous removeLastObject];

	[_buffer removeAllItems];
	[self->_buffer removeAllItems];

	namespace = namespaceForPrefix(_prefix, _namespaces);
	if (_prefix != nil && namespace == nil)
		@throw [OFUnboundPrefixException exceptionWithPrefix: _prefix
							      parser: self];
	namespace = namespaceForPrefix(self->_prefix, self->_namespaces);
	if (self->_prefix != nil && namespace == nil)
		@throw [OFUnboundPrefixException
		    exceptionWithPrefix: self->_prefix
				 parser: self];

	if ([_delegate respondsToSelector:
	if ([self->_delegate respondsToSelector:
	    @selector(parser:didEndElement:prefix:namespace:)])
		[_delegate parser: self
		    didEndElement: _name
			   prefix: _prefix
			namespace: namespace];
		[self->_delegate parser: self
			  didEndElement: self->_name
				 prefix: self->_prefix
			      namespace: namespace];

	objc_autoreleasePoolPop(pool);

	[_namespaces removeLastObject];
	[_name release];
	[_prefix release];
	_name = _prefix = nil;
	[self->_namespaces removeLastObject];
	[self->_name release];
	[self->_prefix release];
	self->_name = self->_prefix = nil;

	_last = _i + 1;
	_state = (_data[_i] == '>'
	self->_last = self->_i + 1;
	self->_state = (self->_data[self->_i] == '>'
	    ? OF_XMLPARSER_OUTSIDE_TAG
	    : OF_XMLPARSER_EXPECT_SPACE_OR_TAG_CLOSE);

	if (_previous.count == 0)
		_finishedParsing = true;
	if (self->_previous.count == 0)
		self->_finishedParsing = true;
}

/* Inside a tag, name found */
static void
- (void)of_inTagState
inTagState(OFXMLParser *self)
{
	void *pool;
	OFString *namespace;
	OFXMLAttribute *const *attributesObjects;
	size_t attributesCount;

	if (_data[_i] != '>' && _data[_i] != '/') {
		if (_data[_i] != ' ' && _data[_i] != '\t' &&
		    _data[_i] != '\n' && _data[_i] != '\r') {
			_last = _i;
			_state = OF_XMLPARSER_IN_ATTRIBUTE_NAME;
			_i--;
	if (self->_data[self->_i] != '>' && self->_data[self->_i] != '/') {
		if (self->_data[self->_i] != ' ' &&
		    self->_data[self->_i] != '\t' &&
		    self->_data[self->_i] != '\n' &&
		    self->_data[self->_i] != '\r') {
			self->_last = self->_i;
			self->_state = OF_XMLPARSER_IN_ATTRIBUTE_NAME;
			self->_i--;
		}

		return;
	}

	attributesObjects = _attributes.objects;
	attributesCount = _attributes.count;
	attributesObjects = self->_attributes.objects;
	attributesCount = self->_attributes.count;

	namespace = namespaceForPrefix(_prefix, _namespaces);
	namespace = namespaceForPrefix(self->_prefix, self->_namespaces);

	if (_prefix != nil && namespace == nil)
		@throw [OFUnboundPrefixException exceptionWithPrefix: _prefix
							      parser: self];
	if (self->_prefix != nil && namespace == nil)
		@throw [OFUnboundPrefixException
		    exceptionWithPrefix: self->_prefix
				 parser: self];

	for (size_t j = 0; j < attributesCount; j++)
		resolveAttributeNamespace(attributesObjects[j], _namespaces,
		    self);
		resolveAttributeNamespace(attributesObjects[j],
		    self->_namespaces, self);

	pool = objc_autoreleasePoolPush();

	if ([_delegate respondsToSelector:
	if ([self->_delegate respondsToSelector:
	    @selector(parser:didStartElement:prefix:namespace:attributes:)])
		[_delegate parser: self
		  didStartElement: _name
			   prefix: _prefix
			namespace: namespace
		       attributes: _attributes];
		[self->_delegate parser: self
			didStartElement: self->_name
				 prefix: self->_prefix
			      namespace: namespace
			     attributes: self->_attributes];

	if (_data[_i] == '/') {
		if ([_delegate respondsToSelector:
	if (self->_data[self->_i] == '/') {
		if ([self->_delegate respondsToSelector:
		    @selector(parser:didEndElement:prefix:namespace:)])
			[_delegate parser: self
			    didEndElement: _name
				   prefix: _prefix
				namespace: namespace];
			[self->_delegate parser: self
				  didEndElement: self->_name
					 prefix: self->_prefix
				      namespace: namespace];

		if (_previous.count == 0)
			_finishedParsing = true;
		if (self->_previous.count == 0)
			self->_finishedParsing = true;

		[_namespaces removeLastObject];
	} else if (_prefix != nil) {
		OFString *str = [OFString stringWithFormat: @"%@:%@",
							    _prefix, _name];
		[_previous addObject: str];
		[self->_namespaces removeLastObject];
	} else if (self->_prefix != nil) {
		OFString *str = [OFString stringWithFormat:
		    @"%@:%@", self->_prefix, self->_name];
		[self->_previous addObject: str];
	} else
		[_previous addObject: _name];
		[self->_previous addObject: self->_name];

	objc_autoreleasePoolPop(pool);

	[_name release];
	[_prefix release];
	[_attributes removeAllObjects];
	_name = _prefix = nil;
	[self->_name release];
	[self->_prefix release];
	[self->_attributes removeAllObjects];
	self->_name = self->_prefix = nil;

	_last = _i + 1;
	_state = (_data[_i] == '/'
	self->_last = self->_i + 1;
	self->_state = (self->_data[self->_i] == '/'
	    ? OF_XMLPARSER_EXPECT_TAG_CLOSE
	    : OF_XMLPARSER_OUTSIDE_TAG);
}

/* Looking for attribute name */
static void
- (void)of_inAttributeNameState
inAttributeNameState(OFXMLParser *self)
{
	void *pool;
	OFString *bufferString;
	const char *bufferCString, *tmp;
	size_t length, bufferLength;

	if (self->_data[self->_i] != '='  && self->_data[self->_i] != ' '  &&
	if (_data[_i] != '=' && _data[_i] != ' ' && _data[_i] != '\t' &&
	    _data[_i] != '\n' && _data[_i] != '\r')
	    self->_data[self->_i] != '\t' && self->_data[self->_i] != '\n' &&
	    self->_data[self->_i] != '\r')
		return;

	if ((length = _i - _last) > 0)
		appendToBuffer(_buffer, _data + _last, _encoding, length);
	if ((length = self->_i - self->_last) > 0)
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, length);

	pool = objc_autoreleasePoolPush();

	bufferString = [OFString stringWithUTF8String: _buffer.items
					       length: _buffer.count];
	bufferString = [OFString stringWithUTF8String: self->_buffer.items
					       length: self->_buffer.count];

	bufferCString = bufferString.UTF8String;
	bufferLength = bufferString.UTF8StringLength;

	if ((tmp = memchr(bufferCString, ':', bufferLength)) != NULL) {
		_attributeName = [[OFString alloc]
		self->_attributeName = [[OFString alloc]
		    initWithUTF8String: tmp + 1
				length: bufferLength -
					(tmp - bufferCString) - 1];
		_attributePrefix = [[OFString alloc]
		self->_attributePrefix = [[OFString alloc]
		    initWithUTF8String: bufferCString
				length: tmp - bufferCString];
	} else {
		_attributeName = [bufferString copy];
		_attributePrefix = nil;
		self->_attributeName = [bufferString copy];
		self->_attributePrefix = nil;
	}

	objc_autoreleasePoolPop(pool);

	[_buffer removeAllItems];
	[self->_buffer removeAllItems];

	_last = _i + 1;
	_state = (_data[_i] == '='
	self->_last = self->_i + 1;
	self->_state = (self->_data[self->_i] == '='
	    ? OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER
	    : OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN);
}

/* Expecting equal sign of an attribute */
static void
- (void)of_expectAttributeEqualSignState
expectAttributeEqualSignState(OFXMLParser *self)
{
	if (_data[_i] == '=') {
		_last = _i + 1;
		_state = OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER;
	if (self->_data[self->_i] == '=') {
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER;
		return;
	}

	if (_data[_i] != ' ' && _data[_i] != '\t' && _data[_i] != '\n' &&
	    _data[_i] != '\r')
	if (self->_data[self->_i] != ' '  && self->_data[self->_i] != '\t' &&
	    self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r')
		@throw [OFMalformedXMLException exceptionWithParser: self];
}

/* Expecting name/value delimiter of an attribute */
static void
- (void)of_expectAttributeDelimiterState
expectAttributeDelimiterState(OFXMLParser *self)
{
	_last = _i + 1;
	self->_last = self->_i + 1;

	if (_data[_i] == ' ' || _data[_i] == '\t' || _data[_i] == '\n' ||
	    _data[_i] == '\r')
	if (self->_data[self->_i] == ' '  || self->_data[self->_i] == '\t' ||
	    self->_data[self->_i] == '\n' || self->_data[self->_i] == '\r')
		return;

	if (_data[_i] != '\'' && _data[_i] != '"')
	if (self->_data[self->_i] != '\'' && self->_data[self->_i] != '"')
		@throw [OFMalformedXMLException exceptionWithParser: self];

	_delimiter = _data[_i];
	_state = OF_XMLPARSER_IN_ATTRIBUTE_VALUE;
	self->_delimiter = self->_data[self->_i];
	self->_state = OF_XMLPARSER_IN_ATTRIBUTE_VALUE;
}

/* Looking for attribute value */
static void
- (void)of_inAttributeValueState
inAttributeValueState(OFXMLParser *self)
{
	void *pool;
	OFString *attributeValue;
	size_t length;
	OFXMLAttribute *attribute;

	if (_data[_i] != _delimiter)
	if (self->_data[self->_i] != self->_delimiter)
		return;

	if ((length = _i - _last) > 0)
		appendToBuffer(_buffer, _data + _last, _encoding, length);
	if ((length = self->_i - self->_last) > 0)
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, length);

	pool = objc_autoreleasePoolPush();
	attributeValue = transformString(self, _buffer, 0, true);
	attributeValue = transformString(self, self->_buffer, 0, true);

	if (self->_attributePrefix == nil &&
	if (_attributePrefix == nil && [_attributeName isEqual: @"xmlns"])
		[_namespaces.lastObject setObject: attributeValue
					   forKey: @""];
	if ([_attributePrefix isEqual: @"xmlns"])
		[_namespaces.lastObject setObject: attributeValue
					   forKey: _attributeName];
	    [self->_attributeName isEqual: @"xmlns"])
		[self->_namespaces.lastObject setObject: attributeValue
						 forKey: @""];
	if ([self->_attributePrefix isEqual: @"xmlns"])
		[self->_namespaces.lastObject setObject: attributeValue
						 forKey: self->_attributeName];

	attribute = [OFXMLAttribute attributeWithName: _attributeName
					    namespace: _attributePrefix
	attribute = [OFXMLAttribute attributeWithName: self->_attributeName
					    namespace: self->_attributePrefix
					  stringValue: attributeValue];
	attribute->_useDoubleQuotes = (_delimiter == '"');
	[_attributes addObject: attribute];
	attribute->_useDoubleQuotes = (self->_delimiter == '"');
	[self->_attributes addObject: attribute];

	objc_autoreleasePoolPop(pool);

	[_buffer removeAllItems];
	[_attributeName release];
	[_attributePrefix release];
	_attributeName = _attributePrefix = nil;
	[self->_buffer removeAllItems];
	[self->_attributeName release];
	[self->_attributePrefix release];
	self->_attributeName = self->_attributePrefix = nil;

	_last = _i + 1;
	_state = OF_XMLPARSER_IN_TAG;
	self->_last = self->_i + 1;
	self->_state = OF_XMLPARSER_IN_TAG;
}

/* Expecting closing '>' */
static void
- (void)of_expectTagCloseState
expectTagCloseState(OFXMLParser *self)
{
	if (_data[_i] == '>') {
		_last = _i + 1;
		_state = OF_XMLPARSER_OUTSIDE_TAG;
	if (self->_data[self->_i] == '>') {
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_OUTSIDE_TAG;
	} else
		@throw [OFMalformedXMLException exceptionWithParser: self];
}

/* Expecting closing '>' or space */
static void
- (void)of_expectSpaceOrTagCloseState
expectSpaceOrTagCloseState(OFXMLParser *self)
{
	if (_data[_i] == '>') {
		_last = _i + 1;
		_state = OF_XMLPARSER_OUTSIDE_TAG;
	} else if (_data[_i] != ' ' && _data[_i] != '\t' &&
	    _data[_i] != '\n' && _data[_i] != '\r')
	if (self->_data[self->_i] == '>') {
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_OUTSIDE_TAG;
	} else if (self->_data[self->_i] != ' ' &&
	    self->_data[self->_i] != '\t' && self->_data[self->_i] != '\n' &&
	    self->_data[self->_i] != '\r')
		@throw [OFMalformedXMLException exceptionWithParser: self];
}

/* In <! */
static void
- (void)of_inExclamationMarkState
inExclamationMarkState(OFXMLParser *self)
{
	if (_finishedParsing && _data[_i] != '-')
	if (self->_finishedParsing && self->_data[self->_i] != '-')
		@throw [OFMalformedXMLException exceptionWithParser: self];

	if (_data[_i] == '-')
		_state = OF_XMLPARSER_IN_COMMENT_OPENING;
	else if (_data[_i] == '[') {
		_state = OF_XMLPARSER_IN_CDATA_OPENING;
		_level = 0;
	} else if (_data[_i] == 'D') {
		_state = OF_XMLPARSER_IN_DOCTYPE;
		_level = 0;
	if (self->_data[self->_i] == '-')
		self->_state = OF_XMLPARSER_IN_COMMENT_OPENING;
	else if (self->_data[self->_i] == '[') {
		self->_state = OF_XMLPARSER_IN_CDATA_OPENING;
		self->_level = 0;
	} else if (self->_data[self->_i] == 'D') {
		self->_state = OF_XMLPARSER_IN_DOCTYPE;
		self->_level = 0;
	} else
		@throw [OFMalformedXMLException exceptionWithParser: self];

	_last = _i + 1;
	self->_last = self->_i + 1;
}

/* CDATA */
static void
- (void)of_inCDATAOpeningState
inCDATAOpeningState(OFXMLParser *self)
{
	if (_data[_i] != "CDATA["[_level])
	if (self->_data[self->_i] != "CDATA["[self->_level])
		@throw [OFMalformedXMLException exceptionWithParser: self];

	if (++_level == 6) {
		_state = OF_XMLPARSER_IN_CDATA;
		_level = 0;
	if (++self->_level == 6) {
		self->_state = OF_XMLPARSER_IN_CDATA;
		self->_level = 0;
	}

	_last = _i + 1;
	self->_last = self->_i + 1;
}

static void
- (void)of_inCDATAState
inCDATAState(OFXMLParser *self)
{

	if (self->_data[self->_i] == ']')
	if (_data[_i] == ']')
		_level++;
	else if (_data[_i] == '>' && _level >= 2) {
		self->_level++;
	else if (self->_data[self->_i] == '>' && self->_level >= 2) {
		void *pool = objc_autoreleasePoolPush();
		OFString *CDATA;

		appendToBuffer(_buffer, _data + _last, _encoding, _i - _last);
		CDATA = transformString(self, _buffer, 2, false);
		appendToBuffer(self->_buffer, self->_data + self->_last,
		    self->_encoding, self->_i - self->_last);
		CDATA = transformString(self, self->_buffer, 2, false);

		if ([_delegate respondsToSelector:
		if ([self->_delegate respondsToSelector:
		    @selector(parser:foundCDATA:)])
			[_delegate parser: self
			       foundCDATA: CDATA];
			[self->_delegate parser: self
				     foundCDATA: CDATA];

		objc_autoreleasePoolPop(pool);

		[_buffer removeAllItems];
		[self->_buffer removeAllItems];

		_last = _i + 1;
		_state = OF_XMLPARSER_OUTSIDE_TAG;
		self->_last = self->_i + 1;
		self->_state = OF_XMLPARSER_OUTSIDE_TAG;
	} else
		_level = 0;
		self->_level = 0;
}

/* Comment */
static void
- (void)of_inCommentOpeningState
inCommentOpeningState(OFXMLParser *self)
{
	if (_data[_i] != '-')
	if (self->_data[self->_i] != '-')
		@throw [OFMalformedXMLException exceptionWithParser: self];

	_last = _i + 1;
	_state = OF_XMLPARSER_IN_COMMENT_1;
	_level = 0;
	self->_last = self->_i + 1;
	self->_state = OF_XMLPARSER_IN_COMMENT_1;
	self->_level = 0;
}

static void
- (void)of_inCommentState1
inCommentState1(OFXMLParser *self)
{
	if (_data[_i] == '-')
		_level++;
	if (self->_data[self->_i] == '-')
		self->_level++;
	else
		_level = 0;
		self->_level = 0;

	if (_level == 2)
		_state = OF_XMLPARSER_IN_COMMENT_2;
	if (self->_level == 2)
		self->_state = OF_XMLPARSER_IN_COMMENT_2;
}

static void
- (void)of_inCommentState2
inCommentState2(OFXMLParser *self)
{
	void *pool;
	OFString *comment;

	if (_data[_i] != '>')
	if (self->_data[self->_i] != '>')
		@throw [OFMalformedXMLException exceptionWithParser: self];

	pool = objc_autoreleasePoolPush();

	appendToBuffer(_buffer, _data + _last, _encoding, _i - _last);
	comment = transformString(self, _buffer, 2, false);
	appendToBuffer(self->_buffer, self->_data + self->_last,
	    self->_encoding, self->_i - self->_last);
	comment = transformString(self, self->_buffer, 2, false);

	if ([self->_delegate respondsToSelector:
	if ([_delegate respondsToSelector: @selector(parser:foundComment:)])
		[_delegate parser: self
		     foundComment: comment];
	    @selector(parser:foundComment:)])
		[self->_delegate parser: self
			   foundComment: comment];

	objc_autoreleasePoolPop(pool);

	[_buffer removeAllItems];
	[self->_buffer removeAllItems];

	_last = _i + 1;
	_state = OF_XMLPARSER_OUTSIDE_TAG;
	self->_last = self->_i + 1;
	self->_state = OF_XMLPARSER_OUTSIDE_TAG;
}

/* In <!DOCTYPE ...> */
static void
- (void)of_inDOCTYPEState
inDOCTYPEState(OFXMLParser *self)
{
	if ((_level < 6 && _data[_i] != "OCTYPE"[_level]) ||
	    (_level == 6 && _data[_i] != ' ' && _data[_i] != '\t' &&
	    _data[_i] != '\n' && _data[_i] != '\r'))
	if ((self->_level < 6 &&
	    self->_data[self->_i] != "OCTYPE"[self->_level]) ||
	    (self->_level == 6 && self->_data[self->_i] != ' ' &&
	    self->_data[self->_i] != '\t' && self->_data[self->_i] != '\n' &&
	    self->_data[self->_i] != '\r'))
		@throw [OFMalformedXMLException exceptionWithParser: self];

	_level++;
	self->_level++;

	if (_level > 6 && _data[_i] == '>')
		_state = OF_XMLPARSER_OUTSIDE_TAG;
	if (self->_level > 6 && self->_data[self->_i] == '>')
		self->_state = OF_XMLPARSER_OUTSIDE_TAG;

	_last = _i + 1;
	self->_last = self->_i + 1;
}

- (size_t)lineNumber
{
	return _lineNumber;
}