ObjFW  Check-in [4c8d02cc0d]

Overview
Comment:Move parsing of encoding names to a single place
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 4c8d02cc0db195a730d82bc84ede826c3203dec21e9c028f0bd249143748d001
User & Date: js on 2017-01-18 03:45:05
Other Links: manifest | tags
Context
2017-01-19
23:08
Add support for disabling encodings check-in: 766eedef4c user: js tags: trunk
2017-01-18
03:45
Move parsing of encoding names to a single place check-in: 4c8d02cc0d user: js tags: trunk
2017-01-17
03:23
Add ISO-8859-2 check-in: 7a27ce7b0b user: js tags: trunk
Changes

Modified src/OFHTTPResponse.m from [f2cda29146] to [ce566f860b].

19
20
21
22
23
24
25

26
27
28
29








































































































30
31
32
33
34
35
36
#import "OFHTTPResponse.h"
#import "OFString.h"
#import "OFDictionary.h"
#import "OFArray.h"
#import "OFDataArray.h"
#import "OFHTTPCookie.h"


#import "OFInvalidFormatException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFUnsupportedVersionException.h"









































































































@implementation OFHTTPResponse
@synthesize statusCode = _statusCode, headers = _headers, cookies = _cookies;

- init
{
	self = [super init];







>




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#import "OFHTTPResponse.h"
#import "OFString.h"
#import "OFDictionary.h"
#import "OFArray.h"
#import "OFDataArray.h"
#import "OFHTTPCookie.h"

#import "OFInvalidEncodingException.h"
#import "OFInvalidFormatException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFUnsupportedVersionException.h"

static of_string_encoding_t
encodingForContentType(OFString *contentType)
{
	const char *UTF8String = [contentType UTF8String];
	size_t last, length = [contentType UTF8StringLength];
	enum {
		STATE_TYPE,
		STATE_BEFORE_PARAM_NAME,
		STATE_PARAM_NAME,
		STATE_PARAM_VALUE_OR_QUOTE,
		STATE_PARAM_VALUE,
		STATE_PARAM_QUOTED_VALUE,
		STATE_AFTER_PARAM_VALUE
	} state = STATE_TYPE;
	OFString *name, *value, *charset = nil;

	last = 0;
	for (size_t i = 0; i < length; i++) {
		switch (state) {
		case STATE_TYPE:
			if (UTF8String[i] == ';') {
				state = STATE_BEFORE_PARAM_NAME;
				last = i + 1;
			}
			break;
		case STATE_BEFORE_PARAM_NAME:
			if (UTF8String[i] == ' ')
				last = i + 1;
			else {
				state = STATE_PARAM_NAME;
				i--;
			}
			break;
		case STATE_PARAM_NAME:
			if (UTF8String[i] == '=') {
				name = [OFString
				    stringWithUTF8String: UTF8String + last
						  length: i - last];

				state = STATE_PARAM_VALUE_OR_QUOTE;
				last = i + 1;
			}
			break;
		case STATE_PARAM_VALUE_OR_QUOTE:
			if (UTF8String[i] == '"') {
				state = STATE_PARAM_QUOTED_VALUE;
				last = i + 1;
			} else {
				state = STATE_PARAM_VALUE;
				i--;
			}
			break;
		case STATE_PARAM_VALUE:
			if (UTF8String[i] == ';') {
				value = [OFString
				    stringWithUTF8String: UTF8String + last
						  length: i - last];
				value = [value
				    stringByDeletingTrailingWhitespaces];

				if ([name isEqual: @"charset"])
					charset = value;

				state = STATE_BEFORE_PARAM_NAME;
				last = i + 1;
			}
			break;
		case STATE_PARAM_QUOTED_VALUE:
			if (UTF8String[i] == '"') {
				value = [OFString
				    stringWithUTF8String: UTF8String + last
						  length: i - last];

				if ([name isEqual: @"charset"])
					charset = value;

				state = STATE_AFTER_PARAM_VALUE;
			}
			break;
		case STATE_AFTER_PARAM_VALUE:
			if (UTF8String[i] == ';') {
				state = STATE_BEFORE_PARAM_NAME;
				last = i + 1;
			} else if (UTF8String[i] != ' ')
				return OF_STRING_ENCODING_AUTODETECT;
			break;
		}
	}
	if (state == STATE_PARAM_VALUE) {
		value = [OFString stringWithUTF8String: UTF8String + last
						length: length - last];
		value = [value stringByDeletingTrailingWhitespaces];

		if ([name isEqual: @"charset"])
			charset = value;
	}

	@try {
		return of_string_parse_encoding(charset);
	} @catch (OFInvalidEncodingException *e) {
		return OF_STRING_ENCODING_AUTODETECT;
	}
}

@implementation OFHTTPResponse
@synthesize statusCode = _statusCode, headers = _headers, cookies = _cookies;

- init
{
	self = [super init];
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
- (OFString*)stringWithEncoding: (of_string_encoding_t)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFString *contentType, *contentLength, *ret;
	OFDataArray *data;

	if (encoding == OF_STRING_ENCODING_AUTODETECT &&
	    (contentType = [_headers objectForKey: @"Content-Type"]) != nil) {
		contentType = [contentType lowercaseString];

		if ([contentType hasSuffix: @"charset=utf-8"])
			encoding = OF_STRING_ENCODING_UTF_8;
		else if ([contentType hasSuffix: @"charset=iso-8859-1"] ||
		    [contentType hasSuffix: @"charset=iso_8859-1"])
			encoding = OF_STRING_ENCODING_ISO_8859_1;
		else if ([contentType hasSuffix: @"charset=iso-8859-2"] ||
		    [contentType hasSuffix: @"charset=iso_8859-2"])
			encoding = OF_STRING_ENCODING_ISO_8859_2;
		else if ([contentType hasSuffix: @"charset=iso-8859-15"] ||
		    [contentType hasSuffix: @"charset=iso_8859-15"])
			encoding = OF_STRING_ENCODING_ISO_8859_15;
		else if ([contentType hasSuffix: @"charset=windows-1251"] ||
		    [contentType hasSuffix: @"charset=cp1251"] ||
		    [contentType hasSuffix: @"charset=cp-1251"])
			encoding = OF_STRING_ENCODING_WINDOWS_1251;
		else if ([contentType hasSuffix: @"charset=windows-1252"] ||
		    [contentType hasSuffix: @"charset=cp1252"] ||
		    [contentType hasSuffix: @"charset=cp-1252"])
			encoding = OF_STRING_ENCODING_WINDOWS_1252;
		else if ([contentType hasSuffix: @"charset=cp437"] ||
		    [contentType hasSuffix: @"charset=cp-437"])
			encoding = OF_STRING_ENCODING_CODEPAGE_437;
		else if ([contentType hasSuffix: @"charset=cp850"] ||
		    [contentType hasSuffix: @"charset=cp-850"])
			encoding = OF_STRING_ENCODING_CODEPAGE_850;
		else if ([contentType hasSuffix: @"charset=cp858"] ||
		    [contentType hasSuffix: @"charset=cp-858"])
			encoding = OF_STRING_ENCODING_CODEPAGE_858;
		else if ([contentType hasSuffix: @"charset=macintosh"])
			encoding = OF_STRING_ENCODING_MAC_ROMAN;
	}

	if (encoding == OF_STRING_ENCODING_AUTODETECT)
		encoding = OF_STRING_ENCODING_UTF_8;

	data = [self readDataArrayTillEndOfStream];

	if ((contentLength = [_headers objectForKey: @"Content-Length"]) != nil)







|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







209
210
211
212
213
214
215
216

217































218
219
220
221
222
223
224
- (OFString*)stringWithEncoding: (of_string_encoding_t)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFString *contentType, *contentLength, *ret;
	OFDataArray *data;

	if (encoding == OF_STRING_ENCODING_AUTODETECT &&
	    (contentType = [_headers objectForKey: @"Content-Type"]) != nil)

		encoding = encodingForContentType(contentType);
































	if (encoding == OF_STRING_ENCODING_AUTODETECT)
		encoding = OF_STRING_ENCODING_UTF_8;

	data = [self readDataArrayTillEndOfStream];

	if ((contentLength = [_headers objectForKey: @"Content-Length"]) != nil)

Modified src/OFLocalization.m from [469e0664e7] to [0a1b003490].

20
21
22
23
24
25
26

27
28
29
30
31
32
33

#import "OFLocalization.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFDictionary.h"

#import "OFInvalidArgumentException.h"


static OFLocalization *sharedLocalization = nil;

@implementation OFLocalization
@synthesize language = _language, territory = _territory, encoding = _encoding;
@synthesize decimalPoint = _decimalPoint;








>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#import "OFLocalization.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFDictionary.h"

#import "OFInvalidArgumentException.h"
#import "OFInvalidEncodingException.h"

static OFLocalization *sharedLocalization = nil;

@implementation OFLocalization
@synthesize language = _language, territory = _territory, encoding = _encoding;
@synthesize decimalPoint = _decimalPoint;

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
		if ((tmp = strrchr(locale, '@')) != NULL)
			*tmp = '\0';

		/* Encoding */
		if ((tmp = strrchr(locale, '.')) != NULL) {
			*tmp++ = '\0';

			tmpLen = strlen(tmp);
			for (size_t i = 0; i < tmpLen; i++)
				tmp[i] = of_ascii_tolower(tmp[i]);

			if (strcmp(tmp, "utf8") == 0 ||
			    strcmp(tmp, "utf-8") == 0)
				_encoding = OF_STRING_ENCODING_UTF_8;
			else if (strcmp(tmp, "ascii") == 0 ||
			    strcmp(tmp, "us-ascii") == 0)
				_encoding = OF_STRING_ENCODING_ASCII;
			else if (strcmp(tmp, "iso8859-1") == 0 ||
			    strcmp(tmp, "iso-8859-1") == 0 ||
			    strcmp(tmp, "iso_8859-1") == 0)
				_encoding = OF_STRING_ENCODING_ISO_8859_1;
			else if (strcmp(tmp, "iso8859-2") == 0 ||
			    strcmp(tmp, "iso-8859-2") == 0 ||
			    strcmp(tmp, "iso_8859-2") == 0)
				_encoding = OF_STRING_ENCODING_ISO_8859_2;
			else if (strcmp(tmp, "iso8859-15") == 0 ||
			    strcmp(tmp, "iso-8859-15") == 0 ||
			    strcmp(tmp, "iso_8859-15") == 0)
				_encoding = OF_STRING_ENCODING_ISO_8859_15;
			/* Windows and DJGPP use a codepage */
			else if (strcmp(tmp, "1251") == 0)
				_encoding = OF_STRING_ENCODING_WINDOWS_1251;
			else if (strcmp(tmp, "1252") == 0)
				_encoding = OF_STRING_ENCODING_WINDOWS_1252;
			else if (strcmp(tmp, "437") == 0)
				_encoding = OF_STRING_ENCODING_CODEPAGE_437;
			else if (strcmp(tmp, "850") == 0)
				_encoding = OF_STRING_ENCODING_CODEPAGE_850;
			else if (strcmp(tmp, "858") == 0)
				_encoding = OF_STRING_ENCODING_CODEPAGE_858;

		}

		/* Territory */
		if ((tmp = strrchr(locale, '_')) != NULL) {
			*tmp++ = '\0';

			tmpLen = strlen(tmp);







<
<
<
|
<
<
|
<
<
|
|
<
<
|
<
|
<
|
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
>







89
90
91
92
93
94
95



96


97


98
99


100

101

102



103











104
105
106
107
108
109
110
111
		if ((tmp = strrchr(locale, '@')) != NULL)
			*tmp = '\0';

		/* Encoding */
		if ((tmp = strrchr(locale, '.')) != NULL) {
			*tmp++ = '\0';




			@try {


				const of_string_encoding_t ascii =


				    OF_STRING_ENCODING_ASCII;



				_encoding = of_string_parse_encoding([OFString

				    stringWithCString: tmp

					     encoding: ascii]);



			} @catch (OFInvalidEncodingException *e) {











			}
		}

		/* Territory */
		if ((tmp = strrchr(locale, '_')) != NULL) {
			*tmp++ = '\0';

			tmpLen = strlen(tmp);

Modified src/OFString.h from [09f33d7338] to [4a6fdfa037].

1124
1125
1126
1127
1128
1129
1130

1131
1132
1133
1134
1135
1136
1137
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block;
#endif
@end

#ifdef __cplusplus
extern "C" {
#endif

extern size_t of_string_utf8_encode(of_unichar_t, char*);
extern ssize_t of_string_utf8_decode(const char*, size_t, of_unichar_t*);
extern size_t of_string_utf16_length(const of_char16_t*);
extern size_t of_string_utf32_length(const of_char32_t*);
#ifdef __cplusplus
}
#endif







>







1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block;
#endif
@end

#ifdef __cplusplus
extern "C" {
#endif
extern of_string_encoding_t of_string_parse_encoding(OFString*);
extern size_t of_string_utf8_encode(of_unichar_t, char*);
extern ssize_t of_string_utf8_decode(const char*, size_t, of_unichar_t*);
extern size_t of_string_utf16_length(const of_char16_t*);
extern size_t of_string_utf32_length(const of_char32_t*);
#ifdef __cplusplus
}
#endif

Modified src/OFString.m from [0c0cd023b8] to [b05a76cd1f].

119
120
121
122
123
124
125
















































126
127
128
129
130
131
132
}

void
_reference_to_OFConstantString(void)
{
	[OFConstantString class];
}

















































size_t
of_string_utf8_encode(of_unichar_t character, char *buffer)
{
	size_t i = 0;

	if (character < 0x80) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
}

void
_reference_to_OFConstantString(void)
{
	[OFConstantString class];
}

of_string_encoding_t
of_string_parse_encoding(OFString *string)
{
	void *pool = objc_autoreleasePoolPush();
	of_string_encoding_t encoding;

	string = [string lowercaseString];

	if ([string isEqual: @"utf8"] || [string isEqual: @"utf-8"])
		encoding = OF_STRING_ENCODING_UTF_8;
	else if ([string isEqual: @"ascii"] || [string isEqual: @"us-ascii"])
		encoding = OF_STRING_ENCODING_ASCII;
	else if ([string isEqual: @"iso-8859-1"] ||
	    [string isEqual: @"iso_8859-1"])
		encoding = OF_STRING_ENCODING_ISO_8859_1;
	else if ([string isEqual: @"iso-8859-2"] ||
	    [string isEqual: @"iso_8859-2"])
		encoding = OF_STRING_ENCODING_ISO_8859_2;
	else if ([string isEqual: @"iso-8859-15"] ||
	    [string isEqual: @"iso_8859-15"])
		encoding = OF_STRING_ENCODING_ISO_8859_15;
	else if ([string isEqual: @"windows-1251"] ||
	    [string isEqual: @"cp1251"] || [string isEqual: @"cp-1251"] ||
	    [string isEqual: @"1251"])
		encoding = OF_STRING_ENCODING_WINDOWS_1251;
	else if ([string isEqual: @"windows-1252"] ||
	    [string isEqual: @"cp1252"] || [string isEqual: @"cp-1252"] ||
	    [string isEqual: @"1252"])
		encoding = OF_STRING_ENCODING_WINDOWS_1252;
	else if ([string isEqual: @"cp437"] || [string isEqual: @"cp-437"] ||
	    [string isEqual: @"ibm437"] || [string isEqual: @"437"])
		encoding = OF_STRING_ENCODING_CODEPAGE_437;
	else if ([string isEqual: @"cp850"] || [string isEqual: @"cp-850"] ||
	    [string isEqual: @"ibm850"] || [string isEqual: @"850"])
		encoding = OF_STRING_ENCODING_CODEPAGE_850;
	else if ([string isEqual: @"cp858"] || [string isEqual: @"cp-858"] ||
	    [string isEqual: @"ibm858"] || [string isEqual: @"858"])
		encoding = OF_STRING_ENCODING_CODEPAGE_858;
	else if ([string isEqual: @"macintosh"] || [string isEqual: @"mac"])
		encoding = OF_STRING_ENCODING_MAC_ROMAN;
	else
		@throw [OFInvalidEncodingException exception];

	objc_autoreleasePoolPop(pool);

	return encoding;
}

size_t
of_string_utf8_encode(of_unichar_t character, char *buffer)
{
	size_t i = 0;

	if (character < 0x80) {

Modified src/OFXMLParser.m from [72d9697aa5] to [3771da0801].

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
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
			if ([attribute isEqual: @"version"]) {
				if (![value hasPrefix: @"1."])
					return false;

				hasVersion = true;
			}

			if ([attribute isEqual: @"encoding"]) {
				[value lowercase];

				if ([value isEqual: @"utf-8"])
					_encoding = OF_STRING_ENCODING_UTF_8;
				else if ([value isEqual: @"iso-8859-1"] ||
				    [value isEqual: @"iso_8859-1"])
					_encoding =
					    OF_STRING_ENCODING_ISO_8859_1;
				else if ([value isEqual: @"iso-8859-2"] ||
				    [value isEqual: @"iso_8859-2"])
					_encoding =
					    OF_STRING_ENCODING_ISO_8859_2;
				else if ([value isEqual: @"iso-8859-15"] ||
				    [value isEqual: @"iso_8859-15"])
					_encoding =
					    OF_STRING_ENCODING_ISO_8859_15;
				else if ([value isEqual: @"windows-1251"] ||
				    [value isEqual: @"cp1251"] ||
				    [value isEqual: @"cp-1251"])
					_encoding =
					    OF_STRING_ENCODING_WINDOWS_1251;
				else if ([value isEqual: @"windows-1252"] ||
				    [value isEqual: @"cp1252"] ||
				    [value isEqual: @"cp-1252"])
					_encoding =
					    OF_STRING_ENCODING_WINDOWS_1252;
				else if ([value isEqual: @"cp437"] ||
				    [value isEqual: @"cp-437"])
					_encoding =
					    OF_STRING_ENCODING_CODEPAGE_437;
				else if ([value isEqual: @"cp850"] ||
				    [value isEqual: @"cp-850"])
					_encoding =
					    OF_STRING_ENCODING_CODEPAGE_850;
				else if ([value isEqual: @"cp858"] ||
				    [value isEqual: @"cp-858"])
					_encoding =
					    OF_STRING_ENCODING_CODEPAGE_858;
				else if ([value isEqual: @"macintosh"])
					_encoding =
					    OF_STRING_ENCODING_MAC_ROMAN;
				else
					return false;
			}

			last = i + 1;
			PIState = 0;

			break;
		}
	}







|
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







457
458
459
460
461
462
463
464






465





































466
467
468
469
470
471
472
			if ([attribute isEqual: @"version"]) {
				if (![value hasPrefix: @"1."])
					return false;

				hasVersion = true;
			}

			if ([attribute isEqual: @"encoding"])






				_encoding = of_string_parse_encoding(value);






































			last = i + 1;
			PIState = 0;

			break;
		}
	}

Modified tests/OFXMLParserTests.m from [bb4f740fa9] to [b4df7e9977].

20
21
22
23
24
25
26

27
28
29
30
31
32
33
#include <string.h>

#import "OFXMLParser.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFAutoreleasePool.h"


#import "OFMalformedXMLException.h"

#import "TestsAppDelegate.h"

static OFString *module = @"OFXMLParser";
static OFXMLParser *parser;
static int i = 0;







>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <string.h>

#import "OFXMLParser.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFAutoreleasePool.h"

#import "OFInvalidEncodingException.h"
#import "OFMalformedXMLException.h"

#import "TestsAppDelegate.h"

static OFString *module = @"OFXMLParser";
static OFXMLParser *parser;
static int i = 0;
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #1",
	    OFMalformedXMLException,
	    [parser parseString: @"<?xml version='2.0'?>"])

	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #2",
	    OFMalformedXMLException,
	    [parser parseString: @"<?xml encoding='UTF-7'?>"])

	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #3",
	    OFMalformedXMLException,
	    [parser parseString: @"<x><?xml?></x>"])

	[pool drain];
}
@end







|










380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #1",
	    OFMalformedXMLException,
	    [parser parseString: @"<?xml version='2.0'?>"])

	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #2",
	    OFInvalidEncodingException,
	    [parser parseString: @"<?xml encoding='UTF-7'?>"])

	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #3",
	    OFMalformedXMLException,
	    [parser parseString: @"<x><?xml?></x>"])

	[pool drain];
}
@end