ObjFW  Check-in [a6ee2b2065]

Overview
Comment:Slightly changed serialization format.

printf's %a was too fragile to serialize floats and doubles, as it was
behaving differently on different OSes and OS versions. Instead, a hex
representation of the float/double in big endian is used now. While this
is less readable, it is guaranteed to be accurate and always the same.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a6ee2b20655bc5165c9244b121b82d1f1bed77a3190e3978debc9133ea9b2e82
User & Date: js on 2012-07-31 12:05:46
Other Links: manifest | tags
Context
2012-07-31
18:56
.gitignore: Add tests/objc_sync/objc_sync. check-in: 7806e49ef6 user: js tags: trunk
12:05
Slightly changed serialization format. check-in: a6ee2b2065 user: js tags: trunk
11:32
Check version of serialization format. check-in: a2b0cd02a5 user: js tags: trunk
Changes

Modified src/OFDate.m from [c0e29e0a91] to [1da3535d97].

319
320
321
322
323
324
325




326
327
328
329
330
331
332

333
334
335
336
337
338
339
340

- initWithSerialization: (OFXMLElement*)element
{
	self = [super init];

	@try {
		OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];





		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]
				      selector: _cmd];


		seconds = [element doubleValue];

		[pool release];
	} @catch (id e) {
		[self release];
		@throw e;
	}








>
>
>
>







>
|







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

- initWithSerialization: (OFXMLElement*)element
{
	self = [super init];

	@try {
		OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
		union {
			double d;
			uint64_t u;
		} d;

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]
				      selector: _cmd];

		d.u = (uint64_t)[element hexadecimalValue];
		seconds = of_bswap_double_if_le(d.d);

		[pool release];
	} @catch (id e) {
		[self release];
		@throw e;
	}

406
407
408
409
410
411
412




413
414
415


416

417
418
419
420
421
422
423
	return [self dateStringWithFormat: @"%Y-%m-%dT%H:%M:%SZ"];
}

- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFXMLElement *element;





	element = [OFXMLElement elementWithName: [self className]
				      namespace: OF_SERIALIZATION_NS];


	[element setStringValue: [OFString stringWithFormat: @"%la", seconds]];


	[element retain];
	[pool release];
	[element autorelease];

	return element;
}







>
>
>
>



>
>
|
>







411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
	return [self dateStringWithFormat: @"%Y-%m-%dT%H:%M:%SZ"];
}

- (OFXMLElement*)XMLElementBySerializing
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFXMLElement *element;
	union {
		double d;
		uint64_t u;
	} d;

	element = [OFXMLElement elementWithName: [self className]
				      namespace: OF_SERIALIZATION_NS];

	d.d = of_bswap_double_if_le(seconds);
	[element setStringValue:
	    [OFString stringWithFormat: @"%016" PRIx64, d.u]];

	[element retain];
	[pool release];
	[element autorelease];

	return element;
}

Modified src/OFNumber.m from [b82d9f97c4] to [b7208d53f6].

748
749
750
751
752
753
754







755
756
757







758
759
760
761
762
763
764
765
766
			 */
			type = OF_NUMBER_UINTMAX;
			value.uintmax = [element decimalValue];
		} else if ([typeString isEqual: @"signed"]) {
			type = OF_NUMBER_INTMAX;
			value.intmax = [element decimalValue];
		} else if ([typeString isEqual: @"float"]) {







			type = OF_NUMBER_FLOAT;
			value.float_ = [element floatValue];
		} else if ([typeString isEqual: @"double"]) {







			type = OF_NUMBER_DOUBLE;
			value.double_ = [element doubleValue];
		} else
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]
				      selector: _cmd];

		[pool release];
	} @catch (id e) {







>
>
>
>
>
>
>

|

>
>
>
>
>
>
>

|







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
			 */
			type = OF_NUMBER_UINTMAX;
			value.uintmax = [element decimalValue];
		} else if ([typeString isEqual: @"signed"]) {
			type = OF_NUMBER_INTMAX;
			value.intmax = [element decimalValue];
		} else if ([typeString isEqual: @"float"]) {
			union {
				float f;
				uint32_t u;
			} f;

			f.u = (uint32_t)[element hexadecimalValue];

			type = OF_NUMBER_FLOAT;
			value.float_ = of_bswap_float_if_le(f.f);
		} else if ([typeString isEqual: @"double"]) {
			union {
				double d;
				uint64_t u;
			} d;

			d.u = (uint64_t)[element hexadecimalValue];

			type = OF_NUMBER_DOUBLE;
			value.double_ = of_bswap_double_if_le(d.d);
		} else
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]
				      selector: _cmd];

		[pool release];
	} @catch (id e) {
1235
1236
1237
1238
1239
1240
1241







1242
1243
1244
1245
1246
1247
1248







1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
	case OF_NUMBER_INTMAX:
	case OF_NUMBER_PTRDIFF:
	case OF_NUMBER_INTPTR:;
		[element addAttributeWithName: @"type"
				  stringValue: @"signed"];
		break;
	case OF_NUMBER_FLOAT:;







		[element addAttributeWithName: @"type"
				  stringValue: @"float"];
		[element setStringValue:
		    [OFString stringWithFormat: @"%a", value.float_]];

		break;
	case OF_NUMBER_DOUBLE:;







		[element addAttributeWithName: @"type"
				  stringValue: @"double"];
		[element setStringValue:
		    [OFString stringWithFormat: @"%la", value.double_]];

		break;
	default:
		@throw [OFInvalidFormatException
		    exceptionWithClass: [self class]];
	}








>
>
>
>
>
>
>



|



>
>
>
>
>
>
>



|







1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
	case OF_NUMBER_INTMAX:
	case OF_NUMBER_PTRDIFF:
	case OF_NUMBER_INTPTR:;
		[element addAttributeWithName: @"type"
				  stringValue: @"signed"];
		break;
	case OF_NUMBER_FLOAT:;
		union {
			float f;
			uint32_t u;
		} f;

		f.f = of_bswap_float_if_le(value.float_);

		[element addAttributeWithName: @"type"
				  stringValue: @"float"];
		[element setStringValue:
		    [OFString stringWithFormat: @"%08" PRIx32, f.u]];

		break;
	case OF_NUMBER_DOUBLE:;
		union {
			double d;
			uint64_t u;
		} d;

		d.d = of_bswap_double_if_le(value.double_);

		[element addAttributeWithName: @"type"
				  stringValue: @"double"];
		[element setStringValue:
		    [OFString stringWithFormat: @"%016" PRIx64, d.u]];

		break;
	default:
		@throw [OFInvalidFormatException
		    exceptionWithClass: [self class]];
	}

Modified src/OFObject+Serialization.m from [012cfeffa7] to [d27599f768].

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

	pool = [[OFAutoreleasePool alloc] init];
	element = [(id)self XMLElementBySerializing];

	root = [OFXMLElement elementWithName: @"serialization"
				   namespace: OF_SERIALIZATION_NS];
	[root addAttributeWithName: @"version"
		       stringValue: @"0"];
	[root addChild: element];

	ret = [@"<?xml version='1.0' encoding='UTF-8'?>\n"
	    stringByAppendingString: [root XMLStringWithIndentation: 2]];

	[ret retain];
	[pool release];
	[ret autorelease];

	return ret;
}
@end







|












42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

	pool = [[OFAutoreleasePool alloc] init];
	element = [(id)self XMLElementBySerializing];

	root = [OFXMLElement elementWithName: @"serialization"
				   namespace: OF_SERIALIZATION_NS];
	[root addAttributeWithName: @"version"
		       stringValue: @"1"];
	[root addChild: element];

	ret = [@"<?xml version='1.0' encoding='UTF-8'?>\n"
	    stringByAppendingString: [root XMLStringWithIndentation: 2]];

	[ret retain];
	[pool release];
	[ret autorelease];

	return ret;
}
@end

Modified src/OFString+Serialization.m from [7cccc18871] to [5a29f34399].

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

	version = [[root attributeForName: @"version"] stringValue];
	if (version == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]
			      selector: _cmd];

	if ([version decimalValue] > 0)
		@throw [OFUnsupportedVersionException
		    exceptionWithClass: [self class]
			       version: version];

	elements = [root elementsForNamespace: OF_SERIALIZATION_NS];

	if ([elements count] != 1)







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

	version = [[root attributeForName: @"version"] stringValue];
	if (version == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]
			      selector: _cmd];

	if ([version decimalValue] != 1)
		@throw [OFUnsupportedVersionException
		    exceptionWithClass: [self class]
			       version: version];

	elements = [root elementsForNamespace: OF_SERIALIZATION_NS];

	if ([elements count] != 1)

Modified src/asprintf.m from [852b8ff01b] to [dcf7698e7b].

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

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#ifdef __MINGW32__
# define vsnprintf _vsnprintf
#endif

int
vasprintf(char **cString, const char *format, va_list arguments)
{
	int length;

	if ((length = vsnprintf(NULL, 0, format, arguments)) < 0)
		return length;







<
<
<
<







16
17
18
19
20
21
22




23
24
25
26
27
28
29

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>





int
vasprintf(char **cString, const char *format, va_list arguments)
{
	int length;

	if ((length = vsnprintf(NULL, 0, format, arguments)) < 0)
		return length;

Modified tests/serialization.xml from [56f53a7b7a] to [b4acfa6af4].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version='1.0' encoding='UTF-8'?>
<serialization xmlns='https://webkeks.org/objfw/serialization' version='0'>
  <OFMutableDictionary>
    <key>
      <OFArray>
        <OFString>Qu&quot;xbar
test</OFString>
        <OFNumber type='signed'>1234</OFNumber>
        <OFNumber type='double'>0x1.34a456d5cfaadp+10</OFNumber>
        <OFMutableString>asd</OFMutableString>
        <OFDate>0x1.34a456d5cfaadp+10</OFDate>
      </OFArray>
    </key>
    <object>
      <OFString>Hello</OFString>
    </object>
    <key>
      <OFString>Blub</OFString>

|






|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version='1.0' encoding='UTF-8'?>
<serialization xmlns='https://webkeks.org/objfw/serialization' version='1'>
  <OFMutableDictionary>
    <key>
      <OFArray>
        <OFString>Qu&quot;xbar
test</OFString>
        <OFNumber type='signed'>1234</OFNumber>
        <OFNumber type='double'>adfa5c6d454a9340</OFNumber>
        <OFMutableString>asd</OFMutableString>
        <OFDate>adfa5c6d454a9340</OFDate>
      </OFArray>
    </key>
    <object>
      <OFString>Hello</OFString>
    </object>
    <key>
      <OFString>Blub</OFString>