ObjFW  Check-in [494dca4ae4]

Overview
Comment:Use XML for serialization.

This way, we don't need a new parser and don't use a new format.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 494dca4ae4a4ab7343ea13b6f7f3cee6bd0f9922173c684f3f8d55bc0a22b7ed
User & Date: js on 2011-05-14 12:26:39
Other Links: manifest | tags
Context
2011-05-14
19:48
Ignore whitespaces around the root element in -[initWithXMLString]. check-in: 12a8ac4cb3 user: js tags: trunk
12:26
Use XML for serialization. check-in: 494dca4ae4 user: js tags: trunk
2011-05-12
19:58
Style improvements. check-in: 85ffbaabbb user: js tags: trunk
Changes

Deleted SERIALIZATION version [0e6d0b7c8b].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
181
182






















































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1.) Basic Concept

This document describes the serialization used by ObjFW. It is designed to be
easy parsable and usable in other programming languages while still supporting
ObjFW-specific features, which are all optional.

Every object can have a set of parameters which are optional and can be ignored
if they don't exist in the language for which parsing is done. These parameters
are written in the form (parameter1,parameter2) and precede the object.
Parameters not known by the implementation should be ignored - they are
completely optional except for the extension type.

All spaces (except those in strings, of course) are optional and only to improve
readability - they are by no means required, but they are still recommended.

ObjFW serialization supports 4 basic types: Strings, arrays and dictionaries.
It is limited to those 4 types because those are available in all languages.
Lists are a special case of arrays in ObjFW serialization. For all objects
that can not be serialized with those 4 basic types, there is the extension
type [], which can be used for any object but is not portable between languages.
This type is described in 6.).


2.) Strings

Strings are very similar to how strings are done in C. They start with a " and
end with a ". The escape sequences \", \\, \n, \r and \t exist, like in C
strings. It is required to use \", \\, \n and \r. The reason for this is that
using an actual newline would modify the string when indention is done. However,
using \t is recommended.
Strings can be split just like in C. For example "Hello " "World" is equivalent
to "Hello World". Because this is possible, it is recommended to end the string
after \n and continue it in a new line to increase readability.

Strings are required to be UTF-8 encoded.

The only accepted parameter for strings is mutable. If the language for which
parsing is done does not know the concept of mutable and immutable objects, this
parameter should be ignored.

Examples for strings:

	"This is a \"string!\""

	"This is a string containing a\n"
	    "new line!"

	"This is\ta string\tcontaining tabs!"

	(mutable)"This string is mutable!"


3.) Arrays

Arrays start with a [ and end with an ]. The elements are separated by a comma.
Whitespaces are allowed between objects and after the inital [ and before the
final ].

It allows the mutable parameter, which should be handled the same way like it
should be for strings.

It also has the list parameter. Specifying this parameter creates a
double-linked list instead of an array.

It also allows specifying a number as a parameter. This number is considered
the expected size of the array. It is by no means required and it should by no
means be assumed to be reliable. If the number is not equal to the actual size,
the parser should error out. The parser should also make sure to ignore the
number if it is too big to prevent a possible DoS.

Examples for arrays:

	["This", "is", "an", "array", "with", "7", "strings"]

	(mutable)["This array", "is mutable"]

	(3)["This array specifies", "the number of elements", "for performance"]

	(mutable,2)["Parameters can be", "combined"]


4.) Dictionaries

Dictionary start with a { and end with a }. The elements are written in the form
key = value and each entry ends with an ;.

It allows the mutable parameter, which should be handled the same way like it
should be for strings.

It also allows specifying a number as a parameter, which should be handled
exactly like for arrays.

Examples for dictionaries:

	{"This is a key" = "This is a value"}

	(mutable){"mutable" = (BOOL)1}

	(2){
		"key1" = "value1",
		"key2" = "value2"
	}

	{
		["Mapping", "an", "array"] = "To a string";
		{ "mapping" = "a dictionary" } = ["To", "an", "array"];
	}


5.) Numbers

Numbers are written by just writing a number. The type of a number may be
specified by a parameter. If it is not specified, the implementation should
choose are type which fits the number. If the specified type is not big enough
for the number, the implementation should use another type that fits.

Known parameters are:
	BOOL
	char		(signed!)
	short		(signed!)
	int		(signed!)
	long		(signed!)
	int8_t
	int16_t
	int32_t
	int64_t
	unsigned char,
	unsigned short,
	unsigned int,
	unsigned long
	uint8_t
	uint16_t
	uint32_t
	uint64_t
	size_t
	ssize_t
	intmax_t
	uintmax_t
	intptr_t
	uintptr_t
	float
	double

Examples for numbers:

	1
	2.6
	(BOOL)0
	(intmax_t)1234567
	(double)2.5


6.) Extension Type

The extension type allows adding new objects to ObjFW serialization. The
extension type has a parameter class= which specifies the class which should
handle deserialization and a version= parameter which specifies the version of
the class serialization as a single integer. The extension type starts with a [
and ends with a ]. Inside those brackets can be arbitray basic types, which
should be passed unmodified to the class for deserialization.
If an implementation can't deserialize an extension type, it is required to
error out. Other languages are allowed to parse extension types of classes which
are in ObjFW, like OFXMLElement, but are by no means required to do so. Other
languages may also add their own extension types, but are required to add the
foreign= parameter and set it to their name, so other implementations don't try
to deserialize it, but error out instead. Other implementations are allowed to
serialize to ObjFW objects if they know them. For example, it might be desirable
to also create OFXMLElements from other languages.

Examples for using the extension type:

	(class=OFXMLElement)<"<some-xml/>">

 	(class=OFURL)<
		"https://webkeks.org/objfw/"
	>

 	(class=Foo,foreign=Foolang)<
		{
			"property1" = "value1"
		}
	>

Modified src/OFArray.m from [40c18091bb] to [7df94bcaeb].

17
18
19
20
21
22
23

24
25
26
27
28
29
30
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31







+







#include "config.h"

#include <stdarg.h>

#import "OFArray.h"
#import "OFDataArray.h"
#import "OFString.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

#import "OFEnumerationMutationException.h"
#import "OFOutOfRangeException.h"

#import "macros.h"

428
429
430
431
432
433
434
435

436
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
429
430
431
432
433
434
435

436
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







-
+


-
-
-
+
+
+

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

+
+

-
+
-
-
-
+


-
-
-
-



-
-
-
-
-
-
-
+







	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	ret->isa = [OFString class];
	return ret;
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool;
	OFMutableString *ret;
	OFObject <OFSerialization> **cArray;
	size_t i, count;
	OFXMLElement *element;
	id <OFSerialization> *cArray = [array cArray];
	size_t i, count = [array count];

	if ([array count] == 0) {
		if ([self isKindOfClass: [OFMutableArray class]])
	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];
			return @"(mutable,0)[]";
		else
			return @"(0)[]";
	}


	cArray = [array cArray];
	count = [array count];
	if ([self isKindOfClass: [OFMutableArray class]])
		ret = [OFMutableString stringWithFormat: @"(mutable,%zd)[\n",
							 count];
	else
		ret = [OFMutableString stringWithFormat: @"(%zd)[\n", count];
	pool = [[OFAutoreleasePool alloc] init];
	[element addAttributeWithName: @"class"
			  stringValue: [self className]];

	for (i = 0; i < count - 1; i++) {
	for (i = 0; i < count; i++) {
		[ret appendString: [cArray[i] stringBySerializing]];
		[ret appendString: @",\n"];

		[element addChild: [cArray[i] XMLElementBySerializing]];
		[pool releaseObjects];
	}
	[ret appendString: [cArray[i] stringBySerializing]];
	[ret replaceOccurrencesOfString: @"\n"
			     withString: @"\n\t"];
	[ret appendString: @"\n]"];

	[pool release];

	/*
	 * Class swizzle the string to be immutable. We declared the return type
	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	ret->isa = [OFString class];
	return ret;
	return element;
}

- (void)makeObjectsPerformSelector: (SEL)selector
{
	id *cArray = [array cArray];
	size_t i, count = [array count];

Modified src/OFDate.m from [879a67dcaa] to [1c6620e225].

21
22
23
24
25
26
27
28

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

28
29
30
31
32
33
34
35







-
+







#include <time.h>

#include <sys/time.h>

#import "OFDate.h"
#import "OFString.h"
#import "OFDictionary.h"
#import "OFNumber.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"
#ifdef OF_THREADS
# import "OFThread.h"
#endif

#import "OFInitializationFailedException.h"
#import "OFInvalidArgumentException.h"
287
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302









303
304
305
306
307
308












309
310

311
312
313
314
315
316
317
287
288
289
290
291
292
293

294
295







296
297
298
299
300
301
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







-
+

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

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

-
+







}

- (OFString*)description
{
	return [self dateStringWithFormat: @"%Y-%m-%dT%H:%M:%SZ"];
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFDictionary *dictionary = [OFDictionary dictionaryWithKeysAndObjects:
	    @"seconds", [OFNumber numberWithInt64: seconds],
	    @"microseconds", [OFNumber numberWithUInt32: microseconds], nil];
	OFString *ret = [[OFString alloc]
	    initWithFormat: @"(class=OFDate,version=0)<%@>",
			    [dictionary stringBySerializing]];
	OFAutoreleasePool *pool;
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];

	pool = [[OFAutoreleasePool alloc] init];
	[element addAttributeWithName: @"class"
			  stringValue: [self className]];

	@try {
		[pool release];
	} @finally {
		[ret autorelease];
	}
	[element addChild:
	    [OFXMLElement elementWithName: @"seconds"
				namespace: OF_SERIALIZATION_NS
			      stringValue: [OFString stringWithFormat:
					       @"%" PRId64, seconds]]];
	[element addChild:
	    [OFXMLElement elementWithName: @"microseconds"
				namespace: OF_SERIALIZATION_NS
			      stringValue: [OFString stringWithFormat:
					       @"%" PRIu32, microseconds]]];

	[pool release];

	return ret;
	return element;
}

- (uint32_t)microsecond
{
	return microseconds;
}

Modified src/OFDictionary.m from [167e60e6d6] to [5f45c17283].

18
19
20
21
22
23
24

25
26
27
28
29
30
31
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32







+








#include <string.h>

#import "OFDictionary.h"
#import "OFEnumerator.h"
#import "OFArray.h"
#import "OFString.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

#import "OFEnumerationMutationException.h"
#import "OFInvalidArgumentException.h"
#import "OFOutOfRangeException.h"

#import "macros.h"
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
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







-
+

-

+

-
+
-

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

+
+
+



-

-

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

+
+
+
+
+
-
-
+
+



-
-
-



-
-
-
-
-
-
-
+







	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	ret->isa = [OFString class];
	return ret;
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFMutableString *ret;
	OFAutoreleasePool *pool, *pool2;
	OFXMLElement *element;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	id key, object;
	id <OFSerialization> key, object;
	size_t i;

	if (count == 0) {
	element = [OFXMLElement elementWithName: @"object"
		if ([self isKindOfClass: [OFMutableDictionary class]])
			return @"(mutable,0){}";
		else
			return @"(0){}";
	}
				      namespace: OF_SERIALIZATION_NS];


	if ([self isKindOfClass: [OFMutableDictionary class]])
		ret = [OFMutableString stringWithFormat: @"(mutable,%zd){\n",
							 count];
	else
		ret = [OFMutableString stringWithFormat: @"(%zd){\n", count];
	pool = [[OFAutoreleasePool alloc] init];
	[element addAttributeWithName: @"class"
			  stringValue: [self className]];

	keyEnumerator = [self keyEnumerator];
	objectEnumerator = [self objectEnumerator];

	i = 0;
	pool2 = [[OFAutoreleasePool alloc] init];

	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		[ret appendString: [key stringBySerializing]];
		[ret appendString: @" = "];
		[ret appendString: [object stringBySerializing]];
	       (object = [objectEnumerator nextObject]) != nil) {
		OFXMLElement *pair, *keyElement, *valueElement;

		pair = [OFXMLElement elementWithName: @"pair"
					   namespace: OF_SERIALIZATION_NS];

		keyElement = [OFXMLElement
		    elementWithName: @"key"
			  namespace: OF_SERIALIZATION_NS];
		[keyElement addChild: [key XMLElementBySerializing]];
		[pair addChild: keyElement];

		valueElement = [OFXMLElement
		    elementWithName: @"value"
			  namespace: OF_SERIALIZATION_NS];
		[valueElement addChild: [object XMLElementBySerializing]];
		[pair addChild: valueElement];
		if (++i < count)
			[ret appendString: @",\n"];

		[element addChild: pair];

		[pool2 releaseObjects];
	}
	[ret replaceOccurrencesOfString: @"\n"
			     withString: @"\n\t"];
	[ret appendString: @"\n}"];

	[pool release];

	/*
	 * Class swizzle the string to be immutable. We declared the return type
	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	ret->isa = [OFString class];
	return ret;
	return element;
}
@end

@implementation OFDictionaryEnumerator
- initWithDictionary: (OFDictionary*)dictionary_
		data: (struct of_dictionary_bucket**)data_
		size: (uint32_t)size_

Modified src/OFList.m from [75df3d0578] to [60c8cd9af5].

16
17
18
19
20
21
22

23
24
25
26
27
28
29
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30







+








#include "config.h"

#include "assert.h"

#import "OFList.h"
#import "OFString.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

#import "OFEnumerationMutationException.h"

#import "macros.h"

@implementation OFList
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
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







-
+

-

+


-
-
+
+

-

+
+


-
-
+
-
-
-


-
-
-



-
-
-
-
-
-
-
+






-
+





-
+



-
+


-
-
+
+







	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	ret->isa = [OFString class];
	return ret;
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFMutableString *ret;
	OFAutoreleasePool *pool;
	OFXMLElement *element;
	of_list_object_t *iter;

	if (count == 0)
		return @"(list,mutable)[]";
	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];

	ret = [OFMutableString stringWithString: @"(list,mutable)[\n"];
	pool = [[OFAutoreleasePool alloc] init];
	[element addAttributeWithName: @"class"
			  stringValue: [self className]];

	for (iter = firstListObject; iter != NULL; iter = iter->next) {
		[ret appendString: [iter->object stringBySerializing]];

		[element addChild: [iter->object XMLElementBySerializing]];
		if (iter->next != NULL)
			[ret appendString: @",\n"];

		[pool releaseObjects];
	}
	[ret replaceOccurrencesOfString: @"\n"
			     withString: @"\n\t"];
	[ret appendString: @"\n]"];

	[pool release];

	/*
	 * Class swizzle the string to be immutable. We declared the return type
	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	ret->isa = [OFString class];
	return ret;
	return element;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
			   objects: (id*)objects
			     count: (int)count_
{
	of_list_object_t **list_obj = (of_list_object_t**)state->extra;
	of_list_object_t **listObject = (of_list_object_t**)state->extra;

	state->itemsPtr = objects;
	state->mutationsPtr = &mutations;

	if (state->state == 0) {
		*list_obj = firstListObject;
		*listObject = firstListObject;
		state->state = 1;
	}

	if (*list_obj == NULL)
	if (*listObject == NULL)
		return 0;

	objects[0] = (*list_obj)->object;
	*list_obj = (*list_obj)->next;
	objects[0] = (*listObject)->object;
	*listObject = (*listObject)->next;
	return 1;
}

- (OFEnumerator*)objectEnumerator
{
	return [[[OFListEnumerator alloc]
	        initWithList: self

Modified src/OFNumber.m from [2324ed47e6] to [01b0cb5868].

16
17
18
19
20
21
22


23
24
25
26
27
28
29
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31







+
+








#include "config.h"

#include <math.h>

#import "OFNumber.h"
#import "OFString.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

#import "OFInvalidFormatException.h"
#import "OFNotImplementedException.h"

#import "macros.h"

#define RETURN_AS(t)							\
1086
1087
1088
1089
1090
1091
1092
1093

1094












1095
1096

1097


1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130



1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164

1165
1166


1167
1168
1169



1170
1171
1172



1173
1174
1175
1176





1177
1088
1089
1090
1091
1092
1093
1094

1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111

1112
1113
1114


1115


1116


1117


1118


1119


1120


1121


1122


1123


1124


1125
1126
1127
1128


1129


1130


1131


1132


1133


1134


1135


1136


1137


1138


1139
1140


1141
1142
1143


1144
1145
1146
1147


1148
1149
1150
1151
1152
1153

1154
1155
1156
1157
1158
1159







-
+

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


+
-
+
+

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-
+
+
+

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-

+
-
-
+
+

-
-
+
+
+

-
-
+
+
+



-
+
+
+
+
+

	case OF_NUMBER_DOUBLE:
		return [OFString stringWithFormat: @"%lf", value.double_];
	default:
		@throw [OFInvalidFormatException newWithClass: isa];
	}
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool;
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];

	pool = [[OFAutoreleasePool alloc] init];

	[element addAttributeWithName: @"class"
			  stringValue: [self className]];
	[element setStringValue: [self description]];

	switch (type) {
	case OF_NUMBER_BOOL:
		[element addAttributeWithName: @"type"
		return (value.bool_ ? @"<BOOL>1" : @"<BOOL>0");
				  stringValue: @"boolean"];
		break;
	case OF_NUMBER_UCHAR:
		return [OFString stringWithFormat: @"<unsigned char>%hhu",
						   value.uchar];
	case OF_NUMBER_USHORT:
		return [OFString stringWithFormat: @"<unsigned short>%hu",
						   value.ushort];
	case OF_NUMBER_UINT:
		return [OFString stringWithFormat: @"<unsigned int>%u",
						   value.uint];
	case OF_NUMBER_ULONG:
		return [OFString stringWithFormat: @"<unsigned long>%lu",
						   value.ulong];
	case OF_NUMBER_UINT8:
		return [OFString stringWithFormat: @"<uint8_t>%" @PRIu8,
						   value.uint8];
	case OF_NUMBER_UINT16:
		return [OFString stringWithFormat: @"<uint16_t>%" @PRIu16,
						   value.uint16];
	case OF_NUMBER_UINT32:
		return [OFString stringWithFormat: @"<uint32_t>%" @PRIu32,
						   value.uint32];
	case OF_NUMBER_UINT64:
		return [OFString stringWithFormat: @"<uint64_t>%" @PRIu64,
						   value.uint64];
	case OF_NUMBER_SIZE:
		return [OFString stringWithFormat: @"<size_t>%ju",
						   (uintmax_t)value.size];
	case OF_NUMBER_UINTMAX:
		return [OFString stringWithFormat: @"<uintmax_t>%ju",
						   value.uintmax];
	case OF_NUMBER_UINTPTR:
		return [OFString stringWithFormat: @"<uintptr_t>%" @PRIuPTR,
						   value.uintptr];
		[element addAttributeWithName: @"type"
				  stringValue: @"unsigned"];
		break;
	case OF_NUMBER_CHAR:
		return [OFString stringWithFormat: @"<char>%hhd",
						   value.char_];
	case OF_NUMBER_SHORT:
		return [OFString stringWithFormat: @"<short>%hd",
						   value.short_];
	case OF_NUMBER_INT:
		return [OFString stringWithFormat: @"<int>%d",
						   value.int_];
	case OF_NUMBER_LONG:
		return [OFString stringWithFormat: @"<long>%ld",
						   value.long_];
	case OF_NUMBER_INT8:
		return [OFString stringWithFormat: @"<int8_t>%" @PRId8,
						   value.int8];
	case OF_NUMBER_INT16:
		return [OFString stringWithFormat: @"<int16_t>%" @PRId16,
						   value.int16];
	case OF_NUMBER_INT32:
		return [OFString stringWithFormat: @"<int32_t>%" @PRId32,
						   value.int32];
	case OF_NUMBER_INT64:
		return [OFString stringWithFormat: @"<int64_t>%" @PRId64,
						   value.int64];
	case OF_NUMBER_SSIZE:
		return [OFString stringWithFormat: @"<ssize_t>%jd",
						   (intmax_t)value.ssize];
	case OF_NUMBER_INTMAX:
		return [OFString stringWithFormat: @"<intmax_t>%jd",
						   value.intmax];
	case OF_NUMBER_PTRDIFF:
		return [OFString stringWithFormat: @"<ptrdiff_t>%td" @PRIdPTR,
						   value.ptrdiff];
	case OF_NUMBER_INTPTR:
		[element addAttributeWithName: @"type"
		return [OFString stringWithFormat: @"<intptr_t>%" @PRIdPTR,
						   value.intptr];
				  stringValue: @"signed"];
		break;
	case OF_NUMBER_FLOAT:
		return [OFString stringWithFormat: @"<float>%f",
						   value.float_];
		[element addAttributeWithName: @"type"
				  stringValue: @"float"];
		break;
	case OF_NUMBER_DOUBLE:
		return [OFString stringWithFormat: @"<double>%lf",
						   value.double_];
		[element addAttributeWithName: @"type"
				  stringValue: @"double"];
		break;
	default:
		@throw [OFInvalidFormatException newWithClass: isa];
	}
}

	[pool release];

	return element;
}
@end

Modified src/OFSerialization.h from [c6e17d739a] to [14e103c34d].

11
12
13
14
15
16
17



18
19
20
21
22
23
24



25
26

27
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30

31
32







+
+
+






-
+
+
+

-
+

 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

@class OFString;
@class OFXMLElement;

#define OF_SERIALIZATION_NS @"https://webkeks.org/objfw/serialization"

/**
 * \brief A protocol for serializing objects.
 */
@protocol OFSerialization <OFObject>
/**
 * \brief Serializes the object into a string.
 * \brief Serializes the object into an XML element.
 *
 * \return The object serialized into an XML element
 */
- (OFString*)stringBySerializing;
- (OFXMLElement*)XMLElementBySerializing;
@end

Modified src/OFString.m from [bb52ca9d4f] to [47a649e523].

32
33
34
35
36
37
38

39
40
41
42
43
44
45
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46







+








#import "OFString.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFFile.h"
#import "OFURL.h"
#import "OFHTTPRequest.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

#import "OFHTTPRequestFailedException.h"
#import "OFInitializationFailedException.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidEncodingException.h"
#import "OFInvalidFormatException.h"
1051
1052
1053
1054
1055
1056
1057
1058

1059
1060
1061
1062
1063
1064





1065
1066
1067
1068
1069


1070

1071
1072
1073



1074
1075
1076


1077

1078

1079
1080
1081
1082
1083
1084

1085
1086
1087
1088
1089
1090
1091
1052
1053
1054
1055
1056
1057
1058

1059
1060





1061
1062
1063
1064
1065





1066
1067

1068
1069


1070
1071
1072
1073


1074
1075
1076
1077

1078






1079
1080
1081
1082
1083
1084
1085
1086







-
+

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

-
-
+
+
+

-
-
+
+

+
-
+
-
-
-
-
-
-
+







}

- (OFString*)description
{
	return [[self copy] autorelease];
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFMutableString *serialization = [[self mutableCopy] autorelease];
	[serialization replaceOccurrencesOfString: @"\\"
				       withString: @"\\\\"];
	[serialization replaceOccurrencesOfString: @"\""
				       withString: @"\\\""];
	OFAutoreleasePool *pool;
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS
	[serialization replaceOccurrencesOfString: @"\n"
				       withString: @"\\n\"\n    \""];
	[serialization replaceOccurrencesOfString: @"\r"
				       withString: @"\\r"];
	[serialization replaceOccurrencesOfString: @"\t"
				    stringValue: self];

				       withString: @"\\t"];
	pool = [[OFAutoreleasePool alloc] init];

	if ([self isKindOfClass: [OFMutableString class]])
		[serialization prependString: @"(mutable)\""];
	if ([self isKindOfClass: [OFConstantString class]])
		[element addAttributeWithName: @"class"
				  stringValue: @"OFString"];
	else
		[serialization prependString: @"\""];
	[serialization appendString: @"\""];
		[element addAttributeWithName: @"class"
				  stringValue: [self className]];

	[pool release];
	/*

	 * Class swizzle the string to be immutable. We declared the return type
	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	serialization->isa = [OFString class];
	return serialization;
	return element;
}

- (of_unichar_t)characterAtIndex: (size_t)index
{
	of_unichar_t c;

	if (![self isUTF8]) {

Modified src/OFURL.m from [267c53672b] to [8362d51987].

19
20
21
22
23
24
25

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







+







#include <stdlib.h>
#include <string.h>
#include <assert.h>

#import "OFURL.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFOutOfMemoryException.h"

#import "macros.h"
526
527
528
529
530
531
532
533

534
535
536
537
538





539
540
541
542
543
544







545
546

547
548
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







-
+

-
-
-
-
+
+
+
+
+

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

-
+


}

- (OFString*)description
{
	return [self string];
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFString *ret = [[OFString alloc]
	    initWithFormat: @"(class=OFURL,version=0)<%@>",
			    [[self string] stringBySerializing]];
	OFAutoreleasePool *pool;
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];

	@try {
		[pool release];
	} @finally {
		[ret autorelease];
	}
	pool = [[OFAutoreleasePool alloc] init];

	[element addAttributeWithName: @"class"
			  stringValue: [self className]];
	[element setStringValue: [self string]];

	[pool release];

	return ret;
	return element;
}
@end

Modified src/OFXMLAttribute.m from [a0cfce89af] to [be193dc061].

15
16
17
18
19
20
21

22
23
24
25
26
27
28
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29







+







 */

#include "config.h"

#import "OFXMLAttribute.h"
#import "OFString.h"
#import "OFDictionary.h"
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"

@implementation OFXMLAttribute
+ attributeWithName: (OFString*)name
	  namespace: (OFString*)ns
	stringValue: (OFString*)value
{
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
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







-
+

-
-
-
+
+
+
+
+
+
+

-
-
-
+
+
+
+
+
+
+

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

-
-
+
-
-
-
+
-
-
+


}

- (OFString*)stringValue
{
	return [[stringValue copy] autorelease];
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFMutableDictionary *dictionary = [OFMutableDictionary dictionary];
	OFString *ret;
	OFAutoreleasePool *pool;
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];

	pool = [[OFAutoreleasePool alloc] init];

	if (name != nil)
		[dictionary setObject: name
			       forKey: @"name"];
	[element addAttributeWithName: @"class"
			  stringValue: [self className]];

	[element addChild:
	    [OFXMLElement elementWithName: @"name"
				namespace: OF_SERIALIZATION_NS
			      stringValue: name]];
	if (ns != nil)
		[dictionary setObject: ns
			       forKey: @"namespace"];
	if (stringValue != nil)
		[element addChild:
		    [OFXMLElement elementWithName: @"namespace"
					namespace: OF_SERIALIZATION_NS
				      stringValue: ns]];
		[dictionary setObject: stringValue
			       forKey: @"stringValue"];

	[element addChild:
	    [OFXMLElement elementWithName: @"stringValue"
				namespace: OF_SERIALIZATION_NS
	dictionary->isa = [OFDictionary class];

			      stringValue: stringValue]];
	ret = [[OFString alloc]
	    initWithFormat: @"(class=OFXMLElement,version=0)<%@>",
			    [dictionary stringBySerializing]];

	@try {
		[pool release];
	[pool release];
	} @finally {
		[ret autorelease];
	}


	return ret;
	return element;
}
@end

Modified src/OFXMLElement.m from [dfde4a28b8] to [d290a6e873].

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
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







-
+

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


+
+
+
-
-
+
+

+
+
+
-
-
+
+

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

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

+
+
-
+







}

- (OFString*)description
{
	return [self XMLString];
}

- (OFString*)stringBySerializing
- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFMutableDictionary *dictionary = [OFMutableDictionary dictionary];
	OFString *ret;
	OFAutoreleasePool *pool;
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"object"
				      namespace: OF_SERIALIZATION_NS];

	pool = [[OFAutoreleasePool alloc] init];

	[element addAttributeWithName: @"class"
			  stringValue: [self className]];

	if (name != nil)
		[element addChild:
		    [OFXMLElement elementWithName: @"name"
					namespace: OF_SERIALIZATION_NS
		[dictionary setObject: name
			       forKey: @"name"];
				      stringValue: name]];

	if (ns != nil)
		[element addChild:
		    [OFXMLElement elementWithName: @"namespace"
					namespace: OF_SERIALIZATION_NS
		[dictionary setObject: ns
			       forKey: @"namespace"];
				      stringValue: ns]];

	if (defaultNamespace != nil)
		[element addChild:
		[dictionary setObject: defaultNamespace
			       forKey: @"defaultNamespace"];
	if (attributes != nil)
		[dictionary setObject: attributes
			       forKey: @"attributes"];
	if (namespaces != nil)
		    [OFXMLElement elementWithName: @"defaultNamespace"
					namespace: OF_SERIALIZATION_NS
				      stringValue: defaultNamespace]];

	if (attributes != nil) {
		OFXMLElement *attributesElement;

		attributesElement =
		    [OFXMLElement elementWithName: @"attributes"
					namespace: OF_SERIALIZATION_NS];
		[dictionary setObject: namespaces
			       forKey: @"namespaces"];
	if (children != nil)
		[dictionary setObject: children
			       forKey: @"children"];
	if (characters != nil)
		[dictionary setObject: characters
			       forKey: @"characters"];
	if (CDATA != nil)
		[dictionary setObject: CDATA
			       forKey: @"CDATA"];
	if (comment != nil)
		[dictionary setObject: comment
			       forKey: @"comment"];

	dictionary->isa = [OFDictionary class];
		[attributesElement addChild:
		    [attributes XMLElementBySerializing]];
		[element addChild: attributesElement];
	}

	if (namespaces != nil) {
		OFXMLElement *namespacesElement;

	ret = [[OFString alloc]
	    initWithFormat: @"(class=OFXMLElement,version=0)<%@>",
			    [dictionary stringBySerializing]];

	@try {
		[pool release];
	} @finally {
		[ret autorelease];
	}
		namespacesElement =
		    [OFXMLElement elementWithName: @"namespaces"
					namespace: OF_SERIALIZATION_NS];
		[namespacesElement addChild:
		    [namespaces XMLElementBySerializing]];
		[element addChild: namespacesElement];
	}

	if (children != nil) {
		OFXMLElement *childrenElement;

		childrenElement =
		    [OFXMLElement elementWithName: @"children"
					namespace: OF_SERIALIZATION_NS];
		[childrenElement addChild: [children XMLElementBySerializing]];
		[element addChild: childrenElement];
	}

	if (characters != nil)
		[element addChild:
		    [OFXMLElement elementWithName: @"characters"
					namespace: OF_SERIALIZATION_NS
				      stringValue: characters]];

	if (CDATA != nil)
		[element addChild:
		    [OFXMLElement elementWithName: @"CDATA"
					namespace: OF_SERIALIZATION_NS
				      stringValue: CDATA]];

	if (comment != nil)
		[element addChild:
		    [OFXMLElement elementWithName: @"comment"
					namespace: OF_SERIALIZATION_NS
				      stringValue: comment]];

	[pool release];

	return ret;
	return element;
}

- (void)addAttribute: (OFXMLAttribute*)attribute
{
	if (name == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						       selector: _cmd];