ObjFW  Check-in [bceb7ed4c9]

Overview
Comment:Use dot syntax
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: bceb7ed4c93080c0ab9cd2e98876f523f92de56c5a818e7abd64e5f7d22dbefd
User & Date: js on 2019-03-08 00:35:48
Other Links: manifest | tags
Context
2019-03-09
10:48
Several minor fixes check-in: c1e949a8c6 user: js tags: trunk
2019-03-08
00:35
Use dot syntax check-in: bceb7ed4c9 user: js tags: trunk
2019-03-03
12:40
OFHTTPServer: Support for using multiple threads check-in: 607cd05ad7 user: js tags: trunk
Changes

Modified src/OFASN1BitString.m from [12624c872e] to [1e12f722e3].

39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53







-
+








- (instancetype)initWithBitStringValue: (OFData *)bitStringValue
		       bitStringLength: (size_t)bitStringLength
{
	self = [super init];

	@try {
		if ([bitStringValue count] * [bitStringValue itemSize] !=
		if (bitStringValue.count * bitStringValue.itemSize !=
		    bitStringLength / 8)
			@throw [OFInvalidFormatException exception];

		_bitStringValue = [bitStringValue copy];
		_bitStringLength = bitStringLength;
	} @catch (id e) {
		[self release];
64
65
66
67
68
69
70
71

72
73
74
75
76
77

78
79
80
81
82
83
84
64
65
66
67
68
69
70

71
72
73
74
75
76

77
78
79
80
81
82
83
84







-
+





-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFData *bitStringValue;
	size_t bitStringLength;

	@try {
		unsigned char lastByteBits;
		size_t count = [DEREncodedContents count];
		size_t count = DEREncodedContents.count;

		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_BIT_STRING || constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1 || count == 0)
		if (DEREncodedContents.itemSize != 1 || count == 0)
			@throw [OFInvalidFormatException exception];

		lastByteBits =
		    *(unsigned char *)[DEREncodedContents itemAtIndex: 0];

		if (count == 1 && lastByteBits != 0)
			@throw [OFInvalidFormatException exception];
130
131
132
133
134
135
136
137

138
139
140
141
142
143
144
145
130
131
132
133
134
135
136

137
138
139
140
141
142
143
144
145







-
+








		return false;

	return true;
}

- (uint32_t)hash
{
	return [_bitStringValue hash] + (uint32_t)_bitStringLength;
	return _bitStringValue.hash + (uint32_t)_bitStringLength;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<OFASN1BitString: %@ (%zu bits)>",
					   _bitStringValue, _bitStringLength];
}
@end

Modified src/OFASN1Boolean.m from [d63a1fe7aa] to [dc4725221d].

49
50
51
52
53
54
55
56
57


58
59
60
61
62
63
64
49
50
51
52
53
54
55


56
57
58
59
60
61
62
63
64







-
-
+
+







	unsigned char value;

	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_BOOLEAN || constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1 ||
		    [DEREncodedContents count] != 1)
		if (DEREncodedContents.itemSize != 1 ||
		    DEREncodedContents.count != 1)
			@throw [OFInvalidFormatException exception];

		value = *(unsigned char *)[DEREncodedContents itemAtIndex: 0];

		if (value != 0 && value != 0xFF)
			@throw [OFInvalidFormatException exception];
	} @catch (id e) {

Modified src/OFASN1Enumerated.m from [bfa277b108] to [a4cf04c865].

51
52
53
54
55
56
57
58

59
60
61
62

63
64
65
66
67
68
69
51
52
53
54
55
56
57

58
59
60
61

62
63
64
65
66
67
68
69







-
+



-
+







	intmax_t integerValue;

	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_ENUMERATED || constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		integerValue = of_asn1_der_integer_parse(
		    [DEREncodedContents items], [DEREncodedContents count]);
		    DEREncodedContents.items, DEREncodedContents.count);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return [self initWithIntegerValue: integerValue];
}

Modified src/OFASN1IA5String.m from [f26ab2e662] to [ec99f99ba0].

54
55
56
57
58
59
60
61

62
63
64
65

66
67

68
69
70
71
72
73
74
54
55
56
57
58
59
60

61
62
63
64

65
66

67
68
69
70
71
72
73
74







-
+



-
+

-
+







	OFString *IA5StringValue;

	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_IA5_STRING || constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		IA5StringValue = [OFString
		    stringWithCString: [DEREncodedContents items]
		    stringWithCString: DEREncodedContents.items
			     encoding: OF_STRING_ENCODING_ASCII
			       length: [DEREncodedContents count]];
			       length: DEREncodedContents.count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithStringValue: IA5StringValue];

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







-
+



















-
+








	[_IA5StringValue release];

	[super dealloc];
}

- (OFString *)stringValue
{
	return [self IA5StringValue];
	return self.IA5StringValue;
}

- (bool)isEqual: (id)object
{
	OFASN1IA5String *IA5String;

	if (![object isKindOfClass: [OFASN1IA5String class]])
		return false;

	IA5String = object;

	if (![IA5String->_IA5StringValue isEqual: _IA5StringValue])
		return false;

	return true;
}

- (uint32_t)hash
{
	return [_IA5StringValue hash];
	return _IA5StringValue.hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<OFASN1IA5String: %@>",
					   _IA5StringValue];
}
@end

Modified src/OFASN1Integer.m from [508a881579] to [f2823c2ecb].

73
74
75
76
77
78
79
80

81
82
83
84

85
86
87
88
89
90
91
73
74
75
76
77
78
79

80
81
82
83

84
85
86
87
88
89
90
91







-
+



-
+







	intmax_t integerValue;

	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_INTEGER || constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		integerValue = of_asn1_der_integer_parse(
		    [DEREncodedContents items], [DEREncodedContents count]);
		    DEREncodedContents.items, DEREncodedContents.count);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return [self initWithIntegerValue: integerValue];
}

Modified src/OFASN1NumericString.m from [5a551cb41a] to [cdfb24dfd4].

34
35
36
37
38
39
40
41
42


43
44
45
46
47
48
49
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49







-
-
+
+








- (instancetype)initWithStringValue: (OFString *)stringValue
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		const char *cString = [stringValue UTF8String];
		size_t length = [stringValue UTF8StringLength];
		const char *cString = stringValue.UTF8String;
		size_t length = stringValue.UTF8StringLength;

		for (size_t i = 0; i < length; i++)
			if (!of_ascii_isdigit(cString[i]) && cString[i] != ' ')
				@throw [OFInvalidEncodingException exception];

		_numericStringValue = [stringValue copy];

66
67
68
69
70
71
72
73

74
75
76
77

78
79

80
81
82
83
84
85
86
66
67
68
69
70
71
72

73
74
75
76

77
78

79
80
81
82
83
84
85
86







-
+



-
+

-
+








	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_NUMERIC_STRING ||
		    constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		numericStringValue = [OFString
		    stringWithCString: [DEREncodedContents items]
		    stringWithCString: DEREncodedContents.items
			     encoding: OF_STRING_ENCODING_ASCII
			       length: [DEREncodedContents count]];
			       length: DEREncodedContents.count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithStringValue: numericStringValue];

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







-
+



















-
+








	[_numericStringValue release];

	[super dealloc];
}

- (OFString *)stringValue
{
	return [self numericStringValue];
	return self.numericStringValue;
}

- (bool)isEqual: (id)object
{
	OFASN1NumericString *numericString;

	if (![object isKindOfClass: [OFASN1NumericString class]])
		return false;

	numericString = object;

	if (![numericString->_numericStringValue isEqual: _numericStringValue])
		return false;

	return true;
}

- (uint32_t)hash
{
	return [_numericStringValue hash];
	return _numericStringValue.hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<OFASN1NumericString: %@>",
					   _numericStringValue];
}
@end

Modified src/OFASN1ObjectIdentifier.m from [1ad931a1cf] to [531a8feaa4].

39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53







-
+








- (instancetype)initWithSubidentifiers:
    (OFArray OF_GENERIC(OFNumber *) *)subidentifiers
{
	self = [super init];

	@try {
		if ([subidentifiers count] < 1)
		if (subidentifiers.count < 1)
			@throw [OFInvalidFormatException exception];

		switch ([[subidentifiers objectAtIndex: 0] intMaxValue]) {
		case 0:
		case 1:
		case 2:
			break;
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
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







-
-
+
+








-
+

















-
+







		     constructed: (bool)constructed
	      DEREncodedContents: (OFData *)DEREncodedContents
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableArray OF_GENERIC(OFNumber *) *subidentifiers;

	@try {
		const unsigned char *items = [DEREncodedContents items];
		size_t count = [DEREncodedContents count];
		const unsigned char *items = DEREncodedContents.items;
		size_t count = DEREncodedContents.count;
		uintmax_t value = 0;
		uint_fast8_t bits = 0;

		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER ||
		    constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1 || count == 0)
		if (DEREncodedContents.itemSize != 1 || count == 0)
			@throw [OFInvalidArgumentException exception];

		subidentifiers = [OFMutableArray array];

		for (size_t i = 0; i < count; i++) {
			if (bits == 0 && items[i] == 0x80)
				@throw [OFInvalidFormatException exception];

			value = (value << 7) | (items[i] & 0x7F);
			bits += 7;

			if (bits > sizeof(uintmax_t) * 8)
				@throw [OFOutOfRangeException exception];

			if (items[i] & 0x80)
				continue;

			if ([subidentifiers count] == 0) {
			if (subidentifiers.count == 0) {
				if (value < 40)
					[subidentifiers addObject:
					    [OFNumber numberWithUIntMax: 0]];
				else if (value < 80) {
					[subidentifiers addObject:
					    [OFNumber numberWithUIntMax: 1]];
					value -= 40;
164
165
166
167
168
169
170
171

172
173
174
175
176
177
178
179
180
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179
180







-
+









		return false;

	return true;
}

- (uint32_t)hash
{
	return [_subidentifiers hash];
	return _subidentifiers.hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFASN1ObjectIdentifier: %@>",
	    [_subidentifiers componentsJoinedByString: @"."]];
}
@end

Modified src/OFASN1OctetString.m from [45195d9bbf] to [3e4389dd2d].

53
54
55
56
57
58
59
60

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

60
61
62
63
64
65
66
67







-
+







{
	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_OCTET_STRING ||
		    constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return [self initWithOctetStringValue: DEREncodedContents];
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107







-
+








		return false;

	return true;
}

- (uint32_t)hash
{
	return [_octetStringValue hash];
	return _octetStringValue.hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<OFASN1OctetString: %@>",
					   _octetStringValue];
}
@end

Modified src/OFASN1PrintableString.m from [4f4ed13270] to [24350e65d6].

34
35
36
37
38
39
40
41
42


43
44
45
46
47
48
49
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49







-
-
+
+








- (instancetype)initWithStringValue: (OFString *)stringValue
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		const char *cString = [stringValue UTF8String];
		size_t length = [stringValue UTF8StringLength];
		const char *cString = stringValue.UTF8String;
		size_t length = stringValue.UTF8StringLength;

		for (size_t i = 0; i < length; i++) {
			if (of_ascii_isalnum(cString[i]))
				continue;

			switch (cString[i]) {
			case ' ':
85
86
87
88
89
90
91
92

93
94
95
96

97
98

99
100
101
102
103
104
105
85
86
87
88
89
90
91

92
93
94
95

96
97

98
99
100
101
102
103
104
105







-
+



-
+

-
+








	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_PRINTABLE_STRING ||
		    constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		printableStringValue = [OFString
		    stringWithCString: [DEREncodedContents items]
		    stringWithCString: DEREncodedContents.items
			     encoding: OF_STRING_ENCODING_ASCII
			       length: [DEREncodedContents count]];
			       length: DEREncodedContents.count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithStringValue: printableStringValue];

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







-
+




















-
+








	[_printableStringValue release];

	[super dealloc];
}

- (OFString *)stringValue
{
	return [self printableStringValue];
	return self.printableStringValue;
}

- (bool)isEqual: (id)object
{
	OFASN1PrintableString *printableString;

	if (![object isKindOfClass: [OFASN1PrintableString class]])
		return false;

	printableString = object;

	if (![printableString->_printableStringValue isEqual:
	    _printableStringValue])
		return false;

	return true;
}

- (uint32_t)hash
{
	return [_printableStringValue hash];
	return _printableStringValue.hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<OFASN1PrintableString: %@>",
					   _printableStringValue];
}
@end

Modified src/OFASN1UTF8String.m from [2624d9034c] to [5aca8e49db].

54
55
56
57
58
59
60
61

62
63
64
65
66


67
68
69
70
71
72
73
54
55
56
57
58
59
60

61
62
63
64


65
66
67
68
69
70
71
72
73







-
+



-
-
+
+







	OFString *UTF8StringValue;

	@try {
		if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL ||
		    tagNumber != OF_ASN1_TAG_NUMBER_UTF8_STRING || constructed)
			@throw [OFInvalidArgumentException exception];

		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		UTF8StringValue = [OFString
		    stringWithUTF8String: [DEREncodedContents items]
				  length: [DEREncodedContents count]];
		    stringWithUTF8String: DEREncodedContents.items
				  length: DEREncodedContents.count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithStringValue: UTF8StringValue];

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







-
+



















-
+








	[_UTF8StringValue release];

	[super dealloc];
}

- (OFString *)stringValue
{
	return [self UTF8StringValue];
	return self.UTF8StringValue;
}

- (bool)isEqual: (id)object
{
	OFASN1UTF8String *UTF8String;

	if (![object isKindOfClass: [OFASN1UTF8String class]])
		return false;

	UTF8String = object;

	if (![UTF8String->_UTF8StringValue isEqual: _UTF8StringValue])
		return false;

	return true;
}

- (uint32_t)hash
{
	return [_UTF8StringValue hash];
	return _UTF8StringValue.hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<OFASN1UTF8String: %@>",
					   _UTF8StringValue];
}
@end

Modified src/OFASN1Value.m from [021fb1b137] to [826101f4aa].

44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58







-
+







		       tagNumber: (of_asn1_tag_number_t)tagNumber
		     constructed: (bool)constructed
	      DEREncodedContents: (OFData *)DEREncodedContents
{
	self = [super init];

	@try {
		if ([DEREncodedContents itemSize] != 1)
		if (DEREncodedContents.itemSize != 1)
			@throw [OFInvalidFormatException exception];

		_tagClass = tagClass;
		_tagNumber = tagNumber;
		_constructed = constructed;
		_DEREncodedContents = [DEREncodedContents copy];
	} @catch (id e) {
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
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







-
+
















-
+


	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD(hash, _tagClass & 0xFF);
	OF_HASH_ADD(hash, _tagNumber & 0xFF);
	OF_HASH_ADD(hash, _constructed);
	OF_HASH_ADD_HASH(hash, [_DEREncodedContents hash]);
	OF_HASH_ADD_HASH(hash, _DEREncodedContents.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFASN1Value:\n"
	    @"\tTag class = %x\n"
	    @"\tTag number = %x\n"
	    @"\tConstructed = %u\n"
	    @"\tDER-encoded contents = %@\n"
	    @">",
	    _tagClass, _tagNumber, _constructed,
	    [_DEREncodedContents description]];
	    _DEREncodedContents.description];
}
@end

Modified src/OFApplication.m from [529b6d94bf] to [b702abe021].

94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108







-
+







@end

static OFApplication *app = nil;

static void
atexitHandler(void)
{
	id <OFApplicationDelegate> delegate = [app delegate];
	id <OFApplicationDelegate> delegate = app.delegate;

	if ([delegate respondsToSelector: @selector(applicationWillTerminate)])
		[delegate applicationWillTerminate];

	[delegate release];
}

143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
143
144
145
146
147
148
149

150
151
152
153
154
155
156
157







-
+








#ifdef OF_WINDOWS
	__wgetmainargs(&wargc, &wargv, &wenvp, _CRT_glob, &si);
	[app of_setArgumentCount: wargc
	   andWideArgumentValues: wargv];
#endif

	[app setDelegate: delegate];
	app.delegate = delegate;

	[app of_run];

	[delegate release];

	return 0;
}
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
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







-
+




-
+




-
+







+ (OFApplication *)sharedApplication
{
	return app;
}

+ (OFString *)programName
{
	return [app programName];
	return app.programName;
}

+ (OFArray *)arguments
{
	return [app arguments];
	return app.arguments;
}

+ (OFDictionary *)environment
{
	return [app environment];
	return app.environment;
}

+ (void)terminate
{
	[self terminateWithStatus: EXIT_SUCCESS];

	OF_UNREACHABLE
259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
259
260
261
262
263
264
265

266
267
268
269
270
271
272
273







-
+







				fprintf(stderr, "Warning: Invalid environment "
				    "variable: %s\n", [tmp UTF8String]);
				continue;
			}

			key = [tmp substringWithRange: of_range(0, pos)];
			value = [tmp substringWithRange:
			    of_range(pos + 1, [tmp length] - pos - 1)];
			    of_range(pos + 1, tmp.length - pos - 1)];

			[_environment setObject: value
					 forKey: key];

			objc_autoreleasePoolPop(pool);
		}

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







-
+






-
+

















-
-
+
+





-
-
+
+










-
+







	objc_autoreleasePoolPop(pool);

	[runLoop run];
}

- (void)terminate
{
	[[self class] terminate];
	[self.class terminate];

	OF_UNREACHABLE
}

- (void)terminateWithStatus: (int)status
{
	[[self class] terminateWithStatus: status];
	[self.class terminateWithStatus: status];

	OF_UNREACHABLE
}

#ifdef OF_HAVE_SANDBOX
- (void)activateSandbox: (OFSandbox *)sandbox
{
# ifdef OF_HAVE_PLEDGE
	void *pool = objc_autoreleasePoolPush();
	of_string_encoding_t encoding = [OFLocale encoding];
	OFArray OF_GENERIC(of_sandbox_unveil_path_t) *unveiledPaths;
	size_t unveiledPathsCount;
	const char *promises;

	if (_activeSandbox != nil && sandbox != _activeSandbox)
		@throw [OFInvalidArgumentException exception];

	unveiledPaths = [sandbox unveiledPaths];
	unveiledPathsCount = [unveiledPaths count];
	unveiledPaths = sandbox.unveiledPaths;
	unveiledPathsCount = unveiledPaths.count;

	for (size_t i = sandbox->_unveiledPathsIndex;
	    i < unveiledPathsCount; i++) {
		of_sandbox_unveil_path_t unveiledPath =
		    [unveiledPaths objectAtIndex: i];
		OFString *path = [unveiledPath firstObject];
		OFString *permissions = [unveiledPath secondObject];
		OFString *path = unveiledPath.firstObject;
		OFString *permissions = unveiledPath.secondObject;

		if (path == nil || permissions == nil)
			@throw [OFInvalidArgumentException exception];

		unveil([path cStringWithEncoding: encoding],
		    [permissions cStringWithEncoding: encoding]);
	}

	sandbox->_unveiledPathsIndex = unveiledPathsCount;

	promises = [[sandbox pledgeString] cStringWithEncoding: encoding];
	promises = [sandbox.pledgeString cStringWithEncoding: encoding];

	if (pledge(promises, NULL) != 0)
		@throw [OFSandboxActivationFailedException
		    exceptionWithSandbox: sandbox
				   errNo: errno];

	objc_autoreleasePoolPop(pool);
640
641
642
643
644
645
646
647

648
649
650

651
652
653
654
655
656
657
640
641
642
643
644
645
646

647
648
649

650
651
652
653
654
655
656
657







-
+


-
+







# ifdef OF_HAVE_PLEDGE
	void *pool = objc_autoreleasePoolPush();
	const char *promises;

	if (_activeExecSandbox != nil && sandbox != _activeExecSandbox)
		@throw [OFInvalidArgumentException exception];

	if ([[sandbox unveiledPaths] count] != 0)
	if (sandbox.unveiledPaths.count != 0)
		@throw [OFInvalidArgumentException exception];

	promises = [[sandbox pledgeString]
	promises = [sandbox.pledgeString
	    cStringWithEncoding: [OFLocale encoding]];

	if (pledge(NULL, promises) != 0)
		@throw [OFSandboxActivationFailedException
		    exceptionWithSandbox: sandbox
				   errNo: errno];

Modified src/OFArray.m from [d06dd3fbb6] to [58353278e7].

240
241
242
243
244
245
246
247

248
249

250
251
252
253
254
255
256
240
241
242
243
244
245
246

247
248

249
250
251
252
253
254
255
256







-
+

-
+







- (id const *)objects
{
	OFObject *container;
	size_t count;
	id *buffer;

	container = [[[OFObject alloc] init] autorelease];
	count = [self count];
	count = self.count;
	buffer = [container allocMemoryWithSize: sizeof(*buffer)
					  count: [self count]];
					  count: count];

	[self getObjects: buffer
		 inRange: of_range(0, count)];

	return buffer;
}

277
278
279
280
281
282
283
284

285
286
287
288
289
290
291
292

293
294
295
296
297
298
299
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299







-
+







-
+







- (id)valueForKey: (OFString *)key
{
	id ret;

	if ([key hasPrefix: @"@"]) {
		void *pool = objc_autoreleasePoolPush();

		key = [key substringWithRange: of_range(1, [key length] - 1)];
		key = [key substringWithRange: of_range(1, key.length - 1)];
		ret = [[super valueForKey: key] retain];

		objc_autoreleasePoolPop(pool);

		return [ret autorelease];
	}

	ret = [OFMutableArray arrayWithCapacity: [self count]];
	ret = [OFMutableArray arrayWithCapacity: self.count];

	for (id object in self) {
		id value = [object valueForKey: key];

		if (value == nil)
			value = [OFNull null];

307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
307
308
309
310
311
312
313

314
315
316
317
318
319
320
321







-
+








- (void)setValue: (id)value
	  forKey: (OFString *)key
{
	if ([key hasPrefix: @"@"]) {
		void *pool = objc_autoreleasePoolPush();

		key = [key substringWithRange: of_range(1, [key length] - 1)];
		key = [key substringWithRange: of_range(1, key.length - 1)];
		[super setValue: value
			 forKey: key];

		objc_autoreleasePoolPop(pool);
		return;
	}

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







-
+







-
+













-
+







- (bool)containsObjectIdenticalTo: (id)object
{
	return ([self indexOfObjectIdenticalTo: object] != OF_NOT_FOUND);
}

- (id)firstObject
{
	if ([self count] > 0)
	if (self.count > 0)
		return [self objectAtIndex: 0];

	return nil;
}

- (id)lastObject
{
	size_t count = [self count];
	size_t count = self.count;

	if (count > 0)
		return [self objectAtIndex: count - 1];

	return nil;
}

- (OFArray *)objectsInRange: (of_range_t)range
{
	OFArray *ret;
	id *buffer;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length < [self count])
	    range.location + range.length < self.count)
		@throw [OFOutOfRangeException exception];

	if (![self isKindOfClass: [OFMutableArray class]])
		return [OFArray_subarray arrayWithArray: self
						  range: range];

	buffer = [self allocMemoryWithSize: sizeof(*buffer)
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
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







-
+


-
+




















-
-
+
+







			       options: (int)options
{
	OFMutableString *ret;

	if (separator == nil)
		@throw [OFInvalidArgumentException exception];

	if ([self count] == 0)
	if (self.count == 0)
		return @"";

	if ([self count] == 1) {
	if (self.count == 1) {
		OFString *component =
		    [[self firstObject] performSelector: selector];

		if (component == nil)
			@throw [OFInvalidArgumentException exception];

		return component;
	}

	ret = [OFMutableString string];

	if (options & OF_ARRAY_SKIP_EMPTY) {
		for (id object in self) {
			void *pool = objc_autoreleasePoolPush();
			OFString *component =
			    [object performSelector: selector];

			if (component == nil)
				@throw [OFInvalidArgumentException exception];

			if ([component length] > 0) {
				if ([ret length] > 0)
			if (component.length > 0) {
				if (ret.length > 0)
					[ret appendString: separator];
				[ret appendString: component];
			}

			objc_autoreleasePoolPop(pool);
		}
	} else {
516
517
518
519
520
521
522
523

524
525

526
527
528
529
530
531
532
516
517
518
519
520
521
522

523
524

525
526
527
528
529
530
531
532







-
+

-
+







		return true;

	if (![object isKindOfClass: [OFArray class]])
		return false;

	otherArray = object;

	count = [self count];
	count = self.count;

	if (count != [otherArray count])
	if (count != otherArray.count)
		return false;

	for (size_t i = 0; i < count; i++)
		if (![[self objectAtIndex: i] isEqual:
		    [otherArray objectAtIndex: i]])
			return false;

548
549
550
551
552
553
554
555

556
557
558
559
560
561
562
548
549
550
551
552
553
554

555
556
557
558
559
560
561
562







-
+







}

- (OFString *)description
{
	void *pool;
	OFMutableString *ret;

	if ([self count] == 0)
	if (self.count == 0)
		return @"()";

	pool = objc_autoreleasePoolPush();
	ret = [[self componentsJoinedByString: @",\n"] mutableCopy];

	@try {
		[ret prependString: @"(\n"];
583
584
585
586
587
588
589
590

591
592
593

594
595
596
597
598
599
600
583
584
585
586
587
588
589

590
591
592

593
594
595
596
597
598
599
600







-
+


-
+







	if ([self isKindOfClass: [OFMutableArray class]])
		element = [OFXMLElement elementWithName: @"OFMutableArray"
					      namespace: OF_SERIALIZATION_NS];
	else
		element = [OFXMLElement elementWithName: @"OFArray"
					      namespace: OF_SERIALIZATION_NS];

	for (id object in self) {
	for (id <OFSerialization> object in self) {
		void *pool2 = objc_autoreleasePoolPush();

		[element addChild: [object XMLElementBySerializing]];
		[element addChild: object.XMLElementBySerializing];

		objc_autoreleasePoolPop(pool2);
	}

	[element retain];

	objc_autoreleasePoolPop(pool);
615
616
617
618
619
620
621
622

623
624
625
626
627
628
629
615
616
617
618
619
620
621

622
623
624
625
626
627
628
629







-
+







}

- (OFString *)of_JSONRepresentationWithOptions: (int)options
					 depth: (size_t)depth
{
	OFMutableString *JSON = [OFMutableString stringWithString: @"["];
	void *pool = objc_autoreleasePoolPush();
	size_t i, count = [self count];
	size_t i, count = self.count;

	if (options & OF_JSON_REPRESENTATION_PRETTY) {
		OFMutableString *indentation = [OFMutableString string];

		for (i = 0; i < depth; i++)
			[indentation appendString: @"\t"];

675
676
677
678
679
680
681
682

683
684
685
686
687
688
689
675
676
677
678
679
680
681

682
683
684
685
686
687
688
689







-
+







- (OFData *)messagePackRepresentation
{
	OFMutableData *data;
	size_t i, count;
	void *pool;

	data = [OFMutableData data];
	count = [self count];
	count = self.count;

	if (count <= 15) {
		uint8_t tmp = 0x90 | ((uint8_t)count & 0xF);
		[data addItem: &tmp];
	} else if (count <= UINT16_MAX) {
		uint8_t type = 0xDC;
		uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)count);
707
708
709
710
711
712
713
714
715


716
717
718
719
720
721
722
707
708
709
710
711
712
713


714
715
716
717
718
719
720
721
722







-
-
+
+







	for (id object in self) {
		void *pool2 = objc_autoreleasePoolPush();
		OFData *child;

		i++;

		child = [object messagePackRepresentation];
		[data addItems: [child items]
			 count: [child count]];
		[data addItems: child.items
			 count: child.count];

		objc_autoreleasePoolPop(pool2);
	}

	assert(i == count);

	[data makeImmutable];
795
796
797
798
799
800
801
802
803


804
805
806
807
808
809
810
795
796
797
798
799
800
801


802
803
804
805
806
807
808
809
810







-
-
+
+







			     count: (int)count
{
	of_range_t range = of_range(state->state, count);

	if (range.length > SIZE_MAX - range.location)
		@throw [OFOutOfRangeException exception];

	if (range.location + range.length > [self count])
		range.length = [self count] - range.location;
	if (range.location + range.length > self.count)
		range.length = self.count - range.location;

	[self getObjects: objects
		 inRange: range];

	if (range.location + range.length > ULONG_MAX)
		@throw [OFOutOfRangeException exception];

871
872
873
874
875
876
877
878

879
880
881
882
883
884
885
871
872
873
874
875
876
877

878
879
880
881
882
883
884
885







-
+







	return ret;
}

#ifdef OF_HAVE_BLOCKS
- (OFArray *)mappedArrayUsingBlock: (of_array_map_block_t)block
{
	OFArray *ret;
	size_t count = [self count];
	size_t count = self.count;
	id *tmp = [self allocMemoryWithSize: sizeof(id)
				      count: count];

	@try {
		[self enumerateObjectsUsingBlock: ^ (id object, size_t idx,
		    bool *stop) {
			tmp[idx] = block(object, idx);
893
894
895
896
897
898
899
900

901
902
903
904
905
906
907
893
894
895
896
897
898
899

900
901
902
903
904
905
906
907







-
+








	return ret;
}

- (OFArray *)filteredArrayUsingBlock: (of_array_filter_block_t)block
{
	OFArray *ret;
	size_t count = [self count];
	size_t count = self.count;
	id *tmp = [self allocMemoryWithSize: sizeof(id)
				      count: count];

	@try {
		__block size_t i = 0;

		[self enumerateObjectsUsingBlock: ^ (id object, size_t idx,
917
918
919
920
921
922
923
924

925
926
927
928
929
930
931
917
918
919
920
921
922
923

924
925
926
927
928
929
930
931







-
+







	}

	return ret;
}

- (id)foldUsingBlock: (of_array_fold_block_t)block
{
	size_t count = [self count];
	size_t count = self.count;
	__block id current;

	if (count == 0)
		return nil;
	if (count == 1)
		return [[[self firstObject] retain] autorelease];

Modified src/OFArray_adjacent.m from [6816050f97] to [8d3e15f3ea].

93
94
95
96
97
98
99
100
101


102
103
104
105
106
107
108
93
94
95
96
97
98
99


100
101
102
103
104
105
106
107
108







-
-
+
+








	self = [super init];

	if (array == nil)
		return self;

	@try {
		objects = [array objects];
		count = [array count];
		objects = array.objects;
		count = array.count;

		_array = [[OFMutableData alloc] initWithItemSize: sizeof(id)
							capacity: count];
	} @catch (id e) {
		[self release];
		@throw e;
	}
162
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
213
214
215
216
217
218
219


220
221
222
223
224
225
226
227
228
229
230
231

232
233
234
235
236
237
238


239
240
241
242
243
244
245
246
247
248
249

250
251
252
253
254
255
256


257
258
259
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274

275
276
277
278
279
280
281
162
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
213
214
215
216
217


218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236


237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254


255
256
257
258
259
260
261
262
263
264
265
266
267
268

269
270
271
272
273

274
275
276
277
278
279
280
281







-
-
-
+
+
+







-
+

















-
+




-
+















-
-
+
+











-
+





-
-
+
+










-
+





-
-
+
+












-
+




-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if ((![[element name] isEqual: @"OFArray"] &&
		    ![[element name] isEqual: @"OFMutableArray"]) ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if ((![element.name isEqual: @"OFArray"] &&
		    ![element.name isEqual: @"OFMutableArray"]) ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		for (OFXMLElement *child in
		    [element elementsForNamespace: OF_SERIALIZATION_NS]) {
			void *pool2 = objc_autoreleasePoolPush();
			id object;

			object = [child objectByDeserializing];
			object = child.objectByDeserializing;
			[_array addItem: &object];
			[object retain];

			objc_autoreleasePoolPop(pool2);
		}

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

	return self;
}

- (size_t)count
{
	return [_array count];
	return _array.count;
}

- (id const *)objects
{
	return [_array items];
	return _array.items;
}

- (id)objectAtIndex: (size_t)idx
{
	return *((id *)[_array itemAtIndex: idx]);
}

- (id)objectAtIndexedSubscript: (size_t)idx
{
	return *((id *)[_array itemAtIndex: idx]);
}

- (void)getObjects: (id *)buffer
	   inRange: (of_range_t)range
{
	id *objects = [_array items];
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > count)
		@throw [OFOutOfRangeException exception];

	for (size_t i = 0; i < range.length; i++)
		buffer[i] = objects[range.location + i];
}

- (size_t)indexOfObject: (id)object
{
	id *objects;
	id const *objects;
	size_t count;

	if (object == nil)
		return OF_NOT_FOUND;

	objects = [_array items];
	count = [_array count];
	objects = _array.items;
	count = _array.count;

	for (size_t i = 0; i < count; i++)
		if ([objects[i] isEqual: object])
			return i;

	return OF_NOT_FOUND;
}

- (size_t)indexOfObjectIdenticalTo: (id)object
{
	id *objects;
	id const *objects;
	size_t count;

	if (object == nil)
		return OF_NOT_FOUND;

	objects = [_array items];
	count = [_array count];
	objects = _array.items;
	count = _array.count;

	for (size_t i = 0; i < count; i++)
		if (objects[i] == object)
			return i;

	return OF_NOT_FOUND;
}


- (OFArray *)objectsInRange: (of_range_t)range
{
	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > [_array count])
	    range.location + range.length > _array.count)
		@throw [OFOutOfRangeException exception];

	if ([self isKindOfClass: [OFMutableArray class]])
		return [OFArray
		    arrayWithObjects: (id *)[_array items] + range.location
		    arrayWithObjects: (id *)_array.items + range.location
			       count: range.length];

	return [OFArray_adjacentSubarray arrayWithArray: self
						  range: range];
}

- (bool)isEqual: (id)object
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
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
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
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







-
+

-
+


-
-
+
+










-
-
+
+
















-
+














-
+








-
-
+
+









-
-
+
+










	if (![object isKindOfClass: [OFArray_adjacent class]] &&
	    ![object isKindOfClass: [OFMutableArray_adjacent class]])
		return [super isEqual: object];

	otherArray = object;

	count = [_array count];
	count = _array.count;

	if (count != [otherArray count])
	if (count != otherArray.count)
		return false;

	objects = [_array items];
	otherObjects = [otherArray objects];
	objects = _array.items;
	otherObjects = otherArray.objects;

	for (size_t i = 0; i < count; i++)
		if (![objects[i] isEqual: otherObjects[i]])
			return false;

	return true;
}

- (uint32_t)hash
{
	id *objects = [_array items];
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;
	uint32_t hash;

	OF_HASH_INIT(hash);

	for (size_t i = 0; i < count; i++)
		OF_HASH_ADD_HASH(hash, [objects[i] hash]);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
			   objects: (id *)objects
			     count: (int)count_
{
	size_t count = [_array count];
	size_t count = _array.count;

	if (count > INT_MAX)
		/*
		 * Use the implementation from OFArray, which is slower, but can
		 * enumerate in chunks.
		 */
		return [super countByEnumeratingWithState: state
						  objects: objects
						    count: count_];

	if (state->state >= count)
		return 0;

	state->state = (unsigned long)count;
	state->itemsPtr = [_array items];
	state->itemsPtr = _array.items;
	state->mutationsPtr = (unsigned long *)self;

	return (int)count;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
{
	id *objects = [_array items];
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;
	bool stop = false;

	for (size_t i = 0; i < count && !stop; i++)
		block(objects[i], i, &stop);
}
#endif

- (void)dealloc
{
	id *objects = [_array items];
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;

	for (size_t i = 0; i < count; i++)
		[objects[i] release];

	[_array release];

	[super dealloc];
}
@end

Modified src/OFArray_adjacentSubarray.m from [3bce39d414] to [71c6741d2d].

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







-
+
















-
+


-
-
+
+











-
+







#import "OFArray_adjacentSubarray.h"
#import "OFArray_adjacent.h"
#import "OFMutableArray_adjacent.h"

@implementation OFArray_adjacentSubarray
- (const id *)objects
{
	return [_array objects] + _range.location;
	return _array.objects + _range.location;
}

- (bool)isEqual: (id)object
{
	OFArray *otherArray;
	id const *objects, *otherObjects;

	if (object == self)
		return true;

	if (![object isKindOfClass: [OFArray_adjacent class]] &&
	    ![object isKindOfClass: [OFMutableArray_adjacent class]])
		return [super isEqual: object];

	otherArray = object;

	if (_range.length != [otherArray count])
	if (_range.length != otherArray.count)
		return false;

	objects = [self objects];
	otherObjects = [otherArray objects];
	objects = self.objects;
	otherObjects = otherArray.objects;

	for (size_t i = 0; i < _range.length; i++)
		if (![objects[i] isEqual: otherObjects[i]])
			return false;

	return true;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
{
	id const *objects = [self objects];
	id const *objects = self.objects;
	bool stop = false;

	for (size_t i = 0; i < _range.length && !stop; i++)
		block(objects[i], i, &stop);
}
#endif
@end

Modified src/OFCharacterSet_bitset.m from [98690aa9bb] to [37fa197eff].

30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
30
31
32
33
34
35
36


37
38
39
40
41
42
43
44
45







-
-
+
+








- (instancetype)initWithCharactersInString: (OFString *)string
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		const of_unichar_t *characters = [string characters];
		size_t length = [string length];
		const of_unichar_t *characters = string.characters;
		size_t length = string.length;

		for (size_t i = 0; i < length; i++) {
			of_unichar_t c = characters[i];

			if (c / 8 >= _size) {
				size_t newSize;

Modified src/OFCondition.m from [7f0b7083ad] to [42e8f34c96].

33
34
35
36
37
38
39
40

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

40
41
42
43
44
45
46
47







-
+







}

- (instancetype)init
{
	self = [super init];

	if (!of_condition_new(&_condition)) {
		Class c = [self class];
		Class c = self.class;
		[self release];
		@throw [OFInitializationFailedException exceptionWithClass: c];
	}

	_conditionInitialized = true;

	return self;
68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82







-
+







{
	return of_condition_timed_wait(&_condition, &_mutex, timeInterval);
}

- (bool)waitUntilDate: (OFDate *)date
{
	return of_condition_timed_wait(&_condition, &_mutex,
	    [date timeIntervalSinceNow]);
	    date.timeIntervalSinceNow);
}

- (void)signal
{
	if (!of_condition_signal(&_condition))
		@throw [OFConditionSignalFailedException
		    exceptionWithCondition: self];

Modified src/OFConstantString.m from [e40123b4c3] to [299aa74c88].

260
261
262
263
264
265
266
267

268
269
270
271
272
273
274

275
276
277
278
279
280
281
282

283
284
285
286
287
288
289
260
261
262
263
264
265
266

267
268
269
270
271
272
273

274
275
276
277
278
279
280
281

282
283
284
285
286
287
288
289







-
+






-
+







-
+







	return [self isEqual: object];
}

- (uint32_t)hash
{
	[self finishInitialization];

	return [self hash];
	return self.hash;
}

- (OFString *)description
{
	[self finishInitialization];

	return [self description];
	return self.description;
}

/* From OFString */
- (const char *)UTF8String
{
	[self finishInitialization];

	return [self UTF8String];
	return self.UTF8String;
}

- (size_t)getCString: (char *)cString_
	   maxLength: (size_t)maxLength
	    encoding: (of_string_encoding_t)encoding
{
	[self finishInitialization];
300
301
302
303
304
305
306
307

308
309
310
311
312
313
314

315
316
317
318
319
320
321
300
301
302
303
304
305
306

307
308
309
310
311
312
313

314
315
316
317
318
319
320
321







-
+






-
+







	return [self cStringWithEncoding: encoding];
}

- (size_t)length
{
	[self finishInitialization];

	return [self length];
	return self.length;
}

- (size_t)UTF8StringLength
{
	[self finishInitialization];

	return [self UTF8StringLength];
	return self.UTF8StringLength;
}

- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding
{
	[self finishInitialization];

	return [self cStringLengthWithEncoding: encoding];
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
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







-
+






-
+






-
+






-
+






-
+






-
+







						    range: range];
}

- (OFString *)uppercaseString
{
	[self finishInitialization];

	return [self uppercaseString];
	return self.uppercaseString;
}

- (OFString *)lowercaseString
{
	[self finishInitialization];

	return [self lowercaseString];
	return self.lowercaseString;
}

- (OFString *)capitalizedString
{
	[self finishInitialization];

	return [self capitalizedString];
	return self.capitalizedString;
}

- (OFString *)stringByDeletingLeadingWhitespaces
{
	[self finishInitialization];

	return [self stringByDeletingLeadingWhitespaces];
	return self.stringByDeletingLeadingWhitespaces;
}

- (OFString *)stringByDeletingTrailingWhitespaces
{
	[self finishInitialization];

	return [self stringByDeletingTrailingWhitespaces];
	return self.stringByDeletingTrailingWhitespaces;
}

- (OFString *)stringByDeletingEnclosingWhitespaces
{
	[self finishInitialization];

	return [self stringByDeletingEnclosingWhitespaces];
	return self.stringByDeletingEnclosingWhitespaces;
}

- (bool)hasPrefix: (OFString *)prefix
{
	[self finishInitialization];

	return [self hasPrefix: prefix];
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
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







-
+






-
+






-
+






-
+






-
+






-
+






-
+






-
+






-
+






-
+













-
+






-
+







						  options: options];
}

- (OFArray *)pathComponents
{
	[self finishInitialization];

	return [self pathComponents];
	return self.pathComponents;
}

- (OFString *)lastPathComponent
{
	[self finishInitialization];

	return [self lastPathComponent];
	return self.lastPathComponent;
}

- (OFString *)stringByDeletingLastPathComponent
{
	[self finishInitialization];

	return [self stringByDeletingLastPathComponent];
	return self.stringByDeletingLastPathComponent;
}

- (intmax_t)decimalValue
{
	[self finishInitialization];

	return [self decimalValue];
	return self.decimalValue;
}

- (uintmax_t)hexadecimalValue
{
	[self finishInitialization];

	return [self hexadecimalValue];
	return self.hexadecimalValue;
}

- (uintmax_t)octalValue
{
	[self finishInitialization];

	return [self octalValue];
	return self.octalValue;
}

- (float)floatValue
{
	[self finishInitialization];

	return [self floatValue];
	return self.floatValue;
}

- (double)doubleValue
{
	[self finishInitialization];

	return [self doubleValue];
	return self.doubleValue;
}

- (const of_unichar_t *)characters
{
	[self finishInitialization];

	return [self characters];
	return self.characters;
}

- (const of_char16_t *)UTF16String
{
	[self finishInitialization];

	return [self UTF16String];
	return self.UTF16String;
}

- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder
{
	[self finishInitialization];

	return [self UTF16StringWithByteOrder: byteOrder];
}

- (size_t)UTF16StringLength
{
	[self finishInitialization];

	return [self UTF16StringLength];
	return self.UTF16StringLength;
}

- (const of_char32_t *)UTF32String
{
	[self finishInitialization];

	return [self UTF32String];
	return self.UTF32String;
}

- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
{
	[self finishInitialization];

	return [self UTF32StringWithByteOrder: byteOrder];
660
661
662
663
664
665
666
667

668
669
670
671
672
673
674

675
676
677
678
679
680
681
660
661
662
663
664
665
666

667
668
669
670
671
672
673

674
675
676
677
678
679
680
681







-
+






-
+







}

#ifdef OF_HAVE_UNICODE_TABLES
- (OFString *)decomposedStringWithCanonicalMapping
{
	[self finishInitialization];

	return [self decomposedStringWithCanonicalMapping];
	return self.decomposedStringWithCanonicalMapping;
}

- (OFString *)decomposedStringWithCompatibilityMapping
{
	[self finishInitialization];

	return [self decomposedStringWithCompatibilityMapping];
	return self.decomposedStringWithCompatibilityMapping;
}
#endif

#ifdef OF_HAVE_FILES
- (void)writeToFile: (OFString *)path
{
	[self finishInitialization];

Modified src/OFCountedSet.m from [beddf34789] to [d7f89e4f31].

137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151







-
+







	OF_UNRECOGNIZED_SELECTOR
}

- (OFString *)description
{
	OFMutableString *ret;
	void *pool;
	size_t i, count = [self count];
	size_t i, count = self.count;

	if (count == 0)
		return @"{()}";

	ret = [OFMutableString stringWithString: @"{(\n"];

	pool = objc_autoreleasePoolPush();
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
202
203
204
205
206
207
208

209
210
211
212
213
214
215
216







-
+







						[self countForObject: object]];

		objectElement = [OFXMLElement
		    elementWithName: @"object"
			  namespace: OF_SERIALIZATION_NS];
		[objectElement addAttributeWithName: @"count"
					stringValue: count];
		[objectElement addChild: [object XMLElementBySerializing]];
		[objectElement addChild: object.XMLElementBySerializing];
		[element addChild: objectElement];

		objc_autoreleasePoolPop(pool2);
	}

	[element retain];

Modified src/OFCountedSet_hashtable.m from [6969402f59] to [73078b5bc4].

68
69
70
71
72
73
74
75
76


77
78
79
80
81
82
83
68
69
70
71
72
73
74


75
76
77
78
79
80
81
82
83







-
-
+
+







}

- (instancetype)initWithArray: (OFArray *)array
{
	self = [self init];

	@try {
		id const *objects = [array objects];
		size_t count = [array count];
		id const *objects = array.objects;
		size_t count = array.count;

		for (size_t i = 0; i < count; i++)
			[self addObject: objects[i]];
	} @catch (id e) {
		[self release];
		@throw e;
	}
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
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







-
-
+
+











-
-
+
+







-
+








-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: @"OFCountedSet"] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: @"OFCountedSet"] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		for (OFXMLElement *objectElement in
		    [element elementsForName: @"object"
				   namespace: OF_SERIALIZATION_NS]) {
			void *pool2 = objc_autoreleasePoolPush();
			OFXMLElement *object;
			OFXMLAttribute *countAttribute;
			intmax_t signedCount;
			uintmax_t count;

			object = [[objectElement elementsForNamespace:
			    OF_SERIALIZATION_NS] firstObject];
			object = [objectElement elementsForNamespace:
			    OF_SERIALIZATION_NS].firstObject;
			countAttribute =
			    [objectElement attributeForName: @"count"];

			if (object == nil || countAttribute == nil)
				@throw [OFInvalidFormatException exception];

			signedCount =
			    [[countAttribute stringValue] decimalValue];
			    countAttribute.stringValue.decimalValue;
			if (signedCount < 0)
			       @throw [OFOutOfRangeException exception];

			count = signedCount;
			if (count > SIZE_MAX || count > UINTPTR_MAX)
				@throw [OFOutOfRangeException exception];

			[_mapTable setObject: (void *)(uintptr_t)count
				      forKey: [object objectByDeserializing]];
				      forKey: object.objectByDeserializing];

			objc_autoreleasePoolPop(pool2);
		}

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

Modified src/OFDNSResolver.m from [2303b7b240] to [b26d10f3a6].

195
196
197
198
199
200
201
202

203
204
205
206
207
208
209
210

211
212
213
214
215
216
217
195
196
197
198
199
200
201

202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217







-
+







-
+







	   recursion: (unsigned int)recursion
	      result: (OFMutableArray *)result;
-    (void)resolver: (OFDNSResolver *)resolver
    didResolveCNAME: (OFString *)CNAME
      answerRecords: (OFDictionary *)answerRecords
   authorityRecords: (OFDictionary *)authorityRecords
  additionalRecords: (OFDictionary *)additionalRecords
	    context: (id)context
	    context: (OFNumber *)context
	  exception: (id)exception;
- (void)done;
-	(void)resolver: (OFDNSResolver *)resolver
  didResolveDomainName: (OFString *)domainName
	 answerRecords: (OFDictionary *)answerRecords
      authorityRecords: (OFDictionary *)authorityRecords
     additionalRecords: (OFDictionary *)additionalRecords
	       context: (id)context
	       context: (OFNumber *)context
	     exception: (id)exception;
@end

@interface OFDNSResolver_ResolveSocketAddressesDelegate: OFObject
    <OFDNSResolverDelegate>
{
@public
288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
303
304


305
306
307
308
309
310
311
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302


303
304
305
306
307
308
309
310
311







-
+







-
-
+
+







		/* Not an IP address -> we can use it if it contains a dot. */
		size_t pos = [domain rangeOfString: @"."].location;

		if (pos == OF_NOT_FOUND)
			return nil;

		return [domain substringWithRange:
		    of_range(pos + 1, [domain length] - pos - 1)];
		    of_range(pos + 1, domain.length - pos - 1)];
	}
}
#endif

static bool
isFQDN(OFString *host, OFDNSResolverSettings *settings)
{
	const char *UTF8String = [host UTF8String];
	size_t length = [host UTF8StringLength];
	const char *UTF8String = host.UTF8String;
	size_t length = host.UTF8StringLength;
	unsigned int dots = 0;

	if ([host hasSuffix: @"."])
		return true;

	for (size_t i = 0; i < length; i++)
		if (UTF8String[i] == '.')
367
368
369
370
371
372
373
374

375
376
377
378
379
380
381
367
368
369
370
371
372
373

374
375
376
377
378
379
380
381







-
+







				/* Pointing to itself?! */
				@throw [OFInvalidServerReplyException
				    exception];

			suffix = parseName(buffer, length, &j,
			    pointerLevel - 1);

			if ([components count] == 0)
			if (components.count == 0)
				return suffix;
			else {
				[components addObject: suffix];
				return [components
				    componentsJoinedByString: @"."];
			}
		}
757
758
759
760
761
762
763
764

765
766
767
768
769
770
771
757
758
759
760
761
762
763

764
765
766
767
768
769
770
771







-
+







		_selector = selector;
		_context = [context retain];

		queryData = [OFMutableData dataWithCapacity: 512];

		/* Header */

		tmp = OF_BSWAP16_IF_LE([ID uInt16Value]);
		tmp = OF_BSWAP16_IF_LE(ID.uInt16Value);
		[queryData addItems: &tmp
			      count: 2];

		/* RD */
		tmp = OF_BSWAP16_IF_LE(1 << 8);
		[queryData addItems: &tmp
			      count: 2];
779
780
781
782
783
784
785
786

787
788
789

790
791
792
793
794

795
796
797
798
799
800
801
779
780
781
782
783
784
785

786
787
788

789
790
791
792
793

794
795
796
797
798
799
800
801







-
+


-
+




-
+







		[queryData increaseCountBy: 6];

		/* Question */

		/* QNAME */
		for (OFString *component in
		    [domainName componentsSeparatedByString: @"."]) {
			size_t length = [component UTF8StringLength];
			size_t length = component.UTF8StringLength;
			uint8_t length8;

			if (length > 63 || [queryData count] + length > 512)
			if (length > 63 || queryData.count + length > 512)
				@throw [OFOutOfRangeException exception];

			length8 = (uint8_t)length;
			[queryData addItem: &length8];
			[queryData addItems: [component UTF8String]
			[queryData addItems: component.UTF8String
				      count: length];
		}

		/* QTYPE */
		tmp = OF_BSWAP16_IF_LE(recordType);
		[queryData addItems: &tmp
			      count: 2];
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
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







-
-
+
+


-
+


-
+

-
+



















-
+







   additionalRecords: (OFDictionary *)additionalRecords
	  recordType: (of_dns_resource_record_type_t)recordType
	   recursion: (unsigned int)recursion
	      result: (OFMutableArray *)result
{
	bool found = false;

	for (OF_KINDOF(OFDNSResourceRecord *) record in records) {
		if ([record recordClass] != OF_DNS_RESOURCE_RECORD_CLASS_IN)
	for (OFDNSResourceRecord *record in records) {
		if (record.recordClass != OF_DNS_RESOURCE_RECORD_CLASS_IN)
			continue;

		if ([record recordType] == recordType) {
		if (record.recordType == recordType) {
			[result addObject: record];
			found = true;
		} else if ([record recordType] ==
		} else if (record.recordType ==
		    OF_DNS_RESOURCE_RECORD_TYPE_CNAME) {
			[self	resolveCNAME: record
			[self	resolveCNAME: (OFCNAMEDNSResourceRecord *)record
			       answerRecords: answerRecords
			   additionalRecords: additionalRecords
				  recordType: recordType
				   recursion: recursion
				      result: result];
			found = true;
		}
	}

	return found;
}

- (void)resolveCNAME: (OFCNAMEDNSResourceRecord *)CNAME
       answerRecords: (OFDictionary *)answerRecords
   additionalRecords: (OFDictionary *)additionalRecords
	  recordType: (of_dns_resource_record_type_t)recordType
	   recursion: (unsigned int)recursion
	      result: (OFMutableArray *)result
{
	OFString *alias = [CNAME alias];
	OFString *alias = CNAME.alias;
	bool found = false;

	if (recursion == 0)
		return;

	if ([self parseRecords: [answerRecords objectForKey: alias]
		 answerRecords: answerRecords
921
922
923
924
925
926
927
928

929
930
931
932
933
934
935
921
922
923
924
925
926
927

928
929
930
931
932
933
934
935







-
+







		    recordType: recordType
		     recursion: recursion - 1
			result: result])
		found = true;

	if (!found) {
		of_run_loop_mode_t runLoopMode =
		    [[OFRunLoop currentRunLoop] currentMode];
		    [OFRunLoop currentRunLoop].currentMode;
		OFNumber *recordTypeNumber =
		    [OFNumber numberWithInt: recordType];

		_expectedResponses++;

		[result addObject:
		    [OFPair pairWithFirstObject: CNAME
951
952
953
954
955
956
957
958

959
960
961
962
963
964
965
966

967
968
969
970
971
972
973
951
952
953
954
955
956
957

958
959
960
961
962
963
964
965

966
967
968
969
970
971
972
973







-
+







-
+







}

-    (void)resolver: (OFDNSResolver *)resolver
    didResolveCNAME: (OFString *)CNAME
      answerRecords: (OFDictionary *)answerRecords
   authorityRecords: (OFDictionary *)authorityRecords
  additionalRecords: (OFDictionary *)additionalRecords
	    context: (id)context
	    context: (OFNumber *)context
	  exception: (id)exception
{
	/*
	 * TODO: Error handling could be improved. Ignore error if there are
	 * responses, otherwise propagate error.
	 */

	of_dns_resource_record_type_t recordType = [context unsignedIntValue];
	of_dns_resource_record_type_t recordType = context.unsignedIntValue;
	bool found = false;
	OFMutableArray *records;
	size_t count;

	OF_ENSURE(resolver == _resolver);

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







-
+















-
+







	if (!found) {
		if (_expectedResponses == 0)
			[self done];

		return;
	}

	count = [_records count];
	count = _records.count;
	for (size_t i = 0; i < count; i++) {
		id object = [_records objectAtIndex: i];

		if (![object isKindOfClass: [OFPair class]])
			continue;

		if (![[[object firstObject] alias] isEqual: CNAME])
			continue;

		if ([[object secondObject] unsignedIntValue] != recordType)
			continue;

		[_records removeObjectAtIndex: i];
		[_records insertObjectsFromArray: records
					 atIndex: i];
		i += [records count] - 1;
		i += records.count - 1;
	}

	if (_expectedResponses == 0)
		[self done];
}

- (void)done
1045
1046
1047
1048
1049
1050
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
1045
1046
1047
1048
1049
1050
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







-
+



















-
+







-
+







		default:
			break;
		}
	}

	[addresses makeImmutable];

	if ([addresses count] == 0)
	if (addresses.count == 0)
		exception = [OFResolveHostFailedException
		    exceptionWithHost: _host
			  recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
			   recordType: 0
				error: OF_DNS_RESOLVER_ERROR_UNKNOWN];

	if ([_delegate respondsToSelector: @selector(
	    resolver:didResolveDomainName:socketAddresses:exception:)])
		[_delegate	resolver: _resolver
		    didResolveDomainName: _domainName
			 socketAddresses: (exception == nil ? addresses : nil)
			       exception: exception];
}

-	(void)resolver: (OFDNSResolver *)resolver
  didResolveDomainName: (OFString *)domainName
	 answerRecords: (OFDictionary *)answerRecords
      authorityRecords: (OFDictionary *)authorityRecords
     additionalRecords: (OFDictionary *)additionalRecords
	       context: (id)context
	       context: (OFNumber *)context
	     exception: (id)exception
{
	/*
	 * TODO: Error handling could be improved. Ignore error if there are
	 * responses, otherwise propagate error.
	 */

	of_dns_resource_record_type_t recordType = [context unsignedIntValue];
	of_dns_resource_record_type_t recordType = context.unsignedIntValue;

	if (_resolver != nil)
		OF_ENSURE(resolver == _resolver);
	else
		_resolver = [resolver retain];

	_expectedResponses--;
1313
1314
1315
1316
1317
1318
1319
1320

1321
1322
1323
1324
1325

1326
1327

1328
1329
1330
1331
1332
1333
1334
1313
1314
1315
1316
1317
1318
1319

1320
1321
1322
1323
1324

1325
1326

1327
1328
1329
1330
1331
1332
1333
1334







-
+




-
+

-
+







		if (pos != OF_NOT_FOUND)
			line = [line substringWithRange: of_range(0, pos)];

		components = [line
		    componentsSeparatedByCharactersInSet: whitespaceCharacterSet
						 options: OF_STRING_SKIP_EMPTY];

		if ([components count] < 2) {
		if (components.count < 2) {
			objc_autoreleasePoolPop(pool2);
			continue;
		}

		address = [components firstObject];
		address = components.firstObject;
		hosts = [components objectsInRange:
		    of_range(1, [components count] - 1)];
		    of_range(1, components.count - 1)];

		for (OFString *host in hosts) {
			addresses = [staticHosts objectForKey: host];

			if (addresses == nil) {
				addresses = [OFMutableArray array];
				[staticHosts setObject: addresses
1386
1387
1388
1389
1390
1391
1392
1393

1394
1395
1396
1397
1398

1399
1400

1401
1402
1403

1404
1405
1406
1407
1408
1409
1410

1411
1412
1413
1414
1415
1416

1417
1418
1419
1420
1421
1422
1423
1386
1387
1388
1389
1390
1391
1392

1393
1394
1395
1396
1397

1398
1399

1400
1401
1402

1403
1404
1405
1406
1407
1408
1409

1410
1411
1412
1413
1414
1415

1416
1417
1418
1419
1420
1421
1422
1423







-
+




-
+

-
+


-
+






-
+





-
+







		if (pos != OF_NOT_FOUND)
			line = [line substringWithRange: of_range(0, pos)];

		components = [line
		    componentsSeparatedByCharactersInSet: whitespaceCharacterSet
						 options: OF_STRING_SKIP_EMPTY];

		if ([components count] < 2) {
		if (components.count < 2) {
			objc_autoreleasePoolPop(pool2);
			continue;
		}

		option = [components firstObject];
		option = components.firstObject;
		arguments = [components objectsInRange:
		    of_range(1, [components count] - 1)];
		    of_range(1, components.count - 1)];

		if ([option isEqual: @"nameserver"]) {
			if ([arguments count] != 1) {
			if (arguments.count != 1) {
				objc_autoreleasePoolPop(pool2);
				continue;
			}

			[nameServers addObject: [arguments firstObject]];
		} else if ([option isEqual: @"domain"]) {
			if ([arguments count] != 1) {
			if (arguments.count != 1) {
				objc_autoreleasePoolPop(pool2);
				continue;
			}

			[_localDomain release];
			_localDomain = [[arguments firstObject] copy];
			_localDomain = [arguments.firstObject copy];
		} else if ([option isEqual: @"search"]) {
			[_searchDomains release];
			_searchDomains = [arguments copy];
		} else if ([option isEqual: @"options"])
			for (OFString *argument in arguments)
				[self of_parseResolvConfOption: argument];

1433
1434
1435
1436
1437
1438
1439
1440

1441
1442
1443

1444
1445
1446

1447
1448

1449
1450
1451

1452
1453

1454
1455
1456

1457
1458

1459
1460
1461
1462
1463
1464
1465
1433
1434
1435
1436
1437
1438
1439

1440
1441
1442

1443
1444
1445

1446
1447

1448
1449
1450

1451
1452

1453
1454
1455

1456
1457

1458
1459
1460
1461
1462
1463
1464
1465







-
+


-
+


-
+

-
+


-
+

-
+


-
+

-
+







}

- (void)of_parseResolvConfOption: (OFString *)option
{
	@try {
		if ([option hasPrefix: @"ndots:"]) {
			option = [option substringWithRange:
			    of_range(6, [option length] - 6)];
			    of_range(6, option.length - 6)];

			_minNumberOfDotsInAbsoluteName =
			    (unsigned int)[option decimalValue];
			    (unsigned int)option.decimalValue;
		} else if ([option hasPrefix: @"timeout:"]) {
			option = [option substringWithRange:
			    of_range(8, [option length] - 8)];
			    of_range(8, option.length - 8)];

			_timeout = [option decimalValue];
			_timeout = option.decimalValue;
		} else if ([option hasPrefix: @"attempts:"]) {
			option = [option substringWithRange:
			    of_range(9, [option length] - 9)];
			    of_range(9, option.length - 9)];

			_maxAttempts = (unsigned int)[option decimalValue];
			_maxAttempts = (unsigned int)option.decimalValue;
		} else if ([option hasPrefix: @"reload-period:"]) {
			option = [option substringWithRange:
			    of_range(14, [option length] - 14)];
			    of_range(14, option.length - 14)];

			_configReloadInterval = [option decimalValue];
			_configReloadInterval = option.decimalValue;
		} else if ([option isEqual: @"tcp"])
			_usesTCP = true;
	} @catch (OFInvalidFormatException *e) {
	}
}
# endif
#endif
1484
1485
1486
1487
1488
1489
1490
1491

1492
1493
1494
1495
1496
1497
1498
1484
1485
1486
1487
1488
1489
1490

1491
1492
1493
1494
1495
1496
1497
1498







-
+







	nameServers = [OFMutableArray array];

	for (iter = &fixedInfo->DnsServerList; iter != NULL; iter = iter->Next)
		[nameServers addObject:
		    [OFString stringWithCString: iter->IpAddress.String
				       encoding: encoding]];

	if ([nameServers count] > 0) {
	if (nameServers.count > 0) {
		[nameServers makeImmutable];
		_nameServers = [nameServers copy];
	}

	if (fixedInfo->DomainName[0] != '\0')
		_localDomain = [[OFString alloc]
		    initWithCString: fixedInfo->DomainName
1528
1529
1530
1531
1532
1533
1534
1535

1536
1537
1538
1539
1540
1541
1542
1528
1529
1530
1531
1532
1533
1534

1535
1536
1537
1538
1539
1540
1541
1542







-
+







			iter = (struct DomainNameServerNode *)
			    iter->dnsn_MinNode.mln_Succ;
		}
	} @finally {
		ReleaseDomainNameServerList(nameServerList);
	}

	if ([nameServers count] > 0) {
	if (nameServers.count > 0) {
		[nameServers makeImmutable];
		_nameServers = [nameServers copy];
	}

	if (GetDefaultDomainName(buffer, sizeof(buffer)))
		_localDomain = [[OFString alloc] initWithCString: buffer
							encoding: encoding];
1575
1576
1577
1578
1579
1580
1581
1582

1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597

1598
1599
1600
1601
1602
1603
1604
1575
1576
1577
1578
1579
1580
1581

1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596

1597
1598
1599
1600
1601
1602
1603
1604







-
+














-
+







			continue;

		[nameServers addObject: [OFString stringWithFormat:
		    @"%u.%u.%u.%u", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
		    (ip >> 8) & 0xFF, ip & 0xFF]];
	}

	if ([nameServers count] > 0) {
	if (nameServers.count > 0) {
		[nameServers makeImmutable];
		_nameServers = [nameServers copy];
	}
}
#endif

- (void)of_reloadSystemConfig
{
	/*
	 * TODO: Rather than reparsing every, check what actually changed
	 * (mtime) and only reset those.
	 */

	if (_lastConfigReload != nil && _configReloadInterval > 0 &&
	    [_lastConfigReload timeIntervalSinceNow] < _configReloadInterval)
	    _lastConfigReload.timeIntervalSinceNow < _configReloadInterval)
		return;

	[_staticHosts release];
	_staticHosts = nil;

	[_nameServers release];
	_nameServers = nil;
1649
1650
1651
1652
1653
1654
1655
1656

1657
1658
1659
1660
1661
1662
1663
1649
1650
1651
1652
1653
1654
1655

1656
1657
1658
1659
1660
1661
1662
1663







-
+







		OFString *searchDomain = [settings->_searchDomains
		    objectAtIndex: searchDomainsIndex];

		domainName = [OFString stringWithFormat: @"%@.%@.",
		    host, searchDomain];
	}

	if ([domainName UTF8StringLength] > 253)
	if (domainName.UTF8StringLength > 253)
		@throw [OFOutOfRangeException exception];

	query = [[[OFDNSResolverQuery alloc]
		  initWithHost: host
		    domainName: domainName
		   recordClass: recordClass
		    recordType: recordType
1804
1805
1806
1807
1808
1809
1810
1811
1812


1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829


1830
1831
1832
1833
1834
1835
1836
1804
1805
1806
1807
1808
1809
1810


1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827


1828
1829
1830
1831
1832
1833
1834
1835
1836







-
-
+
+















-
-
+
+







		if (_IPv6Socket == nil) {
			of_socket_address_t address =
			    of_socket_address_parse_ip(@"::", 0);

			_IPv6Socket = [[OFUDPSocket alloc] init];
			[_IPv6Socket of_bindToAddress: &address
					    extraType: SOCK_DNS];
			[_IPv6Socket setBlocking: false];
			[_IPv6Socket setDelegate: self];
			_IPv6Socket.blocking = false;
			_IPv6Socket.delegate = self;
			[_IPv6Socket asyncReceiveIntoBuffer: _buffer
						     length: BUFFER_LENGTH];
		}

		sock = _IPv6Socket;
		break;
#endif
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
		if (_IPv4Socket == nil) {
			of_socket_address_t address =
			    of_socket_address_parse_ip(@"0.0.0.0", 0);

			_IPv4Socket = [[OFUDPSocket alloc] init];
			[_IPv4Socket of_bindToAddress: &address
					    extraType: SOCK_DNS];
			[_IPv4Socket setBlocking: false];
			[_IPv4Socket setDelegate: self];
			_IPv4Socket.blocking = false;
			_IPv4Socket.delegate = self;
			[_IPv4Socket asyncReceiveIntoBuffer: _buffer
						     length: BUFFER_LENGTH];
		}

		sock = _IPv4Socket;
		break;
	default:
1846
1847
1848
1849
1850
1851
1852
1853

1854
1855
1856

1857
1858
1859
1860
1861
1862
1863
1864

1865
1866
1867
1868
1869
1870
1871
1846
1847
1848
1849
1850
1851
1852

1853
1854
1855

1856
1857
1858
1859
1860
1861
1862
1863

1864
1865
1866
1867
1868
1869
1870
1871







-
+


-
+







-
+







{
	OFResolveHostFailedException *exception;

	if (query == nil)
		return;

	if (query->_nameServersIndex + 1 <
	    [query->_settings->_nameServers count]) {
	    query->_settings->_nameServers.count) {
		query->_nameServersIndex++;
		[self of_sendQuery: query
		       runLoopMode: [[OFRunLoop currentRunLoop] currentMode]];
		       runLoopMode: [OFRunLoop currentRunLoop].currentMode];
		return;
	}

	if (query->_attempt < query->_settings->_maxAttempts) {
		query->_attempt++;
		query->_nameServersIndex = 0;
		[self of_sendQuery: query
		       runLoopMode: [[OFRunLoop currentRunLoop] currentMode]];
		       runLoopMode: [OFRunLoop currentRunLoop].currentMode];
		return;
	}

	query = [[query retain] autorelease];
	[_queries removeObjectForKey: query->_ID];

	/*
1887
1888
1889
1890
1891
1892
1893
1894

1895
1896
1897
1898
1899
1900
1901
1887
1888
1889
1890
1891
1892
1893

1894
1895
1896
1897
1898
1899
1900
1901







-
+







		   recordType: query->_recordType
			error: OF_DNS_RESOLVER_ERROR_TIMEOUT];

	callback(query->_target, query->_selector, self, query->_domainName,
	    nil, nil, nil, query->_context, exception);
}

-	  (bool)socket: (OF_KINDOF(OFUDPSocket *))sock
-	  (bool)socket: (OFUDPSocket *)sock
  didReceiveIntoBuffer: (void *)buffer_
		length: (size_t)length
		sender: (const of_socket_address_t *)sender
	     exception: (id)exception
{
	unsigned char *buffer = buffer_;
	OFDictionary *answerRecords = nil, *authorityRecords = nil;
1930
1931
1932
1933
1934
1935
1936
1937
1938


1939
1940
1941

1942
1943
1944
1945
1946
1947
1948
1930
1931
1932
1933
1934
1935
1936


1937
1938
1939
1940

1941
1942
1943
1944
1945
1946
1947
1948







-
-
+
+


-
+







		of_dns_resolver_error_t error;
		uint16_t numQuestions, numAnswers, numAuthorityRecords;
		uint16_t numAdditionalRecords;

		if (length < 12)
			@throw [OFTruncatedDataException exception];

		if ([query->_queryData itemSize] != 1 ||
		    [query->_queryData count] < 12)
		if (query->_queryData.itemSize != 1 ||
		    query->_queryData.count < 12)
			@throw [OFInvalidArgumentException exception];

		queryDataBuffer = [query->_queryData items];
		queryDataBuffer = query->_queryData.items;

		/* QR */
		if ((buffer[2] & 0x80) == 0)
			@throw [OFInvalidServerReplyException exception];

		/* Opcode */
		if ((buffer[2] & 0x78) != (queryDataBuffer[2] & 0x78))
1960
1961
1962
1963
1964
1965
1966
1967

1968
1969

1970
1971
1972
1973
1974
1975
1976
1960
1961
1962
1963
1964
1965
1966

1967
1968

1969
1970
1971
1972
1973
1974
1975
1976







-
+

-
+







			error = OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT;
			break;
		case 2:
			error = OF_DNS_RESOLVER_ERROR_SERVER_FAILURE;
			break;
		case 3:
			if (query->_searchDomainsIndex + 1 <
			    [query->_settings->_searchDomains count]) {
			    query->_settings->_searchDomains.count) {
				of_run_loop_mode_t runLoopMode =
				    [[OFRunLoop currentRunLoop] currentMode];
				    [OFRunLoop currentRunLoop].currentMode;

				query->_searchDomainsIndex++;

				[self of_resolveHost: query->_host
					 recordClass: query->_recordClass
					  recordType: query->_recordType
					    settings: query->_settings
2125
2126
2127
2128
2129
2130
2131
2132

2133
2134
2135
2136
2137
2138
2139
2125
2126
2127
2128
2129
2130
2131

2132
2133
2134
2135
2136
2137
2138
2139







-
+







				continue;

			[addresses addItem: &address];
		}

		[addresses makeImmutable];

		if ([addresses count] == 0) {
		if (addresses.count == 0) {
			of_dns_resource_record_type_t recordType = 0;

			addresses = nil;

			switch (addressFamily) {
			case OF_SOCKET_ADDRESS_FAMILY_ANY:
				recordType = OF_DNS_RESOURCE_RECORD_TYPE_ALL;

Modified src/OFDNSResourceRecord.m from [46064a3180] to [b77a7c0c09].

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







-
+

















-
+








of_dns_resource_record_class_t of_dns_resource_record_class_parse(
    OFString *string)
{
	void *pool = objc_autoreleasePoolPush();
	of_dns_resource_record_class_t recordClass;

	string = [string uppercaseString];
	string = string.uppercaseString;

	if ([string isEqual: @"IN"])
		recordClass = OF_DNS_RESOURCE_RECORD_CLASS_IN;
	else
		@throw [OFInvalidArgumentException exception];

	objc_autoreleasePoolPop(pool);

	return recordClass;
}

of_dns_resource_record_type_t of_dns_resource_record_type_parse(
    OFString *string)
{
	void *pool = objc_autoreleasePoolPush();
	of_dns_resource_record_type_t recordType;

	string = [string uppercaseString];
	string = string.uppercaseString;

	if ([string isEqual: @"A"])
		recordType = OF_DNS_RESOURCE_RECORD_TYPE_A;
	else if ([string isEqual: @"NS"])
		recordType = OF_DNS_RESOURCE_RECORD_TYPE_NS;
	else if ([string isEqual: @"CNAME"])
		recordType = OF_DNS_RESOURCE_RECORD_TYPE_CNAME;
167
168
169
170
171
172
173
174

175
176
177
178
179
180
181
167
168
169
170
171
172
173

174
175
176
177
178
179
180
181







-
+







	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tType = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass),
	    of_dns_resource_record_type_to_string(_recordType), _TTL];
}
@end

@implementation OFADNSResourceRecord
- (instancetype)initWithName: (OFString *)name
231
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
231
232
233
234
235
236
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264
265







-
+



















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address));

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tAddress = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_socket_address_ip_string(&_address, NULL), _TTL];
}
@end

@implementation OFAAAADNSResourceRecord
- (instancetype)initWithName: (OFString *)name
		 recordClass: (of_dns_resource_record_class_t)recordClass
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
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







-
+



















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address));

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tAddress = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_socket_address_ip_string(&_address, NULL), _TTL];
}
@end

@implementation OFCNAMEDNSResourceRecord
@synthesize alias = _alias;

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

437
438
439
440
441
442
443
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
435

436
437
438
439
440
441
442
443







-
+




-
+















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_alias hash]);
	OF_HASH_ADD_HASH(hash, _alias.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tAlias = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass), _alias, _TTL];
}
@end

@implementation OFHINFODNSResourceRecord
@synthesize CPU = _CPU, OS = _OS;

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







-
+




-
-
+
+
















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_CPU hash]);
	OF_HASH_ADD_HASH(hash, [_OS hash]);
	OF_HASH_ADD_HASH(hash, _CPU.hash);
	OF_HASH_ADD_HASH(hash, _OS.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tCPU = %@\n"
	    @"\tOS = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass), _CPU, _OS,
	    _TTL];
}
@end

@implementation OFMXDNSResourceRecord
@synthesize preference = _preference, mailExchange = _mailExchange;
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
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







-
+






-
+
















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD(hash, _preference >> 8);
	OF_HASH_ADD(hash, _preference);
	OF_HASH_ADD_HASH(hash, [_mailExchange hash]);
	OF_HASH_ADD_HASH(hash, _mailExchange.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tPreference = %" PRIu16 "\n"
	    @"\tMail Exchange = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass), _preference,
	    _mailExchange, _TTL];
}
@end

@implementation OFNSDNSResourceRecord
@synthesize authoritativeHost = _authoritativeHost;
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
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







-
+




-
+















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_authoritativeHost hash]);
	OF_HASH_ADD_HASH(hash, _authoritativeHost.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tAuthoritative Host = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass),
	    _authoritativeHost, _TTL];
}
@end

@implementation OFPTRDNSResourceRecord
@synthesize domainName = _domainName;
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
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







-
+




-
+















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_domainName hash]);
	OF_HASH_ADD_HASH(hash, _domainName.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tDomain Name = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass), _domainName,
	    _TTL];
}
@end

@implementation OFRPDNSResourceRecord
@synthesize mailbox = _mailbox, TXTDomainName = _TXTDomainName;
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
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







-
+




-
-
+
+
















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_mailbox hash]);
	OF_HASH_ADD_HASH(hash, [_TXTDomainName hash]);
	OF_HASH_ADD_HASH(hash, _mailbox.hash);
	OF_HASH_ADD_HASH(hash, _TXTDomainName.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tMailbox = %@\n"
	    @"\tTXT Domain Name = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass), _mailbox,
	    _TXTDomainName, _TTL];
}
@end

@implementation OFSOADNSResourceRecord
@synthesize primaryNameServer = _primaryNameServer;
1043
1044
1045
1046
1047
1048
1049
1050

1051
1052
1053
1054
1055
1056


1057
1058
1059
1060
1061
1062
1063
1043
1044
1045
1046
1047
1048
1049

1050
1051
1052
1053
1054


1055
1056
1057
1058
1059
1060
1061
1062
1063







-
+




-
-
+
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_primaryNameServer hash]);
	OF_HASH_ADD_HASH(hash, [_responsiblePerson hash]);
	OF_HASH_ADD_HASH(hash, _primaryNameServer.hash);
	OF_HASH_ADD_HASH(hash, _responsiblePerson.hash);
	OF_HASH_ADD(hash, _serialNumber >> 24);
	OF_HASH_ADD(hash, _serialNumber >> 16);
	OF_HASH_ADD(hash, _serialNumber >> 8);
	OF_HASH_ADD(hash, _serialNumber);
	OF_HASH_ADD(hash, _refreshInterval >> 24);
	OF_HASH_ADD(hash, _refreshInterval >> 16);
	OF_HASH_ADD(hash, _refreshInterval >> 8);
1091
1092
1093
1094
1095
1096
1097
1098

1099
1100
1101
1102
1103
1104
1105
1091
1092
1093
1094
1095
1096
1097

1098
1099
1100
1101
1102
1103
1104
1105







-
+







	    @"\tSerial Number = %" PRIu32 "\n"
	    @"\tRefresh Interval = %" PRIu32 "\n"
	    @"\tRetry Interval = %" PRIu32 "\n"
	    @"\tExpiration Interval = %" PRIu32 "\n"
	    @"\tMinimum TTL = %" PRIu32 "\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass),
	    _primaryNameServer, _responsiblePerson, _serialNumber,
	    _refreshInterval, _retryInterval, _expirationInterval, _minTTL,
	    _TTL];
}
@end

1183
1184
1185
1186
1187
1188
1189
1190

1191
1192
1193
1194
1195
1196
1197
1198
1199

1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219

1220
1221
1222
1223
1224
1225
1226
1183
1184
1185
1186
1187
1188
1189

1190
1191
1192
1193
1194
1195
1196
1197
1198

1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218

1219
1220
1221
1222
1223
1224
1225
1226







-
+








-
+



















-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD(hash, _priority >> 8);
	OF_HASH_ADD(hash, _priority);
	OF_HASH_ADD(hash, _weight >> 8);
	OF_HASH_ADD(hash, _weight);
	OF_HASH_ADD_HASH(hash, [_target hash]);
	OF_HASH_ADD_HASH(hash, _target.hash);
	OF_HASH_ADD(hash, _port >> 8);
	OF_HASH_ADD(hash, _port);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tPriority = %" PRIu16 "\n"
	    @"\tWeight = %" PRIu16 "\n"
	    @"\tTarget = %@\n"
	    @"\tPort = %" PRIu16 "\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name, _priority, _weight, _target, _port, _TTL];
	    self.className, _name, _priority, _weight, _target, _port, _TTL];
}
@end

@implementation OFTXTDNSResourceRecord
@synthesize textData = _textData;

- (instancetype)initWithName: (OFString *)name
1285
1286
1287
1288
1289
1290
1291
1292

1293
1294
1295
1296
1297

1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313

1314
1315
1316
1317
1285
1286
1287
1288
1289
1290
1291

1292
1293
1294
1295
1296

1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312

1313
1314
1315
1316
1317







-
+




-
+















-
+





- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _recordClass >> 8);
	OF_HASH_ADD(hash, _recordClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, [_textData hash]);
	OF_HASH_ADD_HASH(hash, _textData.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tName = %@\n"
	    @"\tClass = %@\n"
	    @"\tText Data = %@\n"
	    @"\tTTL = %" PRIu32 "\n"
	    @">",
	    [self className], _name,
	    self.className, _name,
	    of_dns_resource_record_class_to_string(_recordClass), _textData,
	    _TTL];
}
@end

Modified src/OFData+ASN1DERValue.m from [1b4c7e0240] to [8ca4fa488c].

46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60







-
+








static size_t parseObject(OFData *self, id *object, size_t depthLimit);

static OFArray *
parseSequence(OFData *contents, size_t depthLimit)
{
	OFMutableArray *ret = [OFMutableArray array];
	size_t count = [contents count];
	size_t count = contents.count;

	if (depthLimit == 0)
		@throw [OFOutOfRangeException exception];

	while (count > 0) {
		id object;
		size_t objectLength;
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87







-
+







	return ret;
}

static OFSet *
parseSet(OFData *contents, size_t depthLimit)
{
	OFMutableSet *ret = [OFMutableSet set];
	size_t count = [contents count];
	size_t count = contents.count;
	OFData *previousObjectData = nil;

	if (depthLimit == 0)
		@throw [OFOutOfRangeException exception];

	while (count > 0) {
		id object;
110
111
112
113
114
115
116
117
118


119
120
121
122
123
124
125
110
111
112
113
114
115
116


117
118
119
120
121
122
123
124
125







-
-
+
+








	return ret;
}

static size_t
parseObject(OFData *self, id *object, size_t depthLimit)
{
	const unsigned char *items = [self items];
	size_t count = [self count];
	const unsigned char *items = self.items;
	size_t count = self.count;
	unsigned char tag;
	size_t contentsLength, bytesConsumed = 0;
	Class valueClass;
	OFData *contents;

	if (count < 2)
		@throw [OFTruncatedDataException exception];
173
174
175
176
177
178
179
180

181
182
183
184
185
186
187
173
174
175
176
177
178
179

180
181
182
183
184
185
186
187







-
+







	case OF_ASN1_TAG_NUMBER_OCTET_STRING:
		valueClass = [OFASN1OctetString class];
		break;
	case OF_ASN1_TAG_NUMBER_NULL:
		if (tag & ASN1_TAG_CONSTRUCTED_MASK)
			@throw [OFInvalidFormatException exception];

		if ([contents count] != 0)
		if (contents.count != 0)
			@throw [OFInvalidFormatException exception];

		*object = [OFNull null];
		return bytesConsumed;
	case OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER:
		valueClass = [OFASN1ObjectIdentifier class];
		break;
232
233
234
235
236
237
238
239

240
241
242

243
244
245
246
247
248
249
250
251
232
233
234
235
236
237
238

239
240
241

242
243
244
245
246
247
248
249
250
251







-
+


-
+









}

- (id)ASN1DERValueWithDepthLimit: (size_t)depthLimit
{
	void *pool = objc_autoreleasePoolPush();
	id object;

	if ([self itemSize] != 1)
	if (self.itemSize != 1)
		@throw [OFInvalidArgumentException exception];

	if (parseObject(self, &object, depthLimit) != [self count])
	if (parseObject(self, &object, depthLimit) != self.count)
		@throw [OFInvalidFormatException exception];

	[object retain];

	objc_autoreleasePoolPop(pool);

	return [object autorelease];
}
@end

Modified src/OFData+CryptoHashing.m from [8a6be30c19] to [0fcbff4bbf].

37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51







-
+







	id <OFCryptoHash> hash = [class cryptoHash];
	size_t digestSize = [class digestSize];
	const unsigned char *digest;
	char cString[digestSize * 2];

	[hash updateWithBuffer: _items
			length: _count * _itemSize];
	digest = [hash digest];
	digest = hash.digest;

	for (size_t i = 0; i < digestSize; i++) {
		uint8_t high, low;

		high = digest[i] >> 4;
		low  = digest[i] & 0x0F;

Modified src/OFData+MessagePackValue.m from [32c546e84a] to [823c91328e].

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







-
+



-
+







-
+










-
-
+
+








	return pos;
}

static OFDate *
createDate(OFData *data)
{
	switch ([data count]) {
	switch (data.count) {
	case 4: {
		uint32_t timestamp;

		memcpy(&timestamp, [data items], 4);
		memcpy(&timestamp, data.items, 4);
		timestamp = OF_BSWAP32_IF_LE(timestamp);

		return [OFDate dateWithTimeIntervalSince1970: timestamp];
	}
	case 8: {
		uint64_t combined;

		memcpy(&combined, [data items], 8);
		memcpy(&combined, data.items, 8);
		combined = OF_BSWAP64_IF_LE(combined);

		return [OFDate dateWithTimeIntervalSince1970:
		    (double)(combined & 0x3FFFFFFFF) +
		    (double)(combined >> 34) / 1000000000];
	}
	case 12: {
		uint32_t nanoseconds;
		int64_t seconds;

		memcpy(&nanoseconds, [data items], 4);
		memcpy(&seconds, (char *)[data items] + 4, 8);
		memcpy(&nanoseconds, data.items, 4);
		memcpy(&seconds, (char *)data.items + 4, 8);

		nanoseconds = OF_BSWAP32_IF_LE(nanoseconds);
		seconds = OF_BSWAP64_IF_LE(seconds);

		return [OFDate dateWithTimeIntervalSince1970:
		    (double)seconds + (double)nanoseconds / 1000000000];
	}
554
555
556
557
558
559
560
561

562
563
564

565
566
567

568
569
570
571
572
573
574
575
576
554
555
556
557
558
559
560

561
562
563

564
565
566

567
568
569
570
571
572
573
574
575
576







-
+


-
+


-
+









{
	return [self messagePackValueWithDepthLimit: 32];
}

- (id)messagePackValueWithDepthLimit: (size_t)depthLimit
{
	void *pool = objc_autoreleasePoolPush();
	size_t count = [self count];
	size_t count = self.count;
	id object;

	if ([self itemSize] != 1)
	if (self.itemSize != 1)
		@throw [OFInvalidArgumentException exception];

	if (parseObject([self items], count, &object, depthLimit) != count)
	if (parseObject(self.items, count, &object, depthLimit) != count)
		@throw [OFInvalidFormatException exception];

	[object retain];

	objc_autoreleasePoolPop(pool);

	return [object autorelease];
}
@end

Modified src/OFData.m from [fa334deef0] to [5a0f1a8428].

185
186
187
188
189
190
191
192
193


194
195
196
197
198
199
200
185
186
187
188
189
190
191


192
193
194
195
196
197
198
199
200







-
-
+
+







{
	char *buffer = NULL;
	uintmax_t size;

	@try {
		OFFile *file;

		size = [[[OFFileManager defaultManager]
		    attributesOfItemAtPath: path] fileSize];
		size = [[OFFileManager defaultManager]
		    attributesOfItemAtPath: path].fileSize;

# if UINTMAX_MAX > SIZE_MAX
		if (size > SIZE_MAX)
			@throw [OFOutOfRangeException exception];
# endif

		if ((buffer = malloc((size_t)size)) == NULL)
249
250
251
252
253
254
255
256

257
258
259
260
261
262
263
249
250
251
252
253
254
255

256
257
258
259
260
261
262
263







-
+








		_itemSize = 1;
		_count = 0;

		pageSize = [OFSystemInfo pageSize];
		buffer = [self allocMemoryWithSize: pageSize];

		while (![stream isAtEndOfStream]) {
		while (!stream.atEndOfStream) {
			size_t length = [stream readIntoBuffer: buffer
							length: pageSize];

			if (SIZE_MAX - _count < length)
				@throw [OFOutOfRangeException exception];

			_items = [self resizeMemory: _items
334
335
336
337
338
339
340
341

342
343
344
345
346
347
348
334
335
336
337
338
339
340

341
342
343
344
345
346
347
348







-
+







	bool mutable = [self isKindOfClass: [OFMutableData class]];

	if (!mutable) {
		[self release];
		self = [OFMutableData alloc];
	}

	self = [(OFMutableData *)self initWithCapacity: [string length] / 3];
	self = [(OFMutableData *)self initWithCapacity: string.length / 3];

	@try {
		if (!of_base64_decode((OFMutableData *)self,
		    [string cStringWithEncoding: OF_STRING_ENCODING_ASCII],
		    [string cStringLengthWithEncoding:
		    OF_STRING_ENCODING_ASCII]))
			@throw [OFInvalidFormatException exception];
359
360
361
362
363
364
365
366
367


368
369
370

371
372
373
374
375
376
377
359
360
361
362
363
364
365


366
367
368
369

370
371
372
373
374
375
376
377







-
-
+
+


-
+








- (instancetype)initWithSerialization: (OFXMLElement *)element
{
	void *pool = objc_autoreleasePoolPush();
	OFString *stringValue;

	@try {
		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		stringValue = [element stringValue];
		stringValue = element.stringValue;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithBase64EncodedString: stringValue];

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







-
+

-
+
















-
+


-
+


-
+







		return true;

	if (![object isKindOfClass: [OFData class]])
		return false;

	data = object;

	if ([data count] != _count || [data itemSize] != _itemSize)
	if (data.count != _count || data.itemSize != _itemSize)
		return false;
	if (memcmp([data items], _items, _count * _itemSize) != 0)
	if (memcmp(data.items, _items, _count * _itemSize) != 0)
		return false;

	return true;
}

- (of_comparison_result_t)compare: (id <OFComparing>)object
{
	OFData *data;
	int comparison;
	size_t count, minCount;

	if (![(id)object isKindOfClass: [OFData class]])
		@throw [OFInvalidArgumentException exception];

	data = (OFData *)object;

	if ([data itemSize] != _itemSize)
	if (data.itemSize != _itemSize)
		@throw [OFInvalidArgumentException exception];

	count = [data count];
	count = data.count;
	minCount = (_count > count ? count : _count);

	if ((comparison = memcmp(_items, [data items],
	if ((comparison = memcmp(_items, data.items,
	    minCount * _itemSize)) == 0) {
		if (_count > count)
			return OF_ORDERED_DESCENDING;
		if (_count < count)
			return OF_ORDERED_ASCENDING;

		return OF_ORDERED_SAME;
562
563
564
565
566
567
568
569

570
571
572

573
574
575
576
577
578

579
580
581
582
583
584
585
562
563
564
565
566
567
568

569
570
571

572
573
574
575
576
577

578
579
580
581
582
583
584
585







-
+


-
+





-
+







	const char *search;
	size_t searchLength;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _count)
		@throw [OFOutOfRangeException exception];

	if (data == nil || [data itemSize] != _itemSize)
	if (data == nil || data.itemSize != _itemSize)
		@throw [OFInvalidArgumentException exception];

	if ((searchLength = [data count]) == 0)
	if ((searchLength = data.count) == 0)
		return of_range(0, 0);

	if (searchLength > range.length)
		return of_range(OF_NOT_FOUND, 0);

	search = [data items];
	search = data.items;

	if (options & OF_DATA_SEARCH_BACKWARDS) {
		for (size_t i = range.length - searchLength;; i--) {
			if (memcmp(_items + i * _itemSize, search,
			    searchLength * _itemSize) == 0)
				return of_range(i, searchLength);

635
636
637
638
639
640
641
642

643
644
645
646
647
648
649
635
636
637
638
639
640
641

642
643
644
645
646
647
648
649







-
+







	OFXMLElement *element;

	if (_itemSize != 1)
		@throw [OFInvalidArgumentException exception];

	pool = objc_autoreleasePoolPush();
	element = [OFXMLElement
	    elementWithName: [self className]
	    elementWithName: self.className
		  namespace: OF_SERIALIZATION_NS
		stringValue: of_base64_encode(_items, _count * _itemSize)];

	[element retain];

	objc_autoreleasePoolPop(pool);

Modified src/OFDate.m from [f76ec7bd46] to [aa9496cc90].

272
273
274
275
276
277
278
279

280
281
282
283
284
285
286


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
272
273
274
275
276
277
278

279
280
281
282
283
284


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







-
+





-
-
+
+

















-
+










-
-
+
+








- (instancetype)initWithDateString: (OFString *)string
			    format: (OFString *)format
{
	self = [super init];

	@try {
		const char *UTF8String = [string UTF8String];
		const char *UTF8String = string.UTF8String;
		struct tm tm = { 0 };
		int16_t tz = 0;

		tm.tm_isdst = -1;

		if (of_strptime(UTF8String, [format UTF8String],
		    &tm, &tz) != UTF8String + [string UTF8StringLength])
		if (of_strptime(UTF8String, format.UTF8String,
		    &tm, &tz) != UTF8String + string.UTF8StringLength)
			@throw [OFInvalidFormatException exception];

		_seconds = tmAndTzToTime(&tm, &tz);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithLocalDateString: (OFString *)string
				 format: (OFString *)format
{
	self = [super init];

	@try {
		const char *UTF8String = [string UTF8String];
		const char *UTF8String = string.UTF8String;
		struct tm tm = { 0 };
		/*
		 * of_strptime() can never set this to INT16_MAX, no matter
		 * what is passed to it, so this is a safe way to figure out if
		 * the date contains a time zone.
		 */
		int16_t tz = INT16_MAX;

		tm.tm_isdst = -1;

		if (of_strptime(UTF8String, [format UTF8String],
		    &tm, &tz) != UTF8String + [string UTF8StringLength])
		if (of_strptime(UTF8String, format.UTF8String,
		    &tm, &tz) != UTF8String + string.UTF8StringLength)
			@throw [OFInvalidFormatException exception];

		if (tz == INT16_MAX) {
#ifndef OF_WINDOWS
			if ((_seconds = mktime(&tm)) == -1)
				@throw [OFInvalidFormatException exception];
#else
341
342
343
344
345
346
347
348
349


350
351
352

353
354
355
356
357
358
359
341
342
343
344
345
346
347


348
349
350
351

352
353
354
355
356
357
358
359







-
-
+
+


-
+







	@try {
		void *pool = objc_autoreleasePoolPush();
		union {
			double d;
			uint64_t u;
		} d;

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

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

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}
431
432
433
434
435
436
437
438

439
440
441
442
443


444
445
446
447
448
449
450
431
432
433
434
435
436
437

438
439
440
441


442
443
444
445
446
447
448
449
450







-
+



-
-
+
+







	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *element;
	union {
		double d;
		uint64_t u;
	} d;

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

	d.d = OF_BSWAP_DOUBLE_IF_LE(_seconds);
	[element setStringValue:
	    [OFString stringWithFormat: @"%016" PRIx64, OF_BSWAP64_IF_LE(d.u)]];
	element.stringValue =
	    [OFString stringWithFormat: @"%016" PRIx64, OF_BSWAP64_IF_LE(d.u)];

	[element retain];

	objc_autoreleasePoolPop(pool);

	return [element autorelease];
}
622
623
624
625
626
627
628
629

630
631
632
633
634
635

636
637
638
639
640
641
642
622
623
624
625
626
627
628

629
630
631
632
633
634

635
636
637
638
639
640
641
642







-
+





-
+







#endif

	pageSize = [OFSystemInfo pageSize];
	buffer = [self allocMemoryWithSize: pageSize];

	@try {
#ifndef OF_WINDOWS
		if (strftime(buffer, pageSize, [format UTF8String], &tm) == 0)
		if (strftime(buffer, pageSize, format.UTF8String, &tm) == 0)
			@throw [OFOutOfRangeException exception];

		ret = [OFString stringWithUTF8String: buffer];
#else
		if (wcsftime(buffer, pageSize / sizeof(wchar_t),
		    [format UTF16String], &tm) == 0)
		    format.UTF16String, &tm) == 0)
			@throw [OFOutOfRangeException exception];

		ret = [OFString stringWithUTF16String: buffer];
#endif
	} @finally {
		[self freeMemory: buffer];
	}
682
683
684
685
686
687
688
689

690
691
692
693
694
695

696
697
698
699
700
701
702
682
683
684
685
686
687
688

689
690
691
692
693
694

695
696
697
698
699
700
701
702







-
+





-
+







#endif

	pageSize = [OFSystemInfo pageSize];
	buffer = [self allocMemoryWithSize: pageSize];

	@try {
#ifndef OF_WINDOWS
		if (strftime(buffer, pageSize, [format UTF8String], &tm) == 0)
		if (strftime(buffer, pageSize, format.UTF8String, &tm) == 0)
			@throw [OFOutOfRangeException exception];

		ret = [OFString stringWithUTF8String: buffer];
#else
		if (wcsftime(buffer, pageSize / sizeof(wchar_t),
		    [format UTF16String], &tm) == 0)
		    format.UTF16String, &tm) == 0)
			@throw [OFOutOfRangeException exception];

		ret = [OFString stringWithUTF16String: buffer];
#endif
	} @finally {
		[self freeMemory: buffer];
	}

Modified src/OFDictionary.m from [01ef213c97] to [f5551c8463].

286
287
288
289
290
291
292
293

294
295

296
297
298
299


300
301
302
303
304
305
306
286
287
288
289
290
291
292

293
294

295
296
297


298
299
300
301
302
303
304
305
306







-
+

-
+


-
-
+
+







- (instancetype)initWithObjects: (OFArray *)objects_
			forKeys: (OFArray *)keys_
{
	id const *objects, *keys;
	size_t count;

	@try {
		count = [objects_ count];
		count = objects_.count;

		if (count != [keys_ count])
		if (count != keys_.count)
			@throw [OFInvalidArgumentException exception];

		objects = [objects_ objects];
		keys = [keys_ objects];
		objects = objects_.objects;
		keys = keys_.objects;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return [self initWithObjects: objects
			     forKeys: keys
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
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







-
+
















-
+








- (id)valueForKey: (OFString *)key
{
	if ([key hasPrefix: @"@"]) {
		void *pool = objc_autoreleasePoolPush();
		id ret;

		key = [key substringWithRange: of_range(1, [key length] - 1)];
		key = [key substringWithRange: of_range(1, key.length - 1)];
		ret = [[super valueForKey: key] retain];

		objc_autoreleasePoolPop(pool);

		return [ret autorelease];
	}

	return [self objectForKey: key];
}

- (void)setValue: (id)value
	  forKey: (OFString *)key
{
	if ([key hasPrefix: @"@"]) {
		void *pool = objc_autoreleasePoolPush();

		key = [key substringWithRange: of_range(1, [key length] - 1)];
		key = [key substringWithRange: of_range(1, key.length - 1)];
		[super setValue: value
			 forKey: key];

		objc_autoreleasePoolPop(pool);
		return;
	}

414
415
416
417
418
419
420
421

422
423
424
425
426
427
428
414
415
416
417
418
419
420

421
422
423
424
425
426
427
428







-
+







		return true;

	if (![object isKindOfClass: [OFDictionary class]])
		return false;

	otherDictionary = object;

	if ([otherDictionary count] != [self count])
	if (otherDictionary.count != self.count)
		return false;

	pool = objc_autoreleasePoolPush();

	keyEnumerator = [self keyEnumerator];
	objectEnumerator = [self objectEnumerator];
	while ((key = [keyEnumerator nextObject]) != nil &&
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
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







-
+











-
+







	objc_autoreleasePoolPop(pool);

	return false;
}

- (OFArray *)allKeys
{
	OFMutableArray *ret = [OFMutableArray arrayWithCapacity: [self count]];
	OFMutableArray *ret = [OFMutableArray arrayWithCapacity: self.count];

	for (id key in self)
		[ret addObject: key];

	[ret makeImmutable];

	return ret;
}

- (OFArray *)allObjects
{
	OFMutableArray *ret = [OFMutableArray arrayWithCapacity: [self count]];
	OFMutableArray *ret = [OFMutableArray arrayWithCapacity: self.count];
	void *pool = objc_autoreleasePoolPush();
	OFEnumerator *enumerator = [self objectEnumerator];
	id object;

	while ((object = [enumerator nextObject]) != nil)
		[ret addObject: object];

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







-
-
+
+














-
+

-
+







}

- (OFString *)description
{
	OFMutableString *ret;
	void *pool;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	id key, object;
	size_t i, count = [self count];
	OFObject *key, *object;
	size_t i, count = self.count;

	if (count == 0)
		return @"{}";

	ret = [OFMutableString stringWithString: @"{\n"];
	pool = objc_autoreleasePoolPush();
	keyEnumerator = [self keyEnumerator];
	objectEnumerator = [self objectEnumerator];

	i = 0;
	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		void *pool2 = objc_autoreleasePoolPush();

		[ret appendString: [key description]];
		[ret appendString: key.description];
		[ret appendString: @" = "];
		[ret appendString: [object description]];
		[ret appendString: object.description];

		if (++i < count)
			[ret appendString: @";\n"];

		objc_autoreleasePoolPop(pool2);
	}
	[ret replaceOccurrencesOfString: @"\n"
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
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







-
+








-
+


-
+







	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	OFEnumerator *keyEnumerator = [self keyEnumerator];
	OFEnumerator *objectEnumerator = [self objectEnumerator];
	OFCharacterSet *allowed = [OFCharacterSet_URLQueryPartAllowed
	    URLQueryPartAllowedCharacterSet];
	bool first = true;
	id key, object;
	OFObject *key, *object;

	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		if OF_UNLIKELY (first)
			first = false;
		else
			[ret appendString: @"&"];

		[ret appendString: [[key description]
		[ret appendString: [key.description
		    stringByURLEncodingWithAllowedCharacters: allowed]];
		[ret appendString: @"="];
		[ret appendString: [[object description]
		[ret appendString: [object.description
		    stringByURLEncodingWithAllowedCharacters: allowed]];
	}

	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

693
694
695
696
697
698
699
700

701
702
703
704
705

706
707
708
709
710
711
712
693
694
695
696
697
698
699

700
701
702
703
704

705
706
707
708
709
710
711
712







-
+




-
+







	       (object = [objectEnumerator nextObject]) != nil) {
		void *pool2 = objc_autoreleasePoolPush();
		OFXMLElement *keyElement, *objectElement;

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

		objectElement = [OFXMLElement
		    elementWithName: @"object"
			  namespace: OF_SERIALIZATION_NS];
		[objectElement addChild: [object XMLElementBySerializing]];
		[objectElement addChild: object.XMLElementBySerializing];

		[element addChild: keyElement];
		[element addChild: objectElement];

		objc_autoreleasePoolPop(pool2);
	}

732
733
734
735
736
737
738
739

740
741
742
743
744
745
746
732
733
734
735
736
737
738

739
740
741
742
743
744
745
746







-
+







- (OFString *)of_JSONRepresentationWithOptions: (int)options
					 depth: (size_t)depth
{
	OFMutableString *JSON = [OFMutableString stringWithString: @"{"];
	void *pool = objc_autoreleasePoolPush();
	OFEnumerator *keyEnumerator = [self keyEnumerator];
	OFEnumerator *objectEnumerator = [self objectEnumerator];
	size_t i, count = [self count];
	size_t i, count = self.count;
	id key, object;

	if (options & OF_JSON_REPRESENTATION_PRETTY) {
		OFMutableString *indentation = [OFMutableString string];

		for (i = 0; i < depth; i++)
			[indentation appendString: @"\t"];
812
813
814
815
816
817
818
819

820
821
822

823
824
825
826
827
828
829
812
813
814
815
816
817
818

819
820
821

822
823
824
825
826
827
828
829







-
+


-
+








- (OFData *)messagePackRepresentation
{
	OFMutableData *data;
	size_t i, count;
	void *pool;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	id key, object;
	id <OFMessagePackRepresentation> key, object;

	data = [OFMutableData data];
	count = [self count];
	count = self.count;

	if (count <= 15) {
		uint8_t tmp = 0x80 | ((uint8_t)count & 0xF);
		[data addItem: &tmp];
	} else if (count <= UINT16_MAX) {
		uint8_t type = 0xDE;
		uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)count);
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
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







-
-
-
+
+
+

-
-
-
+
+
+













	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		void *pool2 = objc_autoreleasePoolPush();
		OFData *child;

		i++;

		child = [key messagePackRepresentation];
		[data addItems: [child items]
			 count: [child count]];
		child = key.messagePackRepresentation;
		[data addItems: child.items
			 count: child.count];

		child = [object messagePackRepresentation];
		[data addItems: [child items]
			 count: [child count]];
		child = object.messagePackRepresentation;
		[data addItems: child.items
			 count: child.count];

		objc_autoreleasePoolPop(pool2);
	}

	assert(i == count);

	[data makeImmutable];

	objc_autoreleasePoolPop(pool);

	return data;
}
@end

Modified src/OFDictionary_hashtable.m from [4b8b632d36] to [59f7a05c14].

118
119
120
121
122
123
124
125

126
127
128
129
130
131
132
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132







-
+







			@throw e;
		}

		return self;
	}

	@try {
		count = [dictionary count];
		count = dictionary.count;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithCapacity: count];

252
253
254
255
256
257
258
259

260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275
276
277




278
279
280
281
282
283


284
285
286
287
288
289
290
252
253
254
255
256
257
258

259
260
261
262
263
264

265
266
267
268
269
270
271
272
273




274
275
276
277
278
279
280
281


282
283
284
285
286
287
288
289
290







-
+





-
+








-
-
-
-
+
+
+
+




-
-
+
+







		OFXMLElement *keyElement, *objectElement;

		keys = [element elementsForName: @"key"
				      namespace: OF_SERIALIZATION_NS];
		objects = [element elementsForName: @"object"
					 namespace: OF_SERIALIZATION_NS];

		if ([keys count] != [objects count])
		if (keys.count != objects.count)
			@throw [OFInvalidFormatException exception];

		_mapTable = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			 objectFunctions: objectFunctions
				capacity: [keys count]];
				capacity: keys.count];

		keyEnumerator = [keys objectEnumerator];
		objectEnumerator = [objects objectEnumerator];
		while ((keyElement = [keyEnumerator nextObject]) != nil &&
		    (objectElement = [objectEnumerator nextObject]) != nil) {
			void *pool2 = objc_autoreleasePoolPush();
			OFXMLElement *key, *object;

			key = [[keyElement elementsForNamespace:
			    OF_SERIALIZATION_NS] firstObject];
			object = [[objectElement elementsForNamespace:
			    OF_SERIALIZATION_NS] firstObject];
			key = [keyElement elementsForNamespace:
			    OF_SERIALIZATION_NS].firstObject;
			object = [objectElement elementsForNamespace:
			    OF_SERIALIZATION_NS].firstObject;

			if (key == nil || object == nil)
				@throw [OFInvalidFormatException exception];

			[_mapTable setObject: [object objectByDeserializing]
				      forKey: [key objectByDeserializing]];
			[_mapTable setObject: object.objectByDeserializing
				      forKey: key.objectByDeserializing];

			objc_autoreleasePoolPop(pool2);
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
304
305
306
307
308
309
310
311

312
313
314
315
316
317
318
304
305
306
307
308
309
310

311
312
313
314
315
316
317
318







-
+







- (id)objectForKey: (id)key
{
	return [_mapTable objectForKey: key];
}

- (size_t)count
{
	return [_mapTable count];
	return _mapTable.count;
}

- (bool)isEqual: (id)object
{
	OFDictionary_hashtable *dictionary;

	if (object == self)
339
340
341
342
343
344
345
346

347
348
349
350
351
352
353
339
340
341
342
343
344
345

346
347
348
349
350
351
352
353







-
+








- (OFArray *)allKeys
{
	OFArray *ret;
	id *keys;
	size_t count;

	count = [_mapTable count];
	count = _mapTable.count;
	keys = [self allocMemoryWithSize: sizeof(*keys)
				   count: count];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMapTableEnumerator *enumerator;
		void **keyPtr;
374
375
376
377
378
379
380
381

382
383
384
385
386
387
388
374
375
376
377
378
379
380

381
382
383
384
385
386
387
388







-
+








- (OFArray *)allObjects
{
	OFArray *ret;
	id *objects;
	size_t count;

	count = [_mapTable count];
	count = _mapTable.count;
	objects = [self allocMemoryWithSize: sizeof(*objects)
				      count: count];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMapTableEnumerator *enumerator;
		void **objectPtr;
444
445
446
447
448
449
450
451

452
453
444
445
446
447
448
449
450

451
452
453







-
+


		    exceptionWithObject: self];
	}
}
#endif

- (uint32_t)hash
{
	return [_mapTable hash];
	return _mapTable.hash;
}
@end

Modified src/OFEnumerator.h from [a15bc1046c] to [3064d9daa6].

83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97







-
+







 */
#define of_fast_enumeration_state_t NSFastEnumerationState
#ifndef NSINTEGER_DEFINED
typedef struct {
	/*! Arbitrary state information for the enumeration */
	unsigned long state;
	/*! Pointer to a C array of objects to return */
	id __unsafe_unretained _Nullable *_Nullable itemsPtr;
	id const __unsafe_unretained _Nullable *_Nullable itemsPtr;
	/*! Arbitrary state information to detect mutations */
	unsigned long *_Nullable mutationsPtr;
	/*! Additional arbitrary state information */
	unsigned long extra[5];
} of_fast_enumeration_state_t;
#endif

Modified src/OFFile.m from [ce755e8542] to [8a440b67d1].

241
242
243
244
245
246
247
248

249
250
251
252
253
254

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
241
242
243
244
245
246
247

248
249
250
251
252
253

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280







-
+





-
+


















-
+







	of_file_handle_t handle;

	@try {
		void *pool = objc_autoreleasePoolPush();
		int flags;

#ifndef OF_AMIGAOS
		if ((flags = parseMode([mode UTF8String])) == -1)
		if ((flags = parseMode(mode.UTF8String)) == -1)
			@throw [OFInvalidArgumentException exception];

		flags |= O_BINARY | O_CLOEXEC;

# if defined(OF_WINDOWS)
		if ((handle = _wopen([path UTF16String], flags,
		if ((handle = _wopen(path.UTF16String, flags,
		    _S_IREAD | _S_IWRITE)) == -1)
# elif defined(OF_HAVE_OFF64_T)
		if ((handle = open64([path cStringWithEncoding:
		    [OFLocale encoding]], flags, 0666)) == -1)
# else
		if ((handle = open([path cStringWithEncoding:
		    [OFLocale encoding]], flags, 0666)) == -1)
# endif
			@throw [OFOpenItemFailedException
			    exceptionWithPath: path
					 mode: mode
					errNo: errno];
#else
		if ((handle = malloc(sizeof(*handle))) == NULL)
			@throw [OFOutOfMemoryException
			    exceptionWithRequestedSize: sizeof(*handle)];

		@try {
			if ((flags = parseMode([mode UTF8String],
			if ((flags = parseMode(mode.UTF8String,
			    &handle->append)) == -1)
				@throw [OFInvalidArgumentException exception];

			if ((handle->handle = Open([path cStringWithEncoding:
			    [OFLocale encoding]], flags)) == 0) {
				int errNo;

354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
354
355
356
357
358
359
360

361
362
363
364
365
366
367
368







-
+







- (instancetype)initWithURL: (OFURL *)URL
		       mode: (OFString *)mode
{
	void *pool = objc_autoreleasePoolPush();
	OFString *fileSystemRepresentation;

	@try {
		fileSystemRepresentation = [URL fileSystemRepresentation];
		fileSystemRepresentation = URL.fileSystemRepresentation;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithPath: fileSystemRepresentation
			     mode: mode];

Modified src/OFFileManager.m from [fd1f20d425] to [a70bd77335].

179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
179
180
181
182
183
184
185

186
187
188
189
190
191
192
193







-
+







}

- (OFURL *)currentDirectoryURL
{
	void *pool = objc_autoreleasePoolPush();
	OFURL *ret;

	ret = [OFURL fileURLWithPath: [self currentDirectoryPath]];
	ret = [OFURL fileURLWithPath: self.currentDirectoryPath];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL
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
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







-
+








-
+

-
+







		 * If we didn't fail because any of the parents is missing,
		 * there is no point in trying to create the parents.
		 */
		if ([e errNo] != ENOENT)
			@throw e;
	}

	components = [[URL URLEncodedPath] componentsSeparatedByString: @"/"];
	components = [URL.URLEncodedPath componentsSeparatedByString: @"/"];

	for (OFString *component in components) {
		if (currentPath != nil)
			currentPath = [currentPath
			    stringByAppendingFormat: @"/%@", component];
		else
			currentPath = component;

		[URL setURLEncodedPath: currentPath];
		URL.URLEncodedPath = currentPath;

		if ([currentPath length] > 0 &&
		if (currentPath.length > 0 &&
		    ![self directoryExistsAtURL: URL])
			[self createDirectoryAtURL: URL];
	}

	objc_autoreleasePoolPop(pool);
}

412
413
414
415
416
417
418
419

420
421
422
423
424
425
426
412
413
414
415
416
417
418

419
420
421
422
423
424
425
426







-
+








- (void)changeCurrentDirectoryPath: (OFString *)path
{
	if (path == nil)
		@throw [OFInvalidArgumentException exception];

#if defined(OF_WINDOWS)
	if (_wchdir([path UTF16String]) != 0)
	if (_wchdir(path.UTF16String) != 0)
		@throw [OFChangeCurrentDirectoryPathFailedException
		    exceptionWithPath: path
				errNo: errno];
#elif defined(OF_AMIGAOS)
	BPTR lock, oldLock;

	if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]],
461
462
463
464
465
466
467
468

469
470
471
472
473
474
475
461
462
463
464
465
466
467

468
469
470
471
472
473
474
475







-
+







#endif
}

- (void)changeCurrentDirectoryURL: (OFURL *)URL
{
	void *pool = objc_autoreleasePoolPush();

	[self changeCurrentDirectoryPath: [URL fileSystemRepresentation]];
	[self changeCurrentDirectoryPath: URL.fileSystemRepresentation];

	objc_autoreleasePoolPop(pool);
}

- (void)copyItemAtPath: (OFString *)source
		toPath: (OFString *)destination
{
510
511
512
513
514
515
516
517

518
519
520

521
522
523
524
525
526
527
510
511
512
513
514
515
516

517
518
519

520
521
522
523
524
525
526
527







-
+


-
+








	@try {
		attributes = [self attributesOfItemAtURL: source];
	} @catch (OFRetrieveItemAttributesFailedException *e) {
		@throw [OFCopyItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: [e errNo]];
				     errNo: e.errNo];
	}

	type = [attributes fileType];
	type = attributes.fileType;

	if ([type isEqual: of_file_type_directory]) {
		OFArray *contents;

		@try {
			[self createDirectoryAtURL: destination];

582
583
584
585
586
587
588
589

590
591
592
593
594
595
596
582
583
584
585
586
587
588

589
590
591
592
593
594
595
596







-
+







			sourceStream = [[OFURLHandler handlerForURL: source]
			    openItemAtURL: source
				     mode: @"r"];
			destinationStream = [[OFURLHandler handlerForURL:
			    destination] openItemAtURL: destination
						  mode: @"w"];

			while (![sourceStream isAtEndOfStream]) {
			while (!sourceStream.atEndOfStream) {
				size_t length;

				length = [sourceStream
				    readIntoBuffer: buffer
					    length: pageSize];
				[destinationStream writeBuffer: buffer
							length: length];
626
627
628
629
630
631
632
633

634
635
636
637
638
639
640
626
627
628
629
630
631
632

633
634
635
636
637
638
639
640







-
+







			[destinationStream close];
			free(buffer);
		}
#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS
	} else if ([type isEqual: of_file_type_symbolic_link]) {
		@try {
			OFString *linkDestination =
			    [attributes fileSymbolicLinkDestination];
			    attributes.fileSymbolicLinkDestination;

			[self createSymbolicLinkAtURL: destination
				  withDestinationPath: linkDestination];
		} @catch (id e) {
			/*
			 * Only convert exceptions to OFCopyItemFailedException
			 * that have an errNo property. This covers all I/O
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
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







-
+


















-
+








-
+







		    exceptionWithURL: source];

	@try {
		if ([URLHandler moveItemAtURL: source
					toURL: destination])
			return;
	} @catch (OFMoveItemFailedException *e) {
		if ([e errNo] != EXDEV)
		if (e.errNo != EXDEV)
			@throw e;
	}

	if ([self fileExistsAtURL: destination])
		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: EEXIST];

	@try {
		[self copyItemAtURL: source
			      toURL: destination];
	} @catch (OFCopyItemFailedException *e) {
		[self removeItemAtURL: destination];

		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: [e errNo]];
				     errNo: e.errNo];
	}

	@try {
		[self removeItemAtURL: source];
	} @catch (OFRemoveItemFailedException *e) {
		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: [e errNo]];
				     errNo: e.errNo];
	}

	objc_autoreleasePoolPop(pool);
}

- (void)removeItemAtURL: (OFURL *)URL
{
751
752
753
754
755
756
757
758

759
760
761
762
763
764
765
751
752
753
754
755
756
757

758
759
760
761
762
763
764
765







-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFURLHandler *URLHandler;

	if (source == nil || destination == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[destination scheme] isEqual: [source scheme]])
	if (![destination.scheme isEqual: source.scheme])
		@throw [OFInvalidArgumentException exception];

	URLHandler = [OFURLHandler handlerForURL: source];

	if (URLHandler == nil)
		@throw [OFUnsupportedProtocolException
		    exceptionWithURL: source];

Modified src/OFGZIPStream.m from [7f75898f5a] to [f365c42bc2].

79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93







-
+







	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	for (;;) {
		uint8_t byte;
		uint32_t CRC32, uncompressedSize;

		if ([_stream isAtEndOfStream]) {
		if (_stream.atEndOfStream) {
			if (_state != OF_GZIP_STREAM_ID1)
				@throw [OFTruncatedDataException exception];

			return 0;
		}

		switch (_state) {
235
236
237
238
239
240
241
242

243
244
245
246
247
248
249
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249







-
+







			_state++;
			break;
		case OF_GZIP_STREAM_DATA:
			if (_inflateStream == nil)
				_inflateStream = [[OFInflateStream alloc]
				    initWithStream: _stream];

			if (![_inflateStream isAtEndOfStream]) {
			if (!_inflateStream.atEndOfStream) {
				size_t bytesRead = [_inflateStream
				    readIntoBuffer: buffer
					    length: length];

				_CRC32 = of_crc32(_CRC32, buffer, bytesRead);
				_uncompressedSize += bytesRead;

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







-
+





-
-
+
+

-
+










}

- (bool)lowlevelIsAtEndOfStream
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return [_stream isAtEndOfStream];
	return _stream.atEndOfStream;
}

- (bool)hasDataInReadBuffer
{
	if (_state == OF_GZIP_STREAM_DATA)
		return ([super hasDataInReadBuffer] ||
		    [_inflateStream hasDataInReadBuffer]);
		return (super.hasDataInReadBuffer ||
		    _inflateStream.hasDataInReadBuffer);

	return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]);
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (void)close
{
	[_stream release];
	_stream = nil;

	[super close];
}
@end

Modified src/OFHMAC.m from [319ce0f0dd] to [61a4776d3d].

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







-
-
+
+


















-
-
+
+







- (void)setKey: (const void *)key
	length: (size_t)length
{
	void *pool = objc_autoreleasePoolPush();
	size_t blockSize = [_hashClass blockSize];
	OFSecureData *outerKeyPad = [OFSecureData dataWithCount: blockSize];
	OFSecureData *innerKeyPad = [OFSecureData dataWithCount: blockSize];
	unsigned char *outerKeyPadItems = [outerKeyPad items];
	unsigned char *innerKeyPadItems = [innerKeyPad items];
	unsigned char *outerKeyPadItems = outerKeyPad.mutableItems;
	unsigned char *innerKeyPadItems = innerKeyPad.mutableItems;

	[_outerHash release];
	[_innerHash release];
	[_outerHashCopy release];
	[_innerHashCopy release];
	_outerHash = _innerHash = _outerHashCopy = _innerHashCopy = nil;

	@try {
		if (length > blockSize) {
			id <OFCryptoHash> hash = [_hashClass cryptoHash];

			[hash updateWithBuffer: key
					length: length];

			length = [_hashClass digestSize];
			if OF_UNLIKELY (length > blockSize)
				length = blockSize;

			memcpy(outerKeyPadItems, [hash digest], length);
			memcpy(innerKeyPadItems, [hash digest], length);
			memcpy(outerKeyPadItems, hash.digest, length);
			memcpy(innerKeyPadItems, hash.digest, length);
		} else {
			memcpy(outerKeyPadItems, key, length);
			memcpy(innerKeyPadItems, key, length);
		}

		memset(outerKeyPadItems + length, 0, blockSize - length);
		memset(innerKeyPadItems + length, 0, blockSize - length);
135
136
137
138
139
140
141
142

143
144

145
146
147
148

149
150
151
152
153
154
155
135
136
137
138
139
140
141

142
143

144
145
146
147

148
149
150
151
152
153
154
155







-
+

-
+



-
+








- (const unsigned char *)digest
{
	if (_outerHash == nil || _innerHash == nil)
		@throw [OFInvalidArgumentException exception];

	if (_calculated)
		return [_outerHash digest];
		return _outerHash.digest;

	[_outerHash updateWithBuffer: [_innerHash digest]
	[_outerHash updateWithBuffer: _innerHash.digest
			      length: [_hashClass digestSize]];
	_calculated = true;

	return [_outerHash digest];
	return _outerHash.digest;
}

- (size_t)digestSize
{
	return [_hashClass digestSize];
}

Modified src/OFHTTPClient.h from [37c93537fa] to [ec1691a772].

70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84







-
+







 * proxy it should use for this connection.
 *
 * @param client The OFHTTPClient that created a socket
 * @param socket The socket created by the OFHTTPClient
 * @param request The request for which the socket was created
 */
-    (void)client: (OFHTTPClient *)client
  didCreateSocket: (OF_KINDOF(OFTCPSocket *))socket
  didCreateSocket: (OFTCPSocket *)socket
	  request: (OFHTTPRequest *)request;

/*!
 * @brief A callback which is called when an OFHTTPClient wants to send the
 *	  body for a request.
 *
 * @param client The OFHTTPClient that wants to send the body

Modified src/OFHTTPClient.m from [281ca703ab] to [fa73320acf].

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
183
184
185
186
187
188
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
183
184
185
186
187
188







-
-
+
+

-
+





-
-
+
+






-
+

-
+



-
+


-
+




-
+



-
+








-
+




-
-
+
+

-
-
+
+


-
+










-
-
+
+







			 redirects: (unsigned int)redirects;
@end

static OFString *
constructRequestString(OFHTTPRequest *request)
{
	void *pool = objc_autoreleasePoolPush();
	of_http_request_method_t method = [request method];
	OFURL *URL = [request URL];
	of_http_request_method_t method = request.method;
	OFURL *URL = request.URL;
	OFString *path;
	OFString *user = [URL user], *password = [URL password];
	OFString *user = URL.user, *password = URL.password;
	OFMutableString *requestString;
	OFMutableDictionary OF_GENERIC(OFString *, OFString *) *headers;
	OFEnumerator OF_GENERIC(OFString *) *keyEnumerator, *objectEnumerator;
	OFString *key, *object;

	if ([URL path] != nil)
		path = [URL URLEncodedPath];
	if (URL.path != nil)
		path = URL.URLEncodedPath;
	else
		path = @"/";

	requestString = [OFMutableString stringWithFormat:
	    @"%s %@", of_http_request_method_to_string(method), path];

	if ([URL query] != nil) {
	if (URL.query != nil) {
		[requestString appendString: @"?"];
		[requestString appendString: [URL URLEncodedQuery]];
		[requestString appendString: URL.URLEncodedQuery];
	}

	[requestString appendString: @" HTTP/"];
	[requestString appendString: [request protocolVersionString]];
	[requestString appendString: request.protocolVersionString];
	[requestString appendString: @"\r\n"];

	headers = [[[request headers] mutableCopy] autorelease];
	headers = [[request.headers mutableCopy] autorelease];
	if (headers == nil)
		headers = [OFMutableDictionary dictionary];

	if ([headers objectForKey: @"Host"] == nil) {
		OFNumber *port = [URL port];
		OFNumber *port = URL.port;

		if (port != nil) {
			OFString *host = [OFString stringWithFormat:
			    @"%@:%@", [URL URLEncodedHost], port];
			    @"%@:%@", URL.URLEncodedHost, port];

			[headers setObject: host
				    forKey: @"Host"];
		} else
			[headers setObject: [URL URLEncodedHost]
				    forKey: @"Host"];
	}

	if (([user length] > 0 || [password length] > 0) &&
	if ((user.length > 0 || password.length > 0) &&
	    [headers objectForKey: @"Authorization"] == nil) {
		OFMutableData *authorizationData = [OFMutableData data];
		OFString *authorization;

		[authorizationData addItems: [user UTF8String]
				      count: [user UTF8StringLength]];
		[authorizationData addItems: user.UTF8String
				      count: user.UTF8StringLength];
		[authorizationData addItem: ":"];
		[authorizationData addItems: [password UTF8String]
				      count: [password UTF8StringLength]];
		[authorizationData addItems: password.UTF8String
				      count: password.UTF8StringLength];

		authorization = [OFString stringWithFormat:
		    @"Basic %@", [authorizationData stringByBase64Encoding]];
		    @"Basic %@", authorizationData.stringByBase64Encoding];

		[headers setObject: authorization
			    forKey: @"Authorization"];
	}

	if ([headers objectForKey: @"User-Agent"] == nil)
		[headers setObject: @"Something using ObjFW "
				    @"<https://heap.zone/objfw>"
			    forKey: @"User-Agent"];

	if ([request protocolVersion].major == 1 &&
	    [request protocolVersion].minor == 0 &&
	if (request.protocolVersion.major == 1 &&
	    request.protocolVersion.minor == 0 &&
	    [headers objectForKey: @"Connection"] == nil)
		[headers setObject: @"keep-alive"
			    forKey: @"Connection"];

	if ([headers objectForKey: @"Content-Length"] != nil &&
	    [headers objectForKey: @"Content-Type"] == nil)
		[headers setObject: @"application/x-www-form-"
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
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
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

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







-
+







-
-
-
+
+
+

















-
+




-
+








-
+















-
+
-



-
+





-
+







	[_client->_delegate client: _client
	      didFailWithException: exception
			   request: _request];
}

- (void)createResponseWithSocketOrThrow: (OFTCPSocket *)sock
{
	OFURL *URL = [_request URL];
	OFURL *URL = _request.URL;
	OFHTTPClientResponse *response;
	OFString *connectionHeader;
	bool keepAlive;
	OFString *location;

	response = [[[OFHTTPClientResponse alloc] initWithSocket: sock]
	    autorelease];
	[response setProtocolVersionString: _version];
	[response setStatusCode: _status];
	[response setHeaders: _serverHeaders];
	response.protocolVersionString = _version;
	response.statusCode = _status;
	response.headers = _serverHeaders;

	connectionHeader = [_serverHeaders objectForKey: @"Connection"];
	if ([_version isEqual: @"1.1"]) {
		if (connectionHeader != nil)
			keepAlive = ([connectionHeader caseInsensitiveCompare:
			    @"close"] != OF_ORDERED_SAME);
		else
			keepAlive = true;
	} else {
		if (connectionHeader != nil)
			keepAlive = ([connectionHeader caseInsensitiveCompare:
			    @"keep-alive"] == OF_ORDERED_SAME);
		else
			keepAlive = false;
	}

	if (keepAlive) {
		[response of_setKeepAlive: true];
		response.of_keepAlive = true;

		_client->_socket = [sock retain];
		_client->_lastURL = [URL copy];
		_client->_lastWasHEAD =
		    ([_request method] == OF_HTTP_REQUEST_METHOD_HEAD);
		    (_request.method == OF_HTTP_REQUEST_METHOD_HEAD);
		_client->_lastResponse = [response retain];
	}

	/* FIXME: Case-insensitive check of redirect's scheme */
	if (_redirects > 0 && (_status == 301 || _status == 302 ||
	    _status == 303 || _status == 307) &&
	    (location = [_serverHeaders objectForKey: @"Location"]) != nil &&
	    (_client->_insecureRedirectsAllowed ||
	    [[URL scheme] isEqual: @"http"] ||
	    [URL.scheme isEqual: @"http"] ||
	    [location hasPrefix: @"https://"])) {
		OFURL *newURL;
		bool follow;

		newURL = [OFURL URLWithString: location
				relativeToURL: URL];

		if ([_client->_delegate respondsToSelector: @selector(client:
		    shouldFollowRedirect:statusCode:request:response:)])
			follow = [_client->_delegate client: _client
				       shouldFollowRedirect: newURL
						 statusCode: _status
						    request: _request
						   response: response];
		else
			follow = defaultShouldFollow(
			follow = defaultShouldFollow(_request.method, _status);
			    [_request method], _status);

		if (follow) {
			OFDictionary OF_GENERIC(OFString *, OFString *)
			    *headers = [_request headers];
			    *headers = _request.headers;
			OFHTTPRequest *newRequest =
			    [[_request copy] autorelease];
			OFMutableDictionary *newHeaders =
			    [[headers mutableCopy] autorelease];

			if (![[newURL host] isEqual: [URL host]])
			if (![newURL.host isEqual: URL.host])
				[newHeaders removeObjectForKey: @"Host"];

			/*
			 * 303 means the request should be converted to a GET
			 * request before redirection. This also means stripping
			 * the entity of the request.
			 */
379
380
381
382
383
384
385
386
387

388
389
390
391


392
393
394
395
396
397
398
378
379
380
381
382
383
384


385
386
387


388
389
390
391
392
393
394
395
396







-
-
+


-
-
+
+







				    (object = [objectEnumerator nextObject]) !=
				    nil)
					if ([key hasPrefix: @"Content-"] ||
					    [key hasPrefix: @"Transfer-"])
						[newHeaders
						    removeObjectForKey: key];

				[newRequest setMethod:
				    OF_HTTP_REQUEST_METHOD_GET];
				newRequest.method = OF_HTTP_REQUEST_METHOD_GET;
			}

			[newRequest setURL: newURL];
			[newRequest setHeaders: newHeaders];
			newRequest.URL = newURL;
			newRequest.headers = newHeaders;

			_client->_inProgress = false;

			[_client asyncPerformRequest: newRequest
					   redirects: _redirects - 1];
			return;
		}
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
485
486
487
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
485







-
+








-
+














-
+









-
+








-
+







	 * end due to a timeout. In this case, we need to reconnect.
	 */
	if (line == nil) {
		[self closeAndReconnect];
		return false;
	}

	if (![line hasPrefix: @"HTTP/"] || [line length] < 9 ||
	if (![line hasPrefix: @"HTTP/"] || line.length < 9 ||
	    [line characterAtIndex: 8] != ' ')
		@throw [OFInvalidServerReplyException exception];

	_version = [[line substringWithRange: of_range(5, 3)] copy];
	if (![_version isEqual: @"1.0"] && ![_version isEqual: @"1.1"])
		@throw [OFUnsupportedVersionException
		    exceptionWithVersion: _version];

	_status = (int)[[line substringWithRange: of_range(9, 3)] decimalValue];
	_status = (int)[line substringWithRange: of_range(9, 3)].decimalValue;

	return true;
}

- (bool)handleServerHeader: (OFString *)line
		    socket: (OFTCPSocket *)sock
{
	OFString *key, *value, *old;
	const char *lineC, *tmp;
	char *keyC;

	if (line == nil)
		@throw [OFInvalidServerReplyException exception];

	if ([line length] == 0) {
	if (line.length == 0) {
		[_serverHeaders makeImmutable];

		if ([_client->_delegate respondsToSelector: @selector(client:
		    didReceiveHeaders:statusCode:request:)])
			[_client->_delegate client: _client
				 didReceiveHeaders: _serverHeaders
					statusCode: _status
					   request: _request];

		[sock setDelegate: nil];
		sock.delegate = nil;

		[self performSelector: @selector(createResponseWithSocket:)
			   withObject: sock
			   afterDelay: 0];

		return false;
	}

	lineC = [line UTF8String];
	lineC = line.UTF8String;

	if ((tmp = strchr(lineC, ':')) == NULL)
		@throw [OFInvalidServerReplyException exception];

	if ((keyC = malloc(tmp - lineC + 1)) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: tmp - lineC + 1];
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
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







-
+




















-
+








-
+




















-
-
+
+



-
+








	[_serverHeaders setObject: value
			   forKey: key];

	return true;
}

- (bool)stream: (OF_KINDOF(OFStream *))sock
- (bool)stream: (OFStream *)sock
   didReadLine: (OFString *)line
     exception: (id)exception
{
	bool ret;

	if (exception != nil) {
		if ([exception isKindOfClass:
		    [OFInvalidEncodingException class]])
			exception = [OFInvalidServerReplyException exception];

		[self raiseException: exception];
		return false;
	}

	@try {
		if (_firstLine) {
			_firstLine = false;
			ret = [self handleFirstLine: line];
		} else
			ret = [self handleServerHeader: line
						socket: sock];
						socket: (OFTCPSocket *)sock];
	} @catch (id e) {
		[self raiseException: e];
		ret = false;
	}

	return ret;
}

- (OFString *)stream: (OF_KINDOF(OFStream *))stream
- (OFString *)stream: (OFStream *)stream
      didWriteString: (OFString *)string
	    encoding: (of_string_encoding_t)encoding
	bytesWritten: (size_t)bytesWritten
	   exception: (id)exception
{
	if (exception != nil) {
		if ([exception isKindOfClass: [OFWriteFailedException class]] &&
		    ([exception errNo] == ECONNRESET ||
		    [exception errNo] == EPIPE)) {
			/* In case a keep-alive connection timed out */
			[self closeAndReconnect];
			return nil;
		}

		[self raiseException: exception];
		return nil;
	}

	_firstLine = true;

	if ([[_request headers] objectForKey: @"Content-Length"] != nil) {
		[stream setDelegate: nil];
	if ([_request.headers objectForKey: @"Content-Length"] != nil) {
		stream.delegate = nil;

		OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc]
		    initWithHandler: self
			     socket: stream] autorelease];
			     socket: (OFTCPSocket *)stream] autorelease];

		if ([_client->_delegate respondsToSelector:
		    @selector(client:wantsRequestBody:request:)])
			[_client->_delegate client: _client
				  wantsRequestBody: requestBody
					   request: _request];
	} else
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
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







-
+




-
+



















-
+



-
-
-
-
-
+
+
+
+
+
-














-
+











-
+






-
+











-
+

-
+

-
-
+
+







		[sock asyncWriteString: constructRequestString(_request)];
	} @catch (id e) {
		[self raiseException: e];
		return;
	}
}

-     (void)socket: (OF_KINDOF(OFTCPSocket *))sock
-     (void)socket: (OFTCPSocket *)sock
  didConnectToHost: (OFString *)host
	      port: (uint16_t)port
	 exception: (id)exception
{
	[(OFTCPSocket *)sock setDelegate: self];
	sock.delegate = self;

	if (exception != nil) {
		[self raiseException: exception];
		return;
	}

	if ([_client->_delegate respondsToSelector:
	    @selector(client:didCreateSocket:request:)])
		[_client->_delegate client: _client
			   didCreateSocket: sock
				   request: _request];

	[self performSelector: @selector(handleSocket:)
		   withObject: sock
		   afterDelay: 0];
}

- (void)start
{
	OFURL *URL = [_request URL];
	OFURL *URL = _request.URL;
	OFTCPSocket *sock;

	/* Can we reuse the last socket? */
	if (_client->_socket != nil && ![_client->_socket isAtEndOfStream] &&
	    [[_client->_lastURL scheme] isEqual: [URL scheme]] &&
	    [[_client->_lastURL host] isEqual: [URL host]] &&
	    [_client->_lastURL port] == [URL port] &&
	    (_client->_lastWasHEAD ||
	if (_client->_socket != nil && !_client->_socket.atEndOfStream &&
	    [_client->_lastURL.scheme isEqual: URL.scheme] &&
	    [_client->_lastURL.host isEqual: URL.host] &&
	    _client->_lastURL.port == URL.port &&
	    (_client->_lastWasHEAD || _client->_lastResponse.atEndOfStream)) {
	    [_client->_lastResponse isAtEndOfStream])) {
		/*
		 * Set _socket to nil, so that in case of an error it won't be
		 * reused. If everything is successful, we set _socket again
		 * at the end.
		 */
		sock = [_client->_socket autorelease];
		_client->_socket = nil;

		[_client->_lastURL release];
		_client->_lastURL = nil;

		[_client->_lastResponse release];
		_client->_lastResponse = nil;

		[sock setDelegate: self];
		sock.delegate = self;

		[self performSelector: @selector(handleSocket:)
			   withObject: sock
			   afterDelay: 0];
	} else
		[self closeAndReconnect];
}

- (void)closeAndReconnect
{
	@try {
		OFURL *URL = [_request URL];
		OFURL *URL = _request.URL;
		OFTCPSocket *sock;
		uint16_t port;
		OFNumber *URLPort;

		[_client close];

		if ([[URL scheme] isEqual: @"https"]) {
		if ([URL.scheme isEqual: @"https"]) {
			if (of_tls_socket_class == Nil)
				@throw [OFUnsupportedProtocolException
				    exceptionWithURL: URL];

			sock = [[[of_tls_socket_class alloc] init] autorelease];
			port = 443;
		} else {
			sock = [OFTCPSocket socket];
			port = 80;
		}

		URLPort = [URL port];
		URLPort = URL.port;
		if (URLPort != nil)
			port = [URLPort uInt16Value];
			port = URLPort.uInt16Value;

		[sock setDelegate: self];
		[sock asyncConnectToHost: [URL host]
		sock.delegate = self;
		[sock asyncConnectToHost: URL.host
				    port: port];
	} @catch (id e) {
		[self raiseException: e];
	}
}
@end

705
706
707
708
709
710
711
712

713
714
715
716
717
718

719
720
721
722
723
724
725
702
703
704
705
706
707
708

709
710
711
712
713
714

715
716
717
718
719
720
721
722







-
+





-
+







		OFDictionary OF_GENERIC(OFString *, OFString *) *headers;
		intmax_t contentLength;
		OFString *contentLengthString;

		_handler = [handler retain];
		_socket = [sock retain];

		headers = [_handler->_request headers];
		headers = _handler->_request.headers;

		contentLengthString = [headers objectForKey: @"Content-Length"];
		if (contentLengthString == nil)
			@throw [OFInvalidArgumentException exception];

		contentLength = [contentLengthString decimalValue];
		contentLength = contentLengthString.decimalValue;
		if (contentLength < 0)
			@throw [OFOutOfRangeException exception];

		_toWrite = contentLength;

		if ([headers objectForKey: @"Transfer-Encoding"] != nil)
			@throw [OFInvalidArgumentException exception];
790
791
792
793
794
795
796
797

798
799
800
801
802
803
804
805
806

807
808
809
810
811
812
813
787
788
789
790
791
792
793

794
795
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810







-
+








-
+







{
	if (_socket == nil)
		return;

	if (_toWrite > 0)
		@throw [OFTruncatedDataException exception];

	[_socket setDelegate: _handler];
	_socket.delegate = _handler;
	[_socket asyncReadLine];

	[_socket release];
	_socket = nil;
}

- (int)fileDescriptorForWriting
{
	return [_socket fileDescriptorForWriting];
	return _socket.fileDescriptorForWriting;
}
@end

@implementation OFHTTPClientResponse
@synthesize of_keepAlive = _keepAlive;

- (instancetype)initWithSocket: (OFTCPSocket *)sock
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
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







-
+









-
+







	[super dealloc];
}

- (void)setHeaders: (OFDictionary *)headers
{
	OFString *contentLength;

	[super setHeaders: headers];
	super.headers = headers;

	_chunked = [[headers objectForKey: @"Transfer-Encoding"]
	    isEqual: @"chunked"];

	contentLength = [headers objectForKey: @"Content-Length"];
	if (contentLength != nil) {
		_hasContentLength = true;

		@try {
			intmax_t toRead = [contentLength decimalValue];
			intmax_t toRead = contentLength.decimalValue;

			if (toRead < 0)
				@throw [OFInvalidServerReplyException
				    exception];

			_toRead = toRead;
		} @catch (OFInvalidFormatException *e) {
862
863
864
865
866
867
868
869

870
871
872
873
874
875
876
859
860
861
862
863
864
865

866
867
868
869
870
871
872
873







-
+







	if (_atEndOfStream)
		return 0;

	if (!_hasContentLength && !_chunked)
		return [_socket readIntoBuffer: buffer
					length: length];

	if ([_socket isAtEndOfStream])
	if (_socket.atEndOfStream)
		@throw [OFTruncatedDataException exception];

	/* Content-Length */
	if (!_chunked) {
		size_t ret;

		if (length > _toRead)
903
904
905
906
907
908
909
910

911
912
913
914
915
916
917
900
901
902
903
904
905
906

907
908
909
910
911
912
913
914







-
+








		length = [_socket readIntoBuffer: buffer
					  length: length];

		_toRead -= length;

		if (_toRead == 0)
			if ([[_socket readLine] length] > 0)
			if ([_socket readLine].length > 0)
				@throw [OFInvalidServerReplyException
				    exception];

		return length;
	} else {
		void *pool = objc_autoreleasePoolPush();
		OFString *line;
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
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







-
+




















-
+








		range = [line rangeOfString: @";"];
		if (range.location != OF_NOT_FOUND)
			line = [line substringWithRange:
			    of_range(0, range.location)];

		@try {
			intmax_t toRead = [line hexadecimalValue];
			intmax_t toRead = line.hexadecimalValue;

			if (toRead < 0)
				@throw [OFOutOfRangeException exception];

			_toRead = toRead;
		} @catch (OFInvalidFormatException *e) {
			@throw [OFInvalidServerReplyException exception];
		}

		if (_toRead == 0) {
			_atEndOfStream = true;

			if (_keepAlive) {
				@try {
					line = [_socket readLine];
				} @catch (OFInvalidEncodingException *e) {
					@throw [OFInvalidServerReplyException
					    exception];
				}

				if ([line length] > 0)
				if (line.length > 0)
					@throw [OFInvalidServerReplyException
					    exception];
			} else {
				[_socket release];
				_socket = nil;
			}
		}
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
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







-
+









-
+




-
+




















-
+

-
+










-
+







	if (_atEndOfStream)
		return true;

	if (_socket == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (!_hasContentLength && !_chunked)
		return [_socket isAtEndOfStream];
		return _socket.atEndOfStream;

	return _atEndOfStream;
}

- (int)fileDescriptorForReading
{
	if (_socket == nil)
		return -1;

	return [_socket fileDescriptorForReading];
	return _socket.fileDescriptorForReading;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] || [_socket hasDataInReadBuffer]);
	return (super.hasDataInReadBuffer || _socket.hasDataInReadBuffer);
}

- (void)close
{
	_atEndOfStream = false;

	[_socket release];
	_socket = nil;

	[super close];
}
@end

@implementation OFHTTPClient_SyncPerformer
- (instancetype)initWithClient: (OFHTTPClient *)client
{
	self = [super init];

	@try {
		_client = [client retain];
		_delegate = [client delegate];
		_delegate = client.delegate;

		[_client setDelegate: self];
		_client.delegate = self;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_client setDelegate: _delegate];
	_client.delegate = _delegate;
	[_client release];

	[super dealloc];
}

- (OFHTTPResponse *)performRequest: (OFHTTPRequest *)request
			 redirects: (unsigned int)redirects
1059
1060
1061
1062
1063
1064
1065
1066

1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
1056
1057
1058
1059
1060
1061
1062

1063
1064
1065
1066
1067
1068

1069
1070
1071
1072
1073
1074
1075
1076







-
+





-
+







	       request: (OFHTTPRequest *)request
{
	/*
	 * Restore the delegate - we're giving up, but not reaching the release
	 * of the autorelease pool that contains us, so resetting it via
	 * -[dealloc] might be too late.
	 */
	[_client setDelegate: _delegate];
	_client.delegate = _delegate;

	@throw exception;
}

-    (void)client: (OFHTTPClient *)client
  didCreateSocket: (OF_KINDOF(OFTCPSocket *))sock
  didCreateSocket: (OFTCPSocket *)sock
	  request: (OFHTTPRequest *)request
{
	if ([_delegate respondsToSelector:
	    @selector(client:didCreateSocket:request:)])
		[_delegate   client: client
		    didCreateSocket: sock
			    request: request];
1113
1114
1115
1116
1117
1118
1119
1120

1121
1122
1123
1124
1125
1126
1127
1110
1111
1112
1113
1114
1115
1116

1117
1118
1119
1120
1121
1122
1123
1124







-
+







	    shouldFollowRedirect:statusCode:request:response:)])
		return [_delegate client: client
		    shouldFollowRedirect: URL
			      statusCode: statusCode
				 request: request
				response: response];
	else
		return defaultShouldFollow([request method], statusCode);
		return defaultShouldFollow(request.method, statusCode);
}
@end

@implementation OFHTTPClient
@synthesize delegate = _delegate;
@synthesize insecureRedirectsAllowed = _insecureRedirectsAllowed;

1166
1167
1168
1169
1170
1171
1172
1173
1174


1175
1176
1177
1178
1179
1180
1181
1163
1164
1165
1166
1167
1168
1169


1170
1171
1172
1173
1174
1175
1176
1177
1178







-
-
+
+







			redirects: REDIRECTS_DEFAULT];
}

- (void)asyncPerformRequest: (OFHTTPRequest *)request
		  redirects: (unsigned int)redirects
{
	void *pool = objc_autoreleasePoolPush();
	OFURL *URL = [request URL];
	OFString *scheme = [URL scheme];
	OFURL *URL = request.URL;
	OFString *scheme = URL.scheme;

	if (![scheme isEqual: @"http"] && ![scheme isEqual: @"https"])
		@throw [OFUnsupportedProtocolException exceptionWithURL: URL];

	if (_inProgress)
		/* TODO: Find a better exception */
		@throw [OFAlreadyConnectedException exception];

Modified src/OFHTTPCookie.m from [26fae4bc2d] to [09fd3cd222].

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







-
+






-
+


-
-
+
+

-
+

-
+

-
+



-
+

-
-
-
+
+
+















-
-
-
+
+
+







#import "OFURL.h"

#import "OFInvalidFormatException.h"

static void
handleAttribute(OFHTTPCookie *cookie, OFString *name, OFString *value)
{
	OFString *lowercaseName = [name lowercaseString];
	OFString *lowercaseName = name.lowercaseString;

	if (value != nil) {
		if ([lowercaseName isEqual: @"expires"]) {
			OFDate *date = [OFDate
			    dateWithDateString: value
					format: @"%a, %d %b %Y %H:%M:%S %z"];
			[cookie setExpires: date];
			cookie.expires = date;
		} else if ([lowercaseName isEqual: @"max-age"]) {
			OFDate *date = [OFDate dateWithTimeIntervalSinceNow:
			    [value decimalValue]];
			[cookie setExpires: date];
			    value.decimalValue];
			cookie.expires = date;
		} else if ([lowercaseName isEqual: @"domain"])
			[cookie setDomain: value];
			cookie.domain = value;
		else if ([lowercaseName isEqual: @"path"])
			[cookie setPath: value];
			cookie.path = value;
		else
			[[cookie extensions] addObject:
			[cookie.extensions addObject:
			    [OFString stringWithFormat: @"%@=%@", name, value]];
	} else {
		if ([lowercaseName isEqual: @"secure"])
			[cookie setSecure: true];
			cookie.secure = true;
		else if ([lowercaseName isEqual: @"httponly"])
			[cookie setHTTPOnly: true];
		else if ([name length] > 0)
			[[cookie extensions] addObject: name];
			cookie.HTTPOnly = true;
		else if (name.length > 0)
			[cookie.extensions addObject: name];
	}
}

@implementation OFHTTPCookie
@synthesize name = _name, value = _value, domain = _domain, path = _path;
@synthesize expires = _expires, secure = _secure, HTTPOnly = _HTTPOnly;
@synthesize extensions = _extensions;

+ (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesWithResponseHeaderFields:
    (OFDictionary OF_GENERIC(OFString *, OFString *) *)headerFields
    forURL: (OFURL *)URL
{
	OFMutableArray OF_GENERIC(OFHTTPCookie *) *ret = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	OFString *string = [headerFields objectForKey: @"Set-Cookie"];
	OFString *domain = [URL host];
	const of_unichar_t *characters = [string characters];
	size_t length = [string length], last = 0;
	OFString *domain = URL.host;
	const of_unichar_t *characters = string.characters;
	size_t length = string.length, last = 0;
	enum {
		STATE_PRE_NAME,
		STATE_NAME,
		STATE_EXPECT_VALUE,
		STATE_VALUE,
		STATE_QUOTED_VALUE,
		STATE_POST_QUOTED_VALUE,
162
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
162
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







-
+




















-
+









-
+







				state = STATE_ATTR_VALUE;
				last = i + 1;
			} else if (characters[i] == ';' ||
			    characters[i] == ',') {
				name = [string substringWithRange:
				    of_range(last, i - last)];

				handleAttribute([ret lastObject], name, nil);
				handleAttribute(ret.lastObject, name, nil);

				state = (characters[i] == ';'
				    ? STATE_PRE_ATTR_NAME : STATE_PRE_NAME);
			}

			break;
		case STATE_ATTR_VALUE:
			if (characters[i] == ';' || characters[i] == ',') {
				value = [string substringWithRange:
				    of_range(last, i - last)];

				/*
				 * Expires often contains a comma, even though
				 * the comma is used as a separator for
				 * concatenating headers as per RFC 2616,
				 * meaning RFC 6265 contradicts RFC 2616.
				 * Solve this by special casing this.
				 */
				if (characters[i] == ',' &&
				    [name caseInsensitiveCompare: @"expires"] ==
				    OF_ORDERED_SAME && [value length] == 3 &&
				    OF_ORDERED_SAME && value.length == 3 &&
				    ([value isEqual: @"Mon"] ||
				    [value isEqual: @"Tue"] ||
				    [value isEqual: @"Wed"] ||
				    [value isEqual: @"Thu"] ||
				    [value isEqual: @"Fri"] ||
				    [value isEqual: @"Sat"] ||
				    [value isEqual: @"Sun"]))
					break;

				handleAttribute([ret lastObject], name, value);
				handleAttribute(ret.lastObject, name, value);

				state = (characters[i] == ';'
				    ? STATE_PRE_ATTR_NAME : STATE_PRE_NAME);
			}
			break;
		}
	}
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
271
272
273

274
275

276
277
278
279
280
281
282
229
230
231
232
233
234
235

236
237
238
239
240
241
242

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

261
262
263
264
265
266
267
268
269
270
271
272

273
274

275
276
277
278
279
280
281
282







-
+






-
+

















-
+











-
+

-
+







						      domain: domain]];
		break;
	case STATE_ATTR_NAME:
		if (last != length) {
			name = [string substringWithRange:
			    of_range(last, length - last)];

			handleAttribute([ret lastObject], name, nil);
			handleAttribute(ret.lastObject, name, nil);
		}
		break;
	case STATE_ATTR_VALUE:
		value = [string substringWithRange:
		    of_range(last, length - last)];

		handleAttribute([ret lastObject], name, value);
		handleAttribute(ret.lastObject, name, value);

		break;
	}

	objc_autoreleasePoolPop(pool);

	return ret;
}

+ (OFDictionary *)requestHeaderFieldsWithCookies:
    (OFArray OF_GENERIC(OFHTTPCookie *) *)cookies
{
	OFDictionary OF_GENERIC(OFString *, OFString *) *ret;
	void *pool;
	OFMutableString *cookieString;
	bool first = true;

	if ([cookies count] == 0)
	if (cookies.count == 0)
		return [OFDictionary dictionary];

	pool = objc_autoreleasePoolPush();
	cookieString = [OFMutableString string];

	for (OFHTTPCookie *cookie in cookies) {
		if OF_UNLIKELY (first)
			first = false;
		else
			[cookieString appendString: @"; "];

		[cookieString appendString: [cookie name]];
		[cookieString appendString: cookie.name];
		[cookieString appendString: @"="];
		[cookieString appendString: [cookie value]];
		[cookieString appendString: cookie.value];
	}

	ret = [[OFDictionary alloc] initWithObject: cookieString
					    forKey: @"Cookie"];

	objc_autoreleasePoolPop(pool);

364
365
366
367
368
369
370
371
372
373
374
375





376
377
378

379
380
381
382
383
384
385
364
365
366
367
368
369
370





371
372
373
374
375
376
377

378
379
380
381
382
383
384
385







-
-
-
-
-
+
+
+
+
+


-
+







}

- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);
	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, [_value hash]);
	OF_HASH_ADD_HASH(hash, [_domain hash]);
	OF_HASH_ADD_HASH(hash, [_path hash]);
	OF_HASH_ADD_HASH(hash, [_expires hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD_HASH(hash, _value.hash);
	OF_HASH_ADD_HASH(hash, _domain.hash);
	OF_HASH_ADD_HASH(hash, _path.hash);
	OF_HASH_ADD_HASH(hash, _expires.hash);
	OF_HASH_ADD(hash, _secure);
	OF_HASH_ADD(hash, _HTTPOnly);
	OF_HASH_ADD_HASH(hash, [_extensions hash]);
	OF_HASH_ADD_HASH(hash, _extensions.hash);
	OF_HASH_FINALIZE(hash);

	return hash;
}

- (id)copy
{
416
417
418
419
420
421
422
423

424
425
426
427
428
429
430
431
432
433
416
417
418
419
420
421
422

423
424
425
426
427
428
429
430
431
432
433







-
+











	if (_secure)
		[ret appendString: @"; Secure"];

	if (_HTTPOnly)
		[ret appendString: @"; HTTPOnly"];

	if ([_extensions count] > 0)
	if (_extensions.count > 0)
		[ret appendFormat:
		    @"; %@", [_extensions componentsJoinedByString: @"; "]];

	objc_autoreleasePoolPop(pool);

	[ret makeImmutable];

	return ret;
}
@end

Modified src/OFHTTPCookieManager.m from [e598ba5279] to [41a76d5b5b].

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







-
-
+
+

-
+




-
-
+
+

-
+











-
-
-
+
+
+







- (void)addCookie: (OFHTTPCookie *)cookie
	   forURL: (OFURL *)URL
{
	void *pool = objc_autoreleasePoolPush();
	OFString *cookieDomain, *URLHost;
	size_t i;

	if (![[cookie path] hasPrefix: @"/"])
		[cookie setPath: @"/"];
	if (![cookie.path hasPrefix: @"/"])
		cookie.path = @"/";

	if ([cookie isSecure] && ![[URL scheme] isEqual: @"https"]) {
	if (cookie.secure && ![URL.scheme isEqual: @"https"]) {
		objc_autoreleasePoolPop(pool);
		return;
	}

	cookieDomain = [[cookie domain] lowercaseString];
	[cookie setDomain: cookieDomain];
	cookieDomain = cookie.domain.lowercaseString;
	cookie.domain = cookieDomain;

	URLHost = [[URL host] lowercaseString];
	URLHost = URL.host.lowercaseString;
	if (![cookieDomain isEqual: URLHost]) {
		URLHost = [@"." stringByAppendingString: URLHost];

		if (![cookieDomain hasSuffix: URLHost]) {
			objc_autoreleasePoolPop(pool);
			return;
		}
	}

	i = 0;
	for (OFHTTPCookie *iter in _cookies) {
		if ([[iter name] isEqual: [cookie name]] &&
		    [[iter domain] isEqual: [cookie domain]] &&
		    [[iter path] isEqual: [cookie path]]) {
		if ([iter.name isEqual: cookie.name] &&
		    [iter.domain isEqual: cookie.domain] &&
		    [iter.path isEqual: cookie.path]) {
			[_cookies replaceObjectAtIndex: i
					    withObject: cookie];

			objc_autoreleasePoolPop(pool);
			return;
		}

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







-
-
+
+


-
+




-
-
+
+





-
+











-
-
+
+








	for (OFHTTPCookie *cookie in _cookies) {
		void *pool;
		OFDate *expires;
		OFString *cookieDomain, *URLHost, *cookiePath, *URLPath;
		bool match;

		expires = [cookie expires];
		if (expires != nil && [expires timeIntervalSinceNow] <= 0)
		expires = cookie.expires;
		if (expires != nil && expires.timeIntervalSinceNow <= 0)
			continue;

		if ([cookie isSecure] && ![[URL scheme] isEqual: @"https"])
		if (cookie.secure && ![URL.scheme isEqual: @"https"])
			continue;

		pool = objc_autoreleasePoolPush();

		cookieDomain = [[cookie domain] lowercaseString];
		URLHost = [[URL host] lowercaseString];
		cookieDomain = cookie.domain.lowercaseString;
		URLHost = URL.host.lowercaseString;
		if ([cookieDomain hasPrefix: @"."]) {
			if ([URLHost hasSuffix: cookieDomain])
				match = true;
			else {
				cookieDomain = [cookieDomain substringWithRange:
				    of_range(1, [cookieDomain length] - 1)];
				    of_range(1, cookieDomain.length - 1)];

				match = [cookieDomain isEqual: URLHost];
			}
		} else
			match = [cookieDomain isEqual: URLHost];

		if (!match) {
			objc_autoreleasePoolPop(pool);
			continue;
		}

		cookiePath = [cookie path];
		URLPath = [URL path];
		cookiePath = cookie.path;
		URLPath = URL.path;
		if (![cookiePath isEqual: @"/"]) {
			if ([cookiePath isEqual: URLPath])
				match = true;
			else {
				if (![cookiePath hasSuffix: @"/"])
					cookiePath = [cookiePath
					    stringByAppendingString: @"/"];
174
175
176
177
178
179
180
181

182
183
184

185
186
187
188
189
190
191
192
193
174
175
176
177
178
179
180

181
182
183

184
185
186
187
188
189
190
191
192
193







-
+


-
+









	[ret makeImmutable];

	return ret;
}

- (void)purgeExpiredCookies
{
	for (size_t i = 0, count = [_cookies count]; i < count; i++) {
	for (size_t i = 0, count = _cookies.count; i < count; i++) {
		OFDate *expires = [[_cookies objectAtIndex: i] expires];

		if (expires != nil && [expires timeIntervalSinceNow] <= 0) {
		if (expires != nil && expires.timeIntervalSinceNow <= 0) {
			[_cookies removeObjectAtIndex: i];

			i--;
			count--;
			continue;
		}
	}
}
@end

Modified src/OFHTTPRequest.m from [8752774259] to [e973ddf9ac].

137
138
139
140
141
142
143
144
145
146



147
148
149
150
151
152
153
137
138
139
140
141
142
143



144
145
146
147
148
149
150
151
152
153







-
-
-
+
+
+







- (id)copy
{
	OFHTTPRequest *copy = [[OFHTTPRequest alloc] init];

	@try {
		copy->_method = _method;
		copy->_protocolVersion = _protocolVersion;
		[copy setURL: _URL];
		[copy setHeaders: _headers];
		[copy setRemoteAddress: &_remoteAddress];
		copy.URL = _URL;
		copy.headers = _headers;
		copy.remoteAddress = &_remoteAddress;
	} @catch (id e) {
		[copy release];
		@throw e;
	}

	return copy;
}
180
181
182
183
184
185
186
187
188


189
190
191
192
193
194
195
180
181
182
183
184
185
186


187
188
189
190
191
192
193
194
195







-
-
+
+







	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD(hash, _method);
	OF_HASH_ADD(hash, _protocolVersion.major);
	OF_HASH_ADD(hash, _protocolVersion.minor);
	OF_HASH_ADD_HASH(hash, [_URL hash]);
	OF_HASH_ADD_HASH(hash, [_headers hash]);
	OF_HASH_ADD_HASH(hash, _URL.hash);
	OF_HASH_ADD_HASH(hash, _headers.hash);
	OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_remoteAddress));

	OF_HASH_FINALIZE(hash);

	return hash;
}

212
213
214
215
216
217
218
219

220
221
222
223


224
225
226
227
228
229
230
231

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257
258
259

260
261
262
263
264
265
266
212
213
214
215
216
217
218

219
220
221


222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266







-
+


-
-
+
+







-
+

















-
+









-
+







- (void)setProtocolVersionString: (OFString *)string
{
	void *pool = objc_autoreleasePoolPush();
	OFArray *components = [string componentsSeparatedByString: @"."];
	intmax_t major, minor;
	of_http_request_protocol_version_t protocolVersion;

	if ([components count] != 2)
	if (components.count != 2)
		@throw [OFInvalidFormatException exception];

	major = [[components firstObject] decimalValue];
	minor = [[components lastObject] decimalValue];
	major = [components.firstObject decimalValue];
	minor = [components.lastObject decimalValue];

	if (major < 0 || major > UINT8_MAX || minor < 0 || minor > UINT8_MAX)
		@throw [OFOutOfRangeException exception];

	protocolVersion.major = (uint8_t)major;
	protocolVersion.minor = (uint8_t)minor;

	[self setProtocolVersion: protocolVersion];
	self.protocolVersion = protocolVersion;

	objc_autoreleasePoolPop(pool);
}

- (OFString *)protocolVersionString
{
	return [OFString stringWithFormat: @"%u.%u",
					   _protocolVersion.major,
					   _protocolVersion.minor];
}

- (OFString *)description
{
	void *pool = objc_autoreleasePoolPush();
	const char *method = of_http_request_method_to_string(_method);
	OFString *indentedHeaders, *ret;

	indentedHeaders = [[_headers description]
	indentedHeaders = [_headers.description
	    stringByReplacingOccurrencesOfString: @"\n"
				      withString: @"\n\t"];

	ret = [[OFString alloc] initWithFormat:
	    @"<%@:\n\tURL = %@\n"
	    @"\tMethod = %s\n"
	    @"\tHeaders = %@\n"
	    @"\tRemote address = %@\n"
	    @">",
	    [self class], _URL, method, indentedHeaders,
	    self.class, _URL, method, indentedHeaders,
	    of_socket_address_ip_string(&_remoteAddress, NULL)];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}
@end

Modified src/OFHTTPResponse.m from [5a8bf08410] to [883113a592].

28
29
30
31
32
33
34
35
36


37
38
39
40
41
42
43
28
29
30
31
32
33
34


35
36
37
38
39
40
41
42
43







-
-
+
+







#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];
	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,
83
84
85
86
87
88
89
90
91


92
93
94
95
96
97
98
83
84
85
86
87
88
89


90
91
92
93
94
95
96
97
98







-
-
+
+







			}
			break;
		case STATE_PARAM_VALUE:
			if (UTF8String[i] == ';') {
				value = [OFString
				    stringWithUTF8String: UTF8String + last
						  length: i - last];
				value = [value
				    stringByDeletingTrailingWhitespaces];
				value =
				    value.stringByDeletingTrailingWhitespaces;

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

				state = STATE_BEFORE_PARAM_NAME;
				last = i + 1;
			}
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
117
118
119
120
121
122
123

124
125
126
127
128
129
130
131







-
+







				return OF_STRING_ENCODING_AUTODETECT;
			break;
		}
	}
	if (state == STATE_PARAM_VALUE) {
		value = [OFString stringWithUTF8String: UTF8String + last
						length: length - last];
		value = [value stringByDeletingTrailingWhitespaces];
		value = value.stringByDeletingTrailingWhitespaces;

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

	@try {
		ret = of_string_parse_encoding(charset);
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
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







-
+


-
-
+
+







-
+







- (void)setProtocolVersionString: (OFString *)string
{
	void *pool = objc_autoreleasePoolPush();
	OFArray *components = [string componentsSeparatedByString: @"."];
	intmax_t major, minor;
	of_http_request_protocol_version_t protocolVersion;

	if ([components count] != 2)
	if (components.count != 2)
		@throw [OFInvalidFormatException exception];

	major = [[components firstObject] decimalValue];
	minor = [[components lastObject] decimalValue];
	major = [components.firstObject decimalValue];
	minor = [components.lastObject decimalValue];

	if (major < 0 || major > UINT8_MAX || minor < 0 || minor > UINT8_MAX)
		@throw [OFOutOfRangeException exception];

	protocolVersion.major = (uint8_t)major;
	protocolVersion.minor = (uint8_t)minor;

	[self setProtocolVersion: protocolVersion];
	self.protocolVersion = protocolVersion;

	objc_autoreleasePoolPop(pool);
}

- (OFString *)protocolVersionString
{
	return [OFString stringWithFormat: @"%u.%u",
226
227
228
229
230
231
232
233

234
235
236

237
238

239
240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258
259

260
261
262
263
264
265
226
227
228
229
230
231
232

233
234
235

236
237

238
239
240
241
242
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265







-
+


-
+

-
+











-
+








-
+







	if (encoding == OF_STRING_ENCODING_AUTODETECT)
		encoding = OF_STRING_ENCODING_UTF_8;

	data = [self readDataUntilEndOfStream];

	if ((contentLength = [_headers objectForKey: @"Content-Length"]) != nil)
		if ([data count] != (size_t)[contentLength decimalValue])
		if (data.count != (size_t)contentLength.decimalValue)
			@throw [OFTruncatedDataException exception];

	ret = [[OFString alloc] initWithCString: (char *)[data items]
	ret = [[OFString alloc] initWithCString: (char *)data.items
				       encoding: encoding
					 length: [data count]];
					 length: data.count];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}

- (OFString *)description
{
	void *pool = objc_autoreleasePoolPush();
	OFString *indentedHeaders, *ret;

	indentedHeaders = [[_headers description]
	indentedHeaders = [_headers.description
	    stringByReplacingOccurrencesOfString: @"\n"
				      withString: @"\n\t"];

	ret = [[OFString alloc] initWithFormat:
	    @"<%@:\n"
	    @"\tStatus code = %d\n"
	    @"\tHeaders = %@\n"
	    @">",
	    [self class], _statusCode, indentedHeaders];
	    self.class, _statusCode, indentedHeaders];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}
@end

Modified src/OFHTTPServer.h from [3b876afaf6] to [3394497349].

95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109







-
+







	OFString *_Nullable _host;
	uint16_t _port;
	bool _usesTLS;
	OFString *_Nullable _certificateFile, *_Nullable _privateKeyFile;
	const char *_Nullable _privateKeyPassphrase;
	id <OFHTTPServerDelegate> _Nullable _delegate;
	OFString *_Nullable _name;
	OF_KINDOF(OFTCPSocket *) _Nullable _listeningSocket;
	OFTCPSocket *_Nullable _listeningSocket;
#ifdef OF_HAVE_THREADS
	size_t _numberOfThreads, _nextThreadIndex;
	OFArray *_threadPool;
#endif
}

/*!

Modified src/OFHTTPServer.m from [503afee9ba] to [3cdaff788f].

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







-
+





-
+







-
+
















-
+









-
+




-
+







 */

@interface OFHTTPServer () <OFTCPSocketDelegate>
@end

@interface OFHTTPServerResponse: OFHTTPResponse <OFReadyForWritingObserving>
{
	OF_KINDOF(OFTCPSocket *) _socket;
	OFTCPSocket *_socket;
	OFHTTPServer *_server;
	OFHTTPRequest *_request;
	bool _chunked, _headersSent;
}

- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
- (instancetype)initWithSocket: (OFTCPSocket *)sock
			server: (OFHTTPServer *)server
		       request: (OFHTTPRequest *)request;
@end

@interface OFHTTPServer_Connection: OFObject <OFTCPSocketDelegate>
{
@public
	OF_KINDOF(OFTCPSocket *) _socket;
	OFTCPSocket *_socket;
	OFHTTPServer *_server;
	OFTimer *_timer;
	enum {
		AWAITING_PROLOG,
		PARSING_HEADERS,
		SEND_RESPONSE
	} _state;
	uint8_t _HTTPMinorVersion;
	of_http_request_method_t _method;
	OFString *_host, *_path;
	uint16_t _port;
	OFMutableDictionary *_headers;
	size_t _contentLength;
	OFStream *_requestBody;
}

- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
- (instancetype)initWithSocket: (OFTCPSocket *)sock
			server: (OFHTTPServer *)server;
- (bool)parseProlog: (OFString *)line;
- (bool)parseHeaders: (OFString *)line;
- (bool)sendErrorAndClose: (short)statusCode;
- (void)createResponse;
@end

@interface OFHTTPServerRequestBodyStream: OFStream <OFReadyForReadingObserving>
{
	OF_KINDOF(OFTCPSocket *) _socket;
	OFTCPSocket *_socket;
	uintmax_t _toRead;
	bool _atEndOfStream;
}

- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
- (instancetype)initWithSocket: (OFTCPSocket *)sock
		 contentLength: (uintmax_t)contentLength;
@end

#ifdef OF_HAVE_THREADS
@interface OFHTTPServerThread: OFThread
- (void)stop;
@end
201
202
203
204
205
206
207
208

209
210
211
212
213
214

215
216
217
218
219
220
221
201
202
203
204
205
206
207

208
209
210
211
212
213

214
215
216
217
218
219
220
221







-
+





-
+







		return NULL;
	}
}

static OF_INLINE OFString *
normalizedKey(OFString *key)
{
	char *cString = of_strdup([key UTF8String]);
	char *cString = of_strdup(key.UTF8String);
	unsigned char *tmp = (unsigned char *)cString;
	bool firstLetter = true;

	if (cString == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: strlen([key UTF8String])];
		    exceptionWithRequestedSize: strlen(key.UTF8String)];

	while (*tmp != '\0') {
		if (!of_ascii_isalpha(*tmp)) {
			firstLetter = true;
			tmp++;
			continue;
		}
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243







-
+







	}

	return [OFString stringWithUTF8StringNoCopy: cString
				       freeWhenDone: true];
}

@implementation OFHTTPServerResponse
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
- (instancetype)initWithSocket: (OFTCPSocket *)sock
			server: (OFHTTPServer *)server
		       request: (OFHTTPRequest *)request
{
	self = [super init];

	_statusCode = 500;
	_socket = [sock retain];
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276
277
278
279
280
281
282

283
284
285
286
287
288
289
290







-
+













-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFMutableDictionary OF_GENERIC(OFString *, OFString *) *headers;
	OFEnumerator *keyEnumerator, *valueEnumerator;
	OFString *key, *value;

	[_socket writeFormat: @"HTTP/%@ %d %s\r\n",
			      [self protocolVersionString], _statusCode,
			      self.protocolVersionString, _statusCode,
			      statusCodeToString(_statusCode)];

	headers = [[_headers mutableCopy] autorelease];

	if ([headers objectForKey: @"Date"] == nil) {
		OFString *date = [[OFDate date]
		    dateStringWithFormat: @"%a, %d %b %Y %H:%M:%S GMT"];

		[headers setObject: date
			    forKey: @"Date"];
	}

	if ([headers objectForKey: @"Server"] == nil) {
		OFString *name = [_server name];
		OFString *name = _server.name;

		if (name != nil)
			[headers setObject: name
				    forKey: @"Server"];
	}

	keyEnumerator = [headers keyEnumerator];
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
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







-
+




















-
+




-
+







		if (!_headersSent)
			[self of_sendHeaders];

		if (_chunked)
			[_socket writeBuffer: "0\r\n\r\n"
				      length: 5];
	} @catch (OFWriteFailedException *e) {
		id <OFHTTPServerDelegate> delegate = [_server delegate];
		id <OFHTTPServerDelegate> delegate = _server.delegate;

		if ([delegate respondsToSelector: @selector(server:
		  didReceiveExceptionForResponse:request:exception:)])
			[delegate		    server: _server
			    didReceiveExceptionForResponse: self
						   request: _request
						 exception: e];
	}

	[_socket release];
	_socket = nil;

	[super close];
}

- (int)fileDescriptorForWriting
{
	if (_socket == nil)
		return -1;

	return [_socket fileDescriptorForWriting];
	return _socket.fileDescriptorForWriting;
}
@end

@implementation OFHTTPServer_Connection
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
- (instancetype)initWithSocket: (OFTCPSocket *)sock
			server: (OFHTTPServer *)server
{
	self = [super init];

	@try {
		_socket = [sock retain];
		_server = [server retain];
405
406
407
408
409
410
411
412

413
414
415
416
417
418
419
405
406
407
408
409
410
411

412
413
414
415
416
417
418
419







-
+







	[_path release];
	[_headers release];
	[_requestBody release];

	[super dealloc];
}

- (bool)stream: (OF_KINDOF(OFStream *))sock
- (bool)stream: (OFStream *)sock
   didReadLine: (OFString *)line
     exception: (id)exception
{
	if (line == nil || exception != nil)
		return false;

	@try {
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
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







-
+




















-
+
-





-
+







{
	OFString *method;
	OFMutableString *path;
	size_t pos;

	@try {
		OFString *version = [line
		    substringWithRange: of_range([line length] - 9, 9)];
		    substringWithRange: of_range(line.length - 9, 9)];
		of_unichar_t tmp;

		if (![version hasPrefix: @" HTTP/1."])
			return [self sendErrorAndClose: 505];

		tmp = [version characterAtIndex: 8];
		if (tmp < '0' || tmp > '9')
			return [self sendErrorAndClose: 400];

		_HTTPMinorVersion = (uint8_t)(tmp - '0');
	} @catch (OFOutOfRangeException *e) {
		return [self sendErrorAndClose: 400];
	}

	pos = [line rangeOfString: @" "].location;
	if (pos == OF_NOT_FOUND)
		return [self sendErrorAndClose: 400];

	method = [line substringWithRange: of_range(0, pos)];
	@try {
		_method = of_http_request_method_from_string(
		_method = of_http_request_method_from_string(method.UTF8String);
		    [method UTF8String]);
	} @catch (OFInvalidFormatException *e) {
		return [self sendErrorAndClose: 405];
	}

	@try {
		of_range_t range = of_range(pos + 1, [line length] - pos - 10);
		of_range_t range = of_range(pos + 1, line.length - pos - 10);

		path = [[[line substringWithRange:
		    range] mutableCopy] autorelease];
	} @catch (OFOutOfRangeException *e) {
		return [self sendErrorAndClose: 400];
	}

490
491
492
493
494
495
496
497

498
499
500
501
502
503
504
505
506

507
508
509
510
511
512
513
489
490
491
492
493
494
495

496
497
498
499
500
501
502
503
504

505
506
507
508
509
510
511
512







-
+








-
+







}

- (bool)parseHeaders: (OFString *)line
{
	OFString *key, *value, *old;
	size_t pos;

	if ([line length] == 0) {
	if (line.length == 0) {
		OFString *contentLengthString;

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

			@try {
				contentLength =
				    [contentLengthString decimalValue];
				    contentLengthString.decimalValue;

			} @catch (OFInvalidFormatException *e) {
				return [self sendErrorAndClose: 400];
			}

			if (contentLength < 0)
				return [self sendErrorAndClose: 400];
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
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







-
+

-
-
+
+




















-
-
-
+
+
+








	pos = [line rangeOfString: @":"].location;
	if (pos == OF_NOT_FOUND)
		return [self sendErrorAndClose: 400];

	key = [line substringWithRange: of_range(0, pos)];
	value = [line substringWithRange:
	    of_range(pos + 1, [line length] - pos - 1)];
	    of_range(pos + 1, line.length - pos - 1)];

	key = normalizedKey([key stringByDeletingTrailingWhitespaces]);
	value = [value stringByDeletingLeadingWhitespaces];
	key = normalizedKey(key.stringByDeletingTrailingWhitespaces);
	value = value.stringByDeletingLeadingWhitespaces;

	old = [_headers objectForKey: key];
	if (old != nil)
		value = [old stringByAppendingFormat: @",%@", value];

	[_headers setObject: value
		     forKey: key];

	if ([key isEqual: @"Host"]) {
		pos = [value
		    rangeOfString: @":"
			  options: OF_STRING_SEARCH_BACKWARDS].location;

		if (pos != OF_NOT_FOUND) {
			[_host release];
			_host = [[value substringWithRange:
			    of_range(0, pos)] retain];

			@try {
				of_range_t range =
				    of_range(pos + 1, [value length] - pos - 1);
				intmax_t portTmp = [[value
				    substringWithRange: range] decimalValue];
				    of_range(pos + 1, value.length - pos - 1);
				intmax_t portTmp = [value
				    substringWithRange: range].decimalValue;

				if (portTmp < 1 || portTmp > UINT16_MAX)
					return [self sendErrorAndClose: 400];

				_port = (uint16_t)portTmp;
			} @catch (OFInvalidFormatException *e) {
				return [self sendErrorAndClose: 400];
586
587
588
589
590
591
592
593

594
595
596
597
598
599
600
585
586
587
588
589
590
591

592
593
594
595
596
597
598
599







-
+







	    dateStringWithFormat: @"%a, %d %b %Y %H:%M:%S GMT"];

	[_socket writeFormat: @"HTTP/1.1 %d %s\r\n"
			      @"Date: %@\r\n"
			      @"Server: %@\r\n"
			      @"\r\n",
			      statusCode, statusCodeToString(statusCode),
			      date, [_server name]];
			      date, _server.name];

	return false;
}

- (void)createResponse
{
	void *pool = objc_autoreleasePoolPush();
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
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







-
+




-
-
+
+

-
+






-
+

-
-
+
+

-
+




-
-
-
-
-
+
+
+
+
+






-
-
-
-
+
+
+
+






-
+







	if (_host == nil || _port == 0) {
		if (_HTTPMinorVersion > 0) {
			[self sendErrorAndClose: 400];
			return;
		}

		[_host release];
		_host = [[_server host] retain];
		_host = [_server.host copy];
		_port = [_server port];
	}

	URL = [OFMutableURL URL];
	[URL setScheme: @"http"];
	[URL setHost: _host];
	URL.scheme = @"http";
	URL.host = _host;
	if (_port != 80)
		[URL setPort: [OFNumber numberWithUInt16: _port]];
		URL.port = [OFNumber numberWithUInt16: _port];

	if ((pos = [_path rangeOfString: @"?"].location) != OF_NOT_FOUND) {
		OFString *path, *query;

		path = [_path substringWithRange: of_range(0, pos)];
		query = [_path substringWithRange:
		    of_range(pos + 1, [_path length] - pos - 1)];
		    of_range(pos + 1, _path.length - pos - 1)];

		[URL setURLEncodedPath: path];
		[URL setURLEncodedQuery: query];
		URL.URLEncodedPath = path;
		URL.URLEncodedQuery = query;
	} else
		[URL setURLEncodedPath: _path];
		URL.URLEncodedPath = _path;

	[URL makeImmutable];

	request = [OFHTTPRequest requestWithURL: URL];
	[request setMethod: _method];
	[request setProtocolVersion:
	    (of_http_request_protocol_version_t){ 1, _HTTPMinorVersion }];
	[request setHeaders: _headers];
	[request setRemoteAddress: [_socket remoteAddress]];
	request.method = _method;
	request.protocolVersion =
	    (of_http_request_protocol_version_t){ 1, _HTTPMinorVersion };
	request.headers = _headers;
	request.remoteAddress = _socket.remoteAddress;

	response = [[[OFHTTPServerResponse alloc]
	    initWithSocket: _socket
		    server: _server
		   request: request] autorelease];

	[[_server delegate] server: _server
		 didReceiveRequest: request
		       requestBody: _requestBody
			  response: response];
	[_server.delegate server: _server
	       didReceiveRequest: request
		     requestBody: _requestBody
			response: response];

	objc_autoreleasePoolPop(pool);
}
@end

@implementation OFHTTPServerRequestBodyStream
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
- (instancetype)initWithSocket: (OFTCPSocket *)sock
		 contentLength: (uintmax_t)contentLength
{
	self = [super init];

	@try {
		_socket = [sock retain];
		_toRead = contentLength;
707
708
709
710
711
712
713
714

715
716
717
718
719

720
721
722
723
724
725
726
706
707
708
709
710
711
712

713
714
715
716
717

718
719
720
721
722
723
724
725







-
+




-
+







	_toRead -= ret;

	return ret;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] || [_socket hasDataInReadBuffer]);
	return (super.hasDataInReadBuffer || _socket.hasDataInReadBuffer);
}

- (int)fileDescriptorForReading
{
	return [_socket fileDescriptorForReading];
	return _socket.fileDescriptorForReading;
}

- (void)close
{
	[_socket release];
	_socket = nil;
}
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
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







-
+

-
+





-
+



















-
+




-
+
+

-
-
-
+
+
-
-
+








- (const char *)privateKeyPassphrase
{
	return _privateKeyPassphrase;
}

#ifdef OF_HAVE_THREADS
- (void)setNumberOfThreads: (size_t)numberOfThreadas
- (void)setNumberOfThreads: (size_t)numberOfThreads
{
	if (numberOfThreadas == 0)
	if (numberOfThreads == 0)
		@throw [OFInvalidArgumentException exception];

	if (_listeningSocket != nil)
		@throw [OFAlreadyConnectedException exception];

	_numberOfThreads = numberOfThreadas;
	_numberOfThreads = numberOfThreads;
}

- (size_t)numberOfThreads
{
	return _numberOfThreads;
}
#endif

- (void)start
{
	void *pool = objc_autoreleasePoolPush();

	if (_host == nil)
		@throw [OFInvalidArgumentException exception];

	if (_listeningSocket != nil)
		@throw [OFAlreadyConnectedException exception];

	if (_usesTLS) {
		id <OFTLSSocket> listeningSocket;
		OFTCPSocket <OFTLSSocket> *TLSSocket;

		if (of_tls_socket_class == Nil)
			@throw [OFUnsupportedProtocolException exception];

		_listeningSocket = [[of_tls_socket_class alloc] init];
		TLSSocket = [[of_tls_socket_class alloc] init];
		_listeningSocket = TLSSocket;

		listeningSocket = _listeningSocket;
		[listeningSocket setCertificateFile: _certificateFile];
		[listeningSocket setPrivateKeyFile: _privateKeyFile];
		TLSSocket.certificateFile = _certificateFile;
		TLSSocket.privateKeyFile = _privateKeyFile;
		[listeningSocket
		    setPrivateKeyPassphrase: _privateKeyPassphrase];
		TLSSocket.privateKeyPassphrase = _privateKeyPassphrase;
	} else
		_listeningSocket = [[OFTCPSocket alloc] init];

	_port = [_listeningSocket bindToHost: _host
					port: _port];
	[_listeningSocket listen];

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







-
+




















-
+





-
+



-
-
+
+







		}

		[threads makeImmutable];
		_threadPool = [threads copy];
	}
#endif

	[(OFTCPSocket *)_listeningSocket setDelegate: self];
	((OFTCPSocket *)_listeningSocket).delegate = self;
	[_listeningSocket asyncAccept];

	objc_autoreleasePoolPop(pool);
}

- (void)stop
{
	[_listeningSocket cancelAsyncRequests];
	[_listeningSocket release];
	_listeningSocket = nil;

#ifdef OF_HAVE_THREADS
	for (OFHTTPServerThread *thread in _threadPool)
		[thread stop];

	[_threadPool release];
	_threadPool = nil;
#endif
}

- (void)of_handleAcceptedSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket
- (void)of_handleAcceptedSocket: (OFTCPSocket *)acceptedSocket
{
	OFHTTPServer_Connection *connection = [[[OFHTTPServer_Connection alloc]
	    initWithSocket: acceptedSocket
		    server: self] autorelease];

	[(OFTCPSocket *)acceptedSocket setDelegate: connection];
	acceptedSocket.delegate = connection;
	[acceptedSocket asyncReadLine];
}

-    (bool)socket: (OF_KINDOF(OFTCPSocket *))sock
  didAcceptSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket
-    (bool)socket: (OFTCPSocket *)sock
  didAcceptSocket: (OFTCPSocket *)acceptedSocket
	exception: (id)exception
{
	if (exception != nil) {
		if (![_delegate respondsToSelector:
		    @selector(server:didReceiveExceptionOnListeningSocket:)])
			return false;

Modified src/OFINICategory.m from [1a0915adbe] to [aa5333e1f9].

77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91







-
+







unescapeString(OFString *string)
{
	OFMutableString *mutableString;

	if (![string hasPrefix: @"\""] || ![string hasSuffix: @"\""])
		return string;

	string = [string substringWithRange: of_range(1, [string length] - 2)];
	string = [string substringWithRange: of_range(1, string.length - 2)];
	mutableString = [[string mutableCopy] autorelease];

	[mutableString replaceOccurrencesOfString: @"\\f"
				       withString: @"\f"];
	[mutableString replaceOccurrencesOfString: @"\\r"
				       withString: @"\r"];
	[mutableString replaceOccurrencesOfString: @"\\n"
159
160
161
162
163
164
165
166

167
168
169


170
171
172
173
174
175
176
159
160
161
162
163
164
165

166
167


168
169
170
171
172
173
174
175
176







-
+

-
-
+
+







		size_t pos;

		if ((pos = [line rangeOfString: @"="].location) == OF_NOT_FOUND)
			@throw [OFInvalidFormatException exception];

		key = [line substringWithRange: of_range(0, pos)];
		value = [line substringWithRange:
		    of_range(pos + 1, [line length] - pos - 1)];
		    of_range(pos + 1, line.length - pos - 1)];

		key = [key stringByDeletingEnclosingWhitespaces];
		value = [value stringByDeletingEnclosingWhitespaces];
		key = key.stringByDeletingEnclosingWhitespaces;
		value = value.stringByDeletingEnclosingWhitespaces;

		key = unescapeString(key);
		value = unescapeString(value);

		pair->_key = [key copy];
		pair->_value = [value copy];

215
216
217
218
219
220
221
222

223
224

225
226
227
228
229
230
231
215
216
217
218
219
220
221

222
223

224
225
226
227
228
229
230
231







-
+

-
+







	void *pool = objc_autoreleasePoolPush();
	OFString *value = [self stringForKey: key
				defaultValue: nil];
	intmax_t ret;

	if (value != nil) {
		if ([value hasPrefix: @"0x"] || [value hasPrefix: @"$"])
			ret = [value hexadecimalValue];
			ret = value.hexadecimalValue;
		else
			ret = [value decimalValue];
			ret = value.decimalValue;
	} else
		ret = defaultValue;

	objc_autoreleasePoolPop(pool);

	return ret;
}
258
259
260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
258
259
260
261
262
263
264

265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

283
284
285
286
287
288
289
290







-
+

















-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFString *value = [self stringForKey: key
				defaultValue: nil];
	float ret;

	if (value != nil)
		ret = [value floatValue];
		ret = value.floatValue;
	else
		ret = defaultValue;

	objc_autoreleasePoolPop(pool);

	return ret;
}

- (double)doubleForKey: (OFString *)key
	  defaultValue: (double)defaultValue
{
	void *pool = objc_autoreleasePoolPush();
	OFString *value = [self stringForKey: key
				defaultValue: nil];
	double ret;

	if (value != nil)
		ret = [value doubleValue];
		ret = value.doubleValue;
	else
		ret = defaultValue;

	objc_autoreleasePoolPop(pool);

	return ret;
}
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
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


485
486
487
488
489
490
491
492
493
494
495
496
497
498

499
500
501
502
503
504
505
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
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
485
486
487
488
489
490
491
492
493
494
495
496
497

498
499
500
501
502
503
504
505







-
+






-
+














-
-
+
+



















-
+



-
-
+
+














-
-
+
+












-
-
+
+













-
+







{
	void *pool;
	OFMutableArray *pairs;
	id const *lines;
	size_t count;
	bool replaced;

	if ([array count] == 0) {
	if (array.count == 0) {
		[self removeValueForKey: key];
		return;
	}

	pool = objc_autoreleasePoolPush();

	pairs = [OFMutableArray arrayWithCapacity: [array count]];
	pairs = [OFMutableArray arrayWithCapacity: array.count];

	for (id object in array) {
		OFINICategory_Pair *pair;

		if (![object isKindOfClass: [OFString class]])
			@throw [OFInvalidArgumentException exception];

		pair = [[[OFINICategory_Pair alloc] init] autorelease];
		pair->_key = [key copy];
		pair->_value = [object copy];

		[pairs addObject: pair];
	}

	lines = [_lines objects];
	count = [_lines count];
	lines = _lines.objects;
	count = _lines.count;
	replaced = false;

	for (size_t i = 0; i < count; i++) {
		OFINICategory_Pair *pair;

		if (![lines[i] isKindOfClass: [OFINICategory_Pair class]])
			continue;

		pair = lines[i];

		if ([pair->_key isEqual: key]) {
			[_lines removeObjectAtIndex: i];

			if (!replaced) {
				[_lines insertObjectsFromArray: pairs
						       atIndex: i];

				replaced = true;
				/* Continue after inserted pairs */
				i += [array count] - 1;
				i += array.count - 1;
			} else
				i--;	/* Continue at same position */

			lines = [_lines objects];
			count = [_lines count];
			lines = _lines.objects;
			count = _lines.count;

			continue;
		}
	}

	if (!replaced)
		[_lines addObjectsFromArray: pairs];

	objc_autoreleasePoolPop(pool);
}

- (void)removeValueForKey: (OFString *)key
{
	void *pool = objc_autoreleasePoolPush();
	id const *lines = [_lines objects];
	size_t count = [_lines count];
	id const *lines = _lines.objects;
	size_t count = _lines.count;

	for (size_t i = 0; i < count; i++) {
		OFINICategory_Pair *pair;

		if (![lines[i] isKindOfClass: [OFINICategory_Pair class]])
			continue;

		pair = lines[i];

		if ([pair->_key isEqual: key]) {
			[_lines removeObjectAtIndex: i];

			lines = [_lines objects];
			count = [_lines count];
			lines = _lines.objects;
			count = _lines.count;

			i--;	/* Continue at same position */
			continue;
		}
	}

	objc_autoreleasePoolPop(pool);
}

- (bool)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding
		   first: (bool)first
{
	if ([_lines count] == 0)
	if (_lines.count == 0)
		return false;

	if (first)
		[stream writeFormat: @"[%@]\r\n", _name];
	else
		[stream writeFormat: @"\r\n[%@]\r\n", _name];

Modified src/OFINIFile.m from [e922a1bcde] to [704c71d30b].

33
34
35
36
37
38
39
40
41


42
43
44
45
46
47
48
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48







-
-
+
+







- (void)of_parseFile: (OFString *)path
	    encoding: (of_string_encoding_t)encoding;
@end

static bool
isWhitespaceLine(OFString *line)
{
	const char *cString = [line UTF8String];
	size_t length = [line UTF8StringLength];
	const char *cString = line.UTF8String;
	size_t length = line.UTF8StringLength;

	for (size_t i = 0; i < length; i++)
		if (!of_ascii_isspace(cString[i]))
			return false;

	return true;
}
98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112







-
+








- (OFINICategory *)categoryForName: (OFString *)name
{
	void *pool = objc_autoreleasePoolPush();
	OFINICategory *category;

	for (category in _categories)
		if ([[category name] isEqual: name])
		if ([category.name isEqual: name])
			return category;

	category = [[[OFINICategory alloc] of_initWithName: name] autorelease];
	[_categories addObject: category];

	objc_autoreleasePoolPop(pool);

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







-
+
















-
+







	OFString *line;

	@try {
		file = [OFFile fileWithPath: path
				       mode: @"r"];
	} @catch (OFOpenItemFailedException *e) {
		/* Handle missing file like an empty file */
		if ([e errNo] == ENOENT)
		if (e.errNo == ENOENT)
			return;

		@throw e;
	}

	while ((line = [file readLineWithEncoding: encoding]) != nil) {
		if (isWhitespaceLine(line))
			continue;

		if ([line hasPrefix: @"["]) {
			OFString *categoryName;

			if (![line hasSuffix: @"]"])
				@throw [OFInvalidFormatException exception];

			categoryName = [line substringWithRange:
			    of_range(1, [line length] - 2)];
			    of_range(1, line.length - 2)];

			category = [[[OFINICategory alloc]
			    of_initWithName: categoryName] autorelease];
			[_categories addObject: category];
		} else {
			if (category == nil)
				@throw [OFInvalidFormatException exception];

Modified src/OFInflate64Stream.h from [d706b9c186] to [7e95b67f65].

32
33
34
35
36
37
38
39

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

39
40
41
42
43
44
45
46







-
+







 *	  underlying stream.
 */
@interface OFInflate64Stream: OFStream <OFReadyForReadingObserving>
{
#ifdef OF_INFLATE64_STREAM_M
@public
#endif
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	unsigned char _buffer[OF_INFLATE64_STREAM_BUFFER_SIZE];
	uint16_t _bufferIndex, _bufferLength;
	uint8_t _byte;
	uint8_t _bitIndex, _savedBitsLength;
	uint16_t _savedBits;
	unsigned char *_Nullable _slidingWindow;
	uint16_t _slidingWindowIndex, _slidingWindowMask;
77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95

96

97
98
99







-
+











-
+
-



/*!
 * @brief Creates a new OFInflate64Stream with the specified underlying stream.
 *
 * @param stream The underlying stream to which compressed data is written or
 *		 from which compressed data is read
 * @return A new, autoreleased OFInflate64Stream
 */
+ (instancetype)streamWithStream: (OF_KINDOF(OFStream *))stream;
+ (instancetype)streamWithStream: (OFStream *)stream;

- (instancetype)init OF_UNAVAILABLE;

/*!
 * @brief Initializes an already allocated OFInflate64Stream with the specified
 *	  underlying stream.
 *
 * @param stream The underlying stream to which compressed data is written or
 *		 from which compressed data is read
 * @return A initialized OFInflate64Stream
 */
- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream OF_DESIGNATED_INITIALIZER;
    OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Modified src/OFInflateStream.h from [39722f3e94] to [ba3144156c].

32
33
34
35
36
37
38
39

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

39
40
41
42
43
44
45
46







-
+







 *	  underlying stream.
 */
@interface OFInflateStream: OFStream <OFReadyForReadingObserving>
{
#ifdef OF_INFLATE_STREAM_M
@public
#endif
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	unsigned char _buffer[OF_INFLATE_STREAM_BUFFER_SIZE];
	uint16_t _bufferIndex, _bufferLength;
	uint8_t _byte;
	uint8_t _bitIndex, _savedBitsLength;
	uint16_t _savedBits;
	unsigned char *_Nullable _slidingWindow;
	uint16_t _slidingWindowIndex, _slidingWindowMask;
77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95

96

97
98
99







-
+











-
+
-



/*!
 * @brief Creates a new OFInflateStream with the specified underlying stream.
 *
 * @param stream The underlying stream to which compressed data is written or
 *		 from which compressed data is read
 * @return A new, autoreleased OFInflateStream
 */
+ (instancetype)streamWithStream: (OF_KINDOF(OFStream *))stream;
+ (instancetype)streamWithStream: (OFStream *)stream;

- (instancetype)init OF_UNAVAILABLE;

/*!
 * @brief Initializes an already allocated OFInflateStream with the specified
 *	  underlying stream.
 *
 * @param stream The underlying stream to which compressed data is written or
 *		 from which compressed data is read
 * @return A initialized OFInflateStream
 */
- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream OF_DESIGNATED_INITIALIZER;
    OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Modified src/OFInflateStream.m from [b3630eb5b7] to [98e2dc75e9].

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







-
+









-
+








	for (uint16_t i = 0; i <= 31; i++)
		lengths[i] = 5;

	fixedDistTree = of_huffman_tree_construct(lengths, 32);
}

+ (instancetype)streamWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)streamWithStream: (OFStream *)stream
{
	return [[[self alloc] initWithStream: stream] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
{
	self = [super init];

	@try {
		_stream = [stream retain];

		/* 0-7 address the bit, 8 means fetch next byte */
664
665
666
667
668
669
670

671

672
673
674
675
676

677
678
679
680
681
682
683
664
665
666
667
668
669
670
671

672
673
674
675
676

677
678
679
680
681
682
683
684







+
-
+




-
+







		@throw [OFNotOpenException exceptionWithObject: self];

	return _atEndOfStream;
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	return [_stream fileDescriptorForReading];
	    .fileDescriptorForReading;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer] ||
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer ||
	    _bufferLength - _bufferIndex > 0);
}

- (void)close
{
	/* Give back our buffer to the stream, in case it's shared */
	[_stream unreadFromBuffer: _buffer + _bufferIndex

Modified src/OFIntrospection.m from [cd6beb50c0] to [79c1692f33].

77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91







-
+








	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<%@: %@ [%s]>",
					   [self class], _name, _typeEncoding];
					   self.class, _name, _typeEncoding];
}

- (bool)isEqual: (id)object
{
	OFMethod *method;

	if (object == self)
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
115
116
117
118
119
120
121

122
123
124
125
126
127
128
129







-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);

	if (_typeEncoding != NULL) {
		size_t length = strlen(_typeEncoding);

		for (size_t i = 0; i < length; i++)
			OF_HASH_ADD(hash, _typeEncoding[i]);
	}
175
176
177
178
179
180
181
182

183
184
185
186
187
188
189
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189







-
+







		const char *attributes;

		_name = [[OFString alloc]
		    initWithUTF8String: property_getName(property)];

		if ((attributes = property_getAttributes(property)) == NULL)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		while (*attributes != '\0') {
			const char *start;

			switch (*attributes) {
			case 'T':
				while (*attributes != ',' &&
207
208
209
210
211
212
213
214

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
207
208
209
210
211
212
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234
235
236
237







-
+















-
+







				attributes++;
				break;
			case 'G':
				start = ++attributes;

				if (_getter != nil)
					@throw [OFInitializationFailedException
					    exceptionWithClass: [self class]];
					    exceptionWithClass: self.class];

				while (*attributes != ',' &&
				    *attributes != '\0')
					attributes++;

				_getter = [[OFString alloc]
				    initWithUTF8String: start
						length: attributes - start];

				break;
			case 'S':
				start = ++attributes;

				if (_setter != nil)
					@throw [OFInitializationFailedException
					    exceptionWithClass: [self class]];
					    exceptionWithClass: self.class];

				while (*attributes != ',' &&
				    *attributes != '\0')
					attributes++;

				_setter = [[OFString alloc]
				    initWithUTF8String: start
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264
265
266
267
268
269
270

271
272
273
274
275

276
277
278
279
280
281
282
250
251
252
253
254
255
256

257
258
259
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274

275
276
277
278
279
280
281
282







-
+












-
+




-
+







				attributes++;
				break;
			case 'V':
				start = ++attributes;

				if (_iVar != nil)
					@throw [OFInitializationFailedException
					    exceptionWithClass: [self class]];
					    exceptionWithClass: self.class];

				while (*attributes != ',' &&
				    *attributes != '\0')
					attributes++;

				_iVar = [[OFString alloc]
				    initWithUTF8String: start
						length: attributes - start];

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

			if (*attributes != ',' && *attributes != '\0')
				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
				    exceptionWithClass: self.class];

			if (*attributes != '\0')
				attributes++;
		}

		if (!(_attributes & OF_PROPERTY_READONLY))
			_attributes |= OF_PROPERTY_READWRITE;
330
331
332
333
334
335
336
337
338


339
340
341
342
343
344
345
330
331
332
333
334
335
336


337
338
339
340
341
342
343
344
345







-
-
+
+







	return [OFString
	    stringWithFormat: @"<%@: %@\n"
			      @"\tAttributes = 0x%03X\n"
			      @"\tGetter = %@\n"
			      @"\tSetter = %@\n"
			      @"\tiVar = %@\n"
			      @">",
			      [self class], _name, _attributes,
			      _getter, _setter, _iVar];
			      self.class, _name, _attributes, _getter, _setter,
			      _iVar];
}

- (bool)isEqual: (id)object
{
	OFProperty *otherProperty;

	if (object == self)
364
365
366
367
368
369
370
371

372
373
374
375


376
377
378
379
380
381
382
364
365
366
367
368
369
370

371
372
373


374
375
376
377
378
379
380
381
382







-
+


-
-
+
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, (_attributes & 0xFF00) >> 8);
	OF_HASH_ADD(hash, _attributes & 0xFF);
	OF_HASH_ADD_HASH(hash, [_getter hash]);
	OF_HASH_ADD_HASH(hash, [_setter hash]);
	OF_HASH_ADD_HASH(hash, _getter.hash);
	OF_HASH_ADD_HASH(hash, _setter.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}
@end

Modified src/OFInvocation.m from [df81aa2e85] to [a9afe182d2].

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







-
+



















-
+








- (instancetype)initWithMethodSignature: (OFMethodSignature *)signature
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		size_t numberOfArguments = [signature numberOfArguments];
		size_t numberOfArguments = signature.numberOfArguments;
		const char *typeEncoding;
		size_t typeSize;

		_methodSignature = [signature retain];
		_arguments = [[OFMutableArray alloc] init];

		for (size_t i = 0; i < numberOfArguments; i++) {
			OFMutableData *data;

			typeEncoding = [_methodSignature
			    argumentTypeAtIndex: i];
			typeSize = of_sizeof_type_encoding(typeEncoding);

			data = [OFMutableData dataWithItemSize: typeSize
						      capacity: 1];
			[data increaseCountBy: 1];
			[_arguments addObject: data];
		}

		typeEncoding = [_methodSignature methodReturnType];
		typeEncoding = _methodSignature.methodReturnType;
		typeSize = of_sizeof_type_encoding(typeEncoding);

		if (typeSize > 0) {
			_returnValue = [[OFMutableData alloc]
			    initWithItemSize: typeSize
				    capacity: 1];
			[_returnValue increaseCountBy: 1];
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
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







-
+







-
+




-
+




-
+









}

- (void)setArgument: (const void *)buffer
	    atIndex: (size_t)idx
{
	OFMutableData *data = [_arguments objectAtIndex: idx];

	memcpy([data items], buffer, [data itemSize]);
	memcpy(data.mutableItems, buffer, data.itemSize);
}

- (void)getArgument: (void *)buffer
	    atIndex: (size_t)idx
{
	OFData *data = [_arguments objectAtIndex: idx];

	memcpy(buffer, [data items], [data itemSize]);
	memcpy(buffer, data.items, data.itemSize);
}

- (void)setReturnValue: (const void *)buffer
{
	memcpy([_returnValue items], buffer, [_returnValue itemSize]);
	memcpy(_returnValue.mutableItems, buffer, _returnValue.itemSize);
}

- (void)getReturnValue: (void *)buffer
{
	memcpy(buffer, [_returnValue items], [_returnValue itemSize]);
	memcpy(buffer, _returnValue.items, _returnValue.itemSize);
}

#ifdef OF_INVOCATION_CAN_INVOKE
- (void)invoke
{
	of_invocation_invoke(self);
}
#endif
@end

Modified src/OFKernelEventObserver.m from [97baff6c86] to [68149c85a6].

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







-
+





-
+













-
+





-
+


















-
+








		_readObjects = [[OFMutableArray alloc] init];
		_writeObjects = [[OFMutableArray alloc] init];

#ifdef OF_HAVE_PIPE
		if (pipe(_cancelFD))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
#else
		_cancelFD[0] = _cancelFD[1] = socket(AF_INET, SOCK_DGRAM, 0);

		if (_cancelFD[0] == INVALID_SOCKET)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		_cancelAddr.sin_family = AF_INET;
		_cancelAddr.sin_port = 0;
		_cancelAddr.sin_addr.s_addr =
		    inet_addr((const void *)"127.0.0.1");
# ifdef OF_WII
		_cancelAddr.sin_len = 8;
# endif

# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
		if (bind(_cancelFD[0], (struct sockaddr *)&_cancelAddr,
		    sizeof(_cancelAddr)) != 0)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		cancelAddrLen = sizeof(_cancelAddr);
		if (of_getsockname(_cancelFD[0],
		    (struct sockaddr *)&_cancelAddr, &cancelAddrLen) != 0)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
# else
		for (;;) {
			uint16_t rnd = 0;
			int ret;

			while (rnd < 1024)
				rnd = (uint16_t)rand();

			_cancelAddr.sin_port = OF_BSWAP16_IF_LE(rnd);
			ret = bind(_cancelFD[0],
			    (struct sockaddr *)&_cancelAddr,
			    sizeof(_cancelAddr));

			if (ret == 0)
				break;

			if (of_socket_errno() != EADDRINUSE)
				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
				    exceptionWithClass: self.class];
		}
# endif
#endif

#ifdef OF_HAVE_THREADS
		_mutex = [[OFMutex alloc] init];
#endif
304
305
306
307
308
309
310
311
312
313



314
315

316
317
318
319
320
321
322
304
305
306
307
308
309
310



311
312
313
314

315
316
317
318
319
320
321
322







-
-
-
+
+
+

-
+







{
	void *pool = objc_autoreleasePoolPush();

#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		int *queueActions = [_queueActions items];
		id const *queueObjects = [_queueObjects objects];
		size_t count = [_queueActions count];
		const int *queueActions = _queueActions.items;
		id const *queueObjects = _queueObjects.objects;
		size_t count = _queueActions.count;

		OF_ENSURE([_queueObjects count] == count);
		OF_ENSURE(_queueObjects.count == count);

		for (size_t i = 0; i < count; i++) {
			int action = queueActions[i];
			id object = queueObjects[i];

			switch (action) {
			case QUEUE_ADD | QUEUE_READ:
408
409
410
411
412
413
414
415

416
417
418
419
420
421
422
408
409
410
411
412
413
414

415
416
417
418
419
420
421
422







-
+







- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)observeUntilDate: (OFDate *)date
{
	[self observeForTimeInterval: [date timeIntervalSinceNow]];
	[self observeForTimeInterval: date.timeIntervalSinceNow];
}

- (void)cancel
{
#ifdef OF_HAVE_PIPE
	OF_ENSURE(write(_cancelFD[1], "", 1) > 0);
#elif defined(OF_WII)

Modified src/OFKernelEventObserver_epoll.m from [0ecb9c1ccd] to [c7d873c63a].

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







-
+





-
+















-
+








	@try {
		struct epoll_event event;

#ifdef HAVE_EPOLL_CREATE1
		if ((_epfd = epoll_create1(EPOLL_CLOEXEC)) == -1)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
#else
		int flags;

		if ((_epfd = epoll_create(1)) == -1)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		if ((flags = fcntl(_epfd, F_GETFD, 0)) != -1)
			fcntl(_epfd, F_SETFD, flags | FD_CLOEXEC);
#endif

		_FDToEvents = [[OFMapTable alloc]
		    initWithKeyFunctions: mapFunctions
			 objectFunctions: mapFunctions];

		memset(&event, 0, sizeof(event));
		event.events = EPOLLIN;
		event.data.ptr = [OFNull null];

		if (epoll_ctl(_epfd, EPOLL_CTL_ADD, _cancelFD[0], &event) == -1)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
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
183
184
185
186
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
183
184
185
186







-
+






-
+






-
+






-
+







				forKey: (void *)((intptr_t)fd + 1)];
	}
}

- (void)of_addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self of_addObject: object
	    fileDescriptor: [object fileDescriptorForReading]
	    fileDescriptor: object.fileDescriptorForReading
		    events: EPOLLIN];
}

- (void)of_addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self of_addObject: object
	    fileDescriptor: [object fileDescriptorForWriting]
	    fileDescriptor: object.fileDescriptorForWriting
		    events: EPOLLOUT];
}

- (void)of_removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self of_removeObject: object
	       fileDescriptor: [object fileDescriptorForReading]
	       fileDescriptor: object.fileDescriptorForReading
		       events: EPOLLIN];
}

- (void)of_removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self of_removeObject: object
	       fileDescriptor: [object fileDescriptorForWriting]
	       fileDescriptor: object.fileDescriptorForWriting
		       events: EPOLLOUT];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	OFNull *nullObject = [OFNull null];
	struct epoll_event eventList[EVENTLIST_SIZE];

Modified src/OFKernelEventObserver_kqueue.m from [3386cd3187] to [48331f17e7].

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







-
+





-
+









-
+




















-
+


















-
+


















-
+













-
+








	@try {
		struct kevent event;

#ifdef HAVE_KQUEUE1
		if ((_kernelQueue = kqueue1(O_CLOEXEC)) == -1)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
#else
		int flags;

		if ((_kernelQueue = kqueue()) == -1)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		if ((flags = fcntl(_kernelQueue, F_GETFD, 0)) != -1)
			fcntl(_kernelQueue, F_SETFD, flags | FD_CLOEXEC);
#endif

		EV_SET(&event, _cancelFD[0], EVFILT_READ, EV_ADD, 0, 0, 0);

		if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	close(_kernelQueue);

	[super dealloc];
}

- (void)of_addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForReading];
	event.ident = object.fileDescriptorForReading;
	event.filter = EVFILT_READ;
	event.flags = EV_ADD;
#ifndef OF_NETBSD
	event.udata = object;
#else
	event.udata = (intptr_t)object;
#endif

	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: errno];
}

- (void)of_addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForWriting];
	event.ident = object.fileDescriptorForWriting;
	event.filter = EVFILT_WRITE;
	event.flags = EV_ADD;
#ifndef OF_NETBSD
	event.udata = object;
#else
	event.udata = (intptr_t)object;
#endif

	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: errno];
}

- (void)of_removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForReading];
	event.ident = object.fileDescriptorForReading;
	event.filter = EVFILT_READ;
	event.flags = EV_DELETE;

	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: errno];
}

- (void)of_removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForWriting];
	event.ident = object.fileDescriptorForWriting;
	event.filter = EVFILT_WRITE;
	event.flags = EV_DELETE;

	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: errno];
}

Modified src/OFKernelEventObserver_poll.m from [f7752f3f82] to [e0fcf68d56].

71
72
73
74
75
76
77
78
79


80
81
82
83
84
85
86
71
72
73
74
75
76
77


78
79
80
81
82
83
84
85
86







-
-
+
+







	[super dealloc];
}

- (void)of_addObject: (id)object
      fileDescriptor: (int)fd
	      events: (short)events
{
	struct pollfd *FDs = [_FDs items];
	size_t count = [_FDs count];
	struct pollfd *FDs = _FDs.mutableItems;
	size_t count = _FDs.count;
	bool found = false;

	for (size_t i = 0; i < count; i++) {
		if (FDs[i].fd == fd) {
			FDs[i].events |= events;
			found = true;
			break;
102
103
104
105
106
107
108
109
110


111
112
113
114
115
116
117
102
103
104
105
106
107
108


109
110
111
112
113
114
115
116
117







-
-
+
+







	}
}

- (void)of_removeObject: (id)object
	 fileDescriptor: (int)fd
		 events: (short)events
{
	struct pollfd *FDs = [_FDs items];
	size_t nFDs = [_FDs count];
	struct pollfd *FDs = _FDs.mutableItems;
	size_t nFDs = _FDs.count;

	for (size_t i = 0; i < nFDs; i++) {
		if (FDs[i].fd == fd) {
			FDs[i].events &= ~events;

			if (FDs[i].events == 0) {
				/*
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
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







-
+






-
+






-
+






-
+














-
-
+
+







		}
	}
}

- (void)of_addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self of_addObject: object
	    fileDescriptor: [object fileDescriptorForReading]
	    fileDescriptor: object.fileDescriptorForReading
		    events: POLLIN];
}

- (void)of_addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self of_addObject: object
	    fileDescriptor: [object fileDescriptorForWriting]
	    fileDescriptor: object.fileDescriptorForWriting
		    events: POLLOUT];
}

- (void)of_removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self of_removeObject: object
	       fileDescriptor: [object fileDescriptorForReading]
	       fileDescriptor: object.fileDescriptorForReading
		       events: POLLIN];
}

- (void)of_removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self of_removeObject: object
	       fileDescriptor: [object fileDescriptorForWriting]
	       fileDescriptor: object.fileDescriptorForWriting
		       events: POLLOUT];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	struct pollfd *FDs;
	int events;
	size_t nFDs;

	[self of_processQueue];

	if ([self of_processReadBuffers])
		return;

	FDs = [_FDs items];
	nFDs = [_FDs count];
	FDs = _FDs.mutableItems;
	nFDs = _FDs.count;

#ifdef OPEN_MAX
	if (nFDs > OPEN_MAX)
		@throw [OFOutOfRangeException exception];
#endif

	events = poll(FDs, (nfds_t)nFDs,

Modified src/OFKernelEventObserver_select.m from [30b2a6d54f] to [02729f3714].

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







-
+
















-
+

















-
+



















-
+
















-
+







- (instancetype)init
{
	self = [super init];

#ifndef OF_WINDOWS
	if (_cancelFD[0] >= (int)FD_SETSIZE)
		@throw [OFInitializationFailedException
		    exceptionWithClass: [self class]];
		    exceptionWithClass: self.class];
#endif

	FD_ZERO(&_readFDs);
	FD_ZERO(&_writeFDs);
	FD_SET(_cancelFD[0], &_readFDs);

	if (_cancelFD[0] > INT_MAX)
		@throw [OFOutOfRangeException exception];

	_maxFD = (int)_cancelFD[0];

	return self;
}

- (void)of_addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	int fd = [object fileDescriptorForReading];
	int fd = object.fileDescriptorForReading;

	if (fd < 0 || fd > INT_MAX - 1)
		@throw [OFOutOfRangeException exception];

#ifndef OF_WINDOWS
	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	if (fd > _maxFD)
		_maxFD = fd;

	FD_SET((of_socket_t)fd, &_readFDs);
}

- (void)of_addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	int fd = [object fileDescriptorForWriting];
	int fd = object.fileDescriptorForWriting;

	if (fd < 0 || fd > INT_MAX - 1)
		@throw [OFOutOfRangeException exception];

#ifndef OF_WINDOWS
	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	if (fd > _maxFD)
		_maxFD = fd;

	FD_SET((of_socket_t)fd, &_writeFDs);
}

- (void)of_removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	/* TODO: Adjust _maxFD */

	int fd = [object fileDescriptorForReading];
	int fd = object.fileDescriptorForReading;

	if (fd < 0)
		@throw [OFOutOfRangeException exception];

#ifndef OF_WINDOWS
	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	FD_CLR((of_socket_t)fd, &_readFDs);
}

- (void)of_removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	/* TODO: Adjust _maxFD */

	int fd = [object fileDescriptorForWriting];
	int fd = object.fileDescriptorForWriting;

	if (fd < 0)
		@throw [OFOutOfRangeException exception];

#ifndef OF_WINDOWS
	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
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
213
214
215
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
213
214
215







-
-
+
+













-
-
+
+







		OF_ENSURE(read(_cancelFD[0], &buffer, 1) == 1);
#else
		OF_ENSURE(recvfrom(_cancelFD[0], (void *)&buffer, 1, 0, NULL,
		    NULL) == 1);
#endif
	}

	objects = [_readObjects objects];
	count = [_readObjects count];
	objects = _readObjects.objects;
	count = _readObjects.count;

	for (size_t i = 0; i < count; i++) {
		void *pool = objc_autoreleasePoolPush();
		int fd = [objects[i] fileDescriptorForReading];

		if (FD_ISSET((of_socket_t)fd, &readFDs) &&
		    [_delegate respondsToSelector:
		    @selector(objectIsReadyForReading:)])
			[_delegate objectIsReadyForReading: objects[i]];

		objc_autoreleasePoolPop(pool);
	}

	objects = [_writeObjects objects];
	count = [_writeObjects count];
	objects = _writeObjects.objects;
	count = _writeObjects.count;

	for (size_t i = 0; i < count; i++) {
		void *pool = objc_autoreleasePoolPush();
		int fd = [objects[i] fileDescriptorForWriting];

		if (FD_ISSET((of_socket_t)fd, &writeFDs) &&
		    [_delegate respondsToSelector:

Modified src/OFLHAArchive.h from [08a1644703] to [667a6061aa].

27
28
29
30
31
32
33
34

35
36
37
38
39
40
41

42
43
44
45
46
47
48
27
28
29
30
31
32
33

34
35
36
37
38
39
40

41
42
43
44
45
46
47
48







-
+






-
+







/*!
 * @class OFLHAArchive OFLHAArchive.h ObjFW/OFLHAArchive.h
 *
 * @brief A class for accessing and manipulating LHA files.
 */
@interface OFLHAArchive: OFObject
{
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	enum {
		OF_LHA_ARCHIVE_MODE_READ,
		OF_LHA_ARCHIVE_MODE_WRITE,
		OF_LHA_ARCHIVE_MODE_APPEND
	} _mode;
	of_string_encoding_t _encoding;
	OF_KINDOF(OFStream *) _Nullable _lastReturnedStream;
	OFStream *_Nullable _lastReturnedStream;
}

/*!
 * @brief The encoding to use for the archive. Defaults to ISO 8859-1.
 */
@property (nonatomic) of_string_encoding_t encoding;

63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77







-
+







 * @param stream A stream from which the LHA archive will be read.
 *		 For read and append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the LHA file. Valid modes are "r" for reading,
 *	       "w" for creating a new file and "a" for appending to an existing
 *	       archive.
 * @return A new, autoreleased OFLHAArchive
 */
+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)archiveWithStream: (OFStream *)stream
			     mode: (OFString *)mode;

#ifdef OF_HAVE_FILES
/*!
 * @brief Creates a new OFLHAArchive object with the specified file.
 *
 * @param path The path to the LHA file
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107







-
+







 * @param stream A stream from which the LHA archive will be read.
 *		 For read and append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the LHA file. Valid modes are "r" for reading,
 *	       "w" for creating a new file and "a" for appending to an existing
 *	       archive.
 * @return An initialized OFLHAArchive
 */
- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode OF_DESIGNATED_INITIALIZER;

#ifdef OF_HAVE_FILES
/*!
 * @brief Initializes an already allocated OFLHAArchive object with the
 *	  specified file.
 *

Modified src/OFLHAArchive.m from [9fc92038be] to [12097984b6].

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







-
-
+
+






-
+








-
+





-
+







-
+




















-
+







#import "OFNotOpenException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFWriteFailedException.h"

@interface OFLHAArchive_FileReadStream: OFStream <OFReadyForReadingObserving>
{
	OF_KINDOF(OFStream *) _stream;
	OF_KINDOF(OFStream *) _decompressedStream;
	OFStream *_stream;
	OFStream *_decompressedStream;
	OFLHAArchiveEntry *_entry;
	uint32_t _toRead, _bytesConsumed;
	uint16_t _CRC16;
	bool _atEndOfStream, _skipped;
}

- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFStream *)stream
			    entry: (OFLHAArchiveEntry *)entry;
- (void)of_skip;
@end

@interface OFLHAArchive_FileWriteStream: OFStream <OFReadyForWritingObserving>
{
	OFMutableLHAArchiveEntry *_entry;
	of_string_encoding_t _encoding;
	OF_KINDOF(OFStream *) _stream;
	OFSeekableStream *_stream;
	of_offset_t _headerOffset;
	uint32_t _bytesWritten;
	uint16_t _CRC16;
}

- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFSeekableStream *)stream
			    entry: (OFLHAArchiveEntry *)entry
			 encoding: (of_string_encoding_t)encoding;
@end

@implementation OFLHAArchive
@synthesize encoding = _encoding;

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)archiveWithStream: (OFStream *)stream
			     mode: (OFString *)mode
{
	return [[[self alloc] initWithStream: stream
					mode: mode] autorelease];
}

#ifdef OF_HAVE_FILES
+ (instancetype)archiveWithPath: (OFString *)path
			   mode: (OFString *)mode
{
	return [[[self alloc] initWithPath: path
				      mode: mode] autorelease];
}
#endif

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode
{
	self = [super init];

	@try {
		_stream = [stream retain];

111
112
113
114
115
116
117
118
119


120
121
122
123
124
125
126
111
112
113
114
115
116
117


118
119
120
121
122
123
124
125
126







-
-
+
+








		if ((_mode == OF_LHA_ARCHIVE_MODE_WRITE ||
		    _mode == OF_LHA_ARCHIVE_MODE_APPEND) &&
		    ![_stream isKindOfClass: [OFSeekableStream class]])
			@throw [OFInvalidArgumentException exception];

		if (_mode == OF_LHA_ARCHIVE_MODE_APPEND)
			[_stream seekToOffset: 0
				       whence: SEEK_END];
			[(OFSeekableStream *)_stream seekToOffset: 0
							   whence: SEEK_END];

		_encoding = OF_STRING_ENCODING_ISO_8859_1;
	} @catch (id e) {
		[self release];
		@throw e;
	}

163
164
165
166
167
168
169
170

171
172
173
174
175
176

177
178
179
180
181
182
183
163
164
165
166
167
168
169

170
171
172
173
174
175

176
177
178
179
180
181
182
183







-
+





-
+







	OFLHAArchiveEntry *entry;
	char header[21];
	size_t headerLen;

	if (_mode != OF_LHA_ARCHIVE_MODE_READ)
		@throw [OFInvalidArgumentException exception];

	[_lastReturnedStream of_skip];
	[(OFLHAArchive_FileReadStream *)_lastReturnedStream of_skip];
	[_lastReturnedStream close];
	[_lastReturnedStream release];
	_lastReturnedStream = nil;

	for (headerLen = 0; headerLen < 21;) {
		if ([_stream isAtEndOfStream]) {
		if (_stream.atEndOfStream) {
			if (headerLen == 0)
				return nil;

			if (headerLen == 1 && header[0] == 0)
				return nil;

			@throw [OFTruncatedDataException exception];
203
204
205
206
207
208
209

210

211
212
213
214
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
232
233
234

235
236
237

238

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256

257
258
259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
203
204
205
206
207
208
209
210

211
212
213
214
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
232
233
234

235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264
265
266
267

268
269
270
271
272
273
274
275







+
-
+











-
+











-
+



+
-
+

















-
+









-
+







{
	if (_mode != OF_LHA_ARCHIVE_MODE_READ)
		@throw [OFInvalidArgumentException exception];

	if (_lastReturnedStream == nil)
		@throw [OFInvalidArgumentException exception];

	return [[(OFLHAArchive_FileReadStream *)_lastReturnedStream
	return [[_lastReturnedStream retain] autorelease];
	    retain] autorelease];
}

- (OFStream <OFReadyForWritingObserving> *)
    streamForWritingEntry: (OFLHAArchiveEntry *)entry
{
	OFString *compressionMethod;

	if (_mode != OF_LHA_ARCHIVE_MODE_WRITE &&
	    _mode != OF_LHA_ARCHIVE_MODE_APPEND)
		@throw [OFInvalidArgumentException exception];

	compressionMethod = [entry compressionMethod];
	compressionMethod = entry.compressionMethod;

	if (![compressionMethod isEqual: @"-lh0-"] &&
	    ![compressionMethod isEqual: @"-lhd-"])
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	[_lastReturnedStream close];
	[_lastReturnedStream release];
	_lastReturnedStream = nil;

	_lastReturnedStream = [[OFLHAArchive_FileWriteStream alloc]
	    of_initWithStream: _stream
	    of_initWithStream: (OFSeekableStream *)_stream
			entry: entry
		     encoding: _encoding];

	return [[(OFLHAArchive_FileWriteStream *)_lastReturnedStream
	return [[_lastReturnedStream retain] autorelease];
	    retain] autorelease];
}

- (void)close
{
	if (_stream == nil)
		return;

	[_lastReturnedStream close];
	[_lastReturnedStream release];
	_lastReturnedStream = nil;

	[_stream release];
	_stream = nil;
}
@end

@implementation OFLHAArchive_FileReadStream
- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFStream *)stream
			    entry: (OFLHAArchiveEntry *)entry
{
	self = [super init];

	@try {
		OFString *compressionMethod;

		_stream = [stream retain];

		compressionMethod = [entry compressionMethod];
		compressionMethod = entry.compressionMethod;

		if ([compressionMethod isEqual: @"-lh4-"] ||
		    [compressionMethod isEqual: @"-lh5-"])
			_decompressedStream = [[OFLHAArchive_LHStream alloc]
			    of_initWithStream: stream
				 distanceBits: 4
			       dictionaryBits: 14];
281
282
283
284
285
286
287
288

289
290
291
292
293
294
295
283
284
285
286
287
288
289

290
291
292
293
294
295
296
297







-
+







			    of_initWithStream: stream
				 distanceBits: 5
			       dictionaryBits: 17];
		else
			_decompressedStream = [stream retain];

		_entry = [entry copy];
		_toRead = [entry uncompressedSize];
		_toRead = entry.uncompressedSize;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
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
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







-
-
+














-
+



-
+












-
-
+
+




+
-
+




-
+














-
+
+


-
+






-
-
+
+








	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (_atEndOfStream)
		return 0;

	if ([_stream isAtEndOfStream] &&
	    ![_decompressedStream hasDataInReadBuffer])
	if (_stream.atEndOfStream && !_decompressedStream.hasDataInReadBuffer)
		@throw [OFTruncatedDataException exception];

	if (length > _toRead)
		length = _toRead;

	ret = [_decompressedStream readIntoBuffer: buffer
					   length: length];

	_toRead -= ret;
	_CRC16 = of_crc16(_CRC16, buffer, ret);

	if (_toRead == 0) {
		_atEndOfStream = true;

		if (_CRC16 != [_entry CRC16]) {
		if (_CRC16 != _entry.CRC16) {
			OFString *actualChecksum = [OFString stringWithFormat:
			    @"%04" PRIX16, _CRC16];
			OFString *expectedChecksum = [OFString stringWithFormat:
			    @"%04" PRIX16, [_entry CRC16]];
			    @"%04" PRIX16, _entry.CRC16];

			@throw [OFChecksumMismatchException
			    exceptionWithActualChecksum: actualChecksum
				       expectedChecksum: expectedChecksum];
		}
	}

	return ret;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] ||
	    [_decompressedStream hasDataInReadBuffer]);
	return (super.hasDataInReadBuffer ||
	    _decompressedStream.hasDataInReadBuffer);
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_decompressedStream)
	return [_decompressedStream fileDescriptorForReading];
	    .fileDescriptorForReading;
}

- (void)of_skip
{
	OF_KINDOF(OFStream *) stream;
	OFStream *stream;
	uint32_t toRead;

	if (_stream == nil || _skipped)
		return;

	stream = _stream;
	toRead = _toRead;

	/*
	 * Get the number of consumed bytes and directly read from the
	 * compressed stream, to make skipping much faster.
	 */
	if ([_decompressedStream isKindOfClass:
	    [OFLHAArchive_LHStream class]]) {
		OFLHAArchive_LHStream *LHStream = _decompressedStream;
		OFLHAArchive_LHStream *LHStream =
		    (OFLHAArchive_LHStream *)_decompressedStream;

		[LHStream close];
		toRead = [_entry compressedSize] - LHStream->_bytesConsumed;
		toRead = _entry.compressedSize - LHStream->_bytesConsumed;

		stream = _stream;
	}

	if ([stream isKindOfClass: [OFSeekableStream class]] &&
	    (sizeof(of_offset_t) > 4 || toRead < INT32_MAX))
		[stream seekToOffset: (of_offset_t)toRead
			      whence: SEEK_CUR];
		[(OFSeekableStream *)stream seekToOffset: (of_offset_t)toRead
						  whence: SEEK_CUR];
	else {
		while (toRead > 0) {
			char buffer[512];
			size_t min = toRead;

			if (min > 512)
				min = 512;
423
424
425
426
427
428
429
430

431
432
433
434
435
436
437
426
427
428
429
430
431
432

433
434
435
436
437
438
439
440







-
+







	_decompressedStream = nil;

	[super close];
}
@end

@implementation OFLHAArchive_FileWriteStream
- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFSeekableStream *)stream
			    entry: (OFLHAArchiveEntry *)entry
			 encoding: (of_string_encoding_t)encoding
{
	self = [super init];

	@try {
		_entry = [entry mutableCopy];
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
516



517
518
519
520
521
522
523
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
516
517



518
519
520
521
522
523
524
525
526
527







-
-
+
+















-
+




+
-
+









-
-
-
+
+
+







	if (UINT32_MAX - _bytesWritten < length)
		@throw [OFOutOfRangeException exception];

	@try {
		bytesWritten = (uint32_t)[_stream writeBuffer: buffer
						       length: length];
	} @catch (OFWriteFailedException *e) {
		_bytesWritten += [e bytesWritten];
		_CRC16 = of_crc16(_CRC16, buffer, [e bytesWritten]);
		_bytesWritten += e.bytesWritten;
		_CRC16 = of_crc16(_CRC16, buffer, e.bytesWritten);

		@throw e;
	}

	_bytesWritten += (uint32_t)bytesWritten;
	_CRC16 = of_crc16(_CRC16, buffer, bytesWritten);

	return bytesWritten;
}

- (bool)lowlevelIsAtEndOfStream
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return [_stream isAtEndOfStream];
	return _stream.atEndOfStream;
}

- (int)fileDescriptorForWriting
{
	return ((id <OFReadyForWritingObserving>)_stream)
	return [_stream fileDescriptorForWriting];
	    .fileDescriptorForWriting;
}

- (void)close
{
	of_offset_t offset;

	if (_stream == nil)
		return;

	[_entry setUncompressedSize: _bytesWritten];
	[_entry setCompressedSize: _bytesWritten];
	[_entry setCRC16: _CRC16];
	_entry.uncompressedSize = _bytesWritten;
	_entry.compressedSize = _bytesWritten;
	_entry.CRC16 = _CRC16;

	offset = [_stream seekToOffset: 0
				whence:SEEK_CUR];
	[_stream seekToOffset: _headerOffset
		       whence: SEEK_SET];
	[_entry of_writeToStream: _stream
			encoding: _encoding];

Modified src/OFLHAArchiveEntry.m from [000c2ce28c] to [436ef99699].

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







-
+










-
-
+
+







parseFileNameExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	[entry->_fileName release];
	entry->_fileName = nil;

	entry->_fileName = [[OFString alloc]
	    initWithCString: (char *)[extension items] + 1
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: [extension count] - 1];
}

static void
parseDirectoryNameExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableData *data = [[extension mutableCopy] autorelease];
	char *items = [data items];
	size_t count = [data count];
	char *items = data.mutableItems;
	size_t count = data.count;
	OFMutableString *directoryName;

	for (size_t i = 1; i < count; i++)
		if (items[i] == '\xFF')
			items[i] = '/';

	directoryName = [OFMutableString stringWithCString: items + 1
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

183
184
185
186
187
188
189
190
191

192
193
194

195
196
197
198
199
200
201
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
183
184
185
186
187
188
189
190

191
192
193

194
195
196
197
198
199
200
201







-
+

-
+








-
+


-
+














-
+


-
+


-
+




















-
+

-
+










-
+

-
+








-
+


-
+







parseCommentExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	[entry->_fileComment release];
	entry->_fileComment = nil;

	entry->_fileComment = [[OFString alloc]
	    initWithCString: (char *)[extension items] + 1
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: [extension count] - 1];
		     length: extension.count - 1];
}

static void
parsePermissionsExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	uint16_t mode;

	if ([extension count] != 3)
	if (extension.count != 3)
		@throw [OFInvalidFormatException exception];

	memcpy(&mode, (char *)[extension items] + 1, 2);
	memcpy(&mode, (char *)extension.items + 1, 2);
	mode = OF_BSWAP16_IF_BE(mode);

	[entry->_mode release];
	entry->_mode = nil;

	entry->_mode = [[OFNumber alloc] initWithUInt16: mode];
}

static void
parseGIDUIDExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	uint16_t UID, GID;

	if ([extension count] != 5)
	if (extension.count != 5)
		@throw [OFInvalidFormatException exception];

	memcpy(&GID, (char *)[extension items] + 1, 2);
	memcpy(&GID, (char *)extension.items + 1, 2);
	GID = OF_BSWAP16_IF_BE(GID);

	memcpy(&UID, (char *)[extension items] + 3, 2);
	memcpy(&UID, (char *)extension.items + 3, 2);
	UID = OF_BSWAP16_IF_BE(UID);

	[entry->_GID release];
	entry->_GID = nil;

	[entry->_UID release];
	entry->_UID = nil;

	entry->_GID = [[OFNumber alloc] initWithUInt16: GID];
	entry->_UID = [[OFNumber alloc] initWithUInt16: UID];
}

static void
parseGroupExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	[entry->_group release];
	entry->_group = nil;

	entry->_group = [[OFString alloc]
	    initWithCString: (char *)[extension items] + 1
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: [extension count] - 1];
		     length: extension.count - 1];
}

static void
parseOwnerExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	[entry->_owner release];
	entry->_owner = nil;

	entry->_owner = [[OFString alloc]
	    initWithCString: (char *)[extension items] + 1
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: [extension count] - 1];
		     length: extension.count - 1];
}

static void
parseModificationDateExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
{
	uint32_t modificationDate;

	if ([extension count] != 5)
	if (extension.count != 5)
		@throw [OFInvalidFormatException exception];

	memcpy(&modificationDate, (char *)[extension items] + 1, 4);
	memcpy(&modificationDate, (char *)extension.items + 1, 4);
	modificationDate = OF_BSWAP32_IF_BE(modificationDate);

	[entry->_modificationDate release];
	entry->_modificationDate = nil;

	entry->_modificationDate = [[OFDate alloc]
	    initWithTimeIntervalSince1970: modificationDate];
287
288
289
290
291
292
293
294
295


296
297
298
299
300
301
302
287
288
289
290
291
292
293


294
295
296
297
298
299
300
301
302







-
-
+
+







	data = [OFMutableData
	    dataWithItems: [entry->_directoryName cStringWithEncoding: encoding]
		    count: [entry->_directoryName
			       cStringLengthWithEncoding: encoding]];
	[data addItems: [entry->_fileName cStringWithEncoding: encoding]
		 count: [entry->_fileName cStringLengthWithEncoding: encoding]];

	cString = [data items];
	length = [data count];
	cString = data.mutableItems;
	length = data.count;
	pos = 0;

	for (size_t i = 0; i < length; i++) {
		if (cString[i] == '/' || cString[i] == '\\') {
			cString[i] = '\xFF';
			pos = i + 1;
		}
591
592
593
594
595
596
597
598

599
600
601
602
603
604
605
591
592
593
594
595
596
597

598
599
600
601
602
603
604
605







-
+







	[data addItems: &tmp32
		 count: sizeof(tmp32)];

	tmp32 = OF_BSWAP32_IF_BE(_uncompressedSize);
	[data addItems: &tmp32
		 count: sizeof(tmp32)];

	tmp32 = OF_BSWAP32_IF_BE((uint32_t)[_date timeIntervalSince1970]);
	tmp32 = OF_BSWAP32_IF_BE((uint32_t)_date.timeIntervalSince1970);
	[data addItems: &tmp32
		 count: sizeof(tmp32)];

	/* Reserved */
	[data increaseCountBy: 1];

	/* Header level */
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
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







-
+













-
+



-
+








	if (_mode != nil) {
		tmp16 = OF_BSWAP16_IF_BE(5);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];
		[data addItem: "\x50"];

		tmp16 = OF_BSWAP16_IF_BE([_mode uInt16Value]);
		tmp16 = OF_BSWAP16_IF_BE(_mode.uInt16Value);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];
	}

	if (_UID != nil || _GID != nil) {
		if (_UID == nil || _GID == nil)
			@throw [OFInvalidArgumentException exception];

		tmp16 = OF_BSWAP16_IF_BE(7);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];
		[data addItem: "\x51"];

		tmp16 = OF_BSWAP16_IF_BE([_GID uInt16Value]);
		tmp16 = OF_BSWAP16_IF_BE(_GID.uInt16Value);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];

		tmp16 = OF_BSWAP16_IF_BE([_UID uInt16Value]);
		tmp16 = OF_BSWAP16_IF_BE(_UID.uInt16Value);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];
	}

	if (_group != nil) {
		size_t groupLength =
		    [_group cStringLengthWithEncoding: encoding];
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
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







-
+





-
+

-
+








-
-
+
+





-
+






-
+

+
-
-
+
+









-
+
-
-
-
+
+







	if (_modificationDate != nil) {
		tmp16 = OF_BSWAP16_IF_BE(7);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];
		[data addItem: "\x54"];

		tmp32 = OF_BSWAP32_IF_BE(
		    (uint32_t)[_modificationDate timeIntervalSince1970]);
		    (uint32_t)_modificationDate.timeIntervalSince1970);
		[data addItems: &tmp32
			 count: sizeof(tmp32)];
	}

	for (OFData *extension in _extensions) {
		size_t extensionLength = [extension count];
		size_t extensionLength = extension.count;

		if ([extension itemSize] != 1)
		if (extension.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		if (extensionLength > UINT16_MAX - 2)
			@throw [OFOutOfRangeException exception];

		tmp16 = OF_BSWAP16_IF_BE((uint16_t)extensionLength + 2);
		[data addItems: &tmp16
			 count: sizeof(tmp16)];
		[data addItems: [extension items]
			 count: [extension count]];
		[data addItems: extension.items
			 count: extension.count];
	}

	/* Zero-length extension to terminate */
	[data increaseCountBy: 2];

	headerSize = [data count];
	headerSize = data.count;

	if (headerSize > UINT16_MAX)
		@throw [OFOutOfRangeException exception];

	/* Now fill in the size and CRC16 for the entire header */
	tmp16 = OF_BSWAP16_IF_BE(headerSize);
	memcpy([data itemAtIndex: 0], &tmp16, sizeof(tmp16));
	memcpy([data mutableItemAtIndex: 0], &tmp16, sizeof(tmp16));

	tmp16 = of_crc16(0, data.items, data.count);
	tmp16 = OF_BSWAP16_IF_BE(of_crc16(0, [data items], [data count]));
	memcpy([data itemAtIndex: 27], &tmp16, sizeof(tmp16));
	tmp16 = OF_BSWAP16_IF_BE(tmp16);
	memcpy([data mutableItemAtIndex: 27], &tmp16, sizeof(tmp16));

	[stream writeData: data];

	objc_autoreleasePoolPop(pool);
}

- (OFString *)description
{
	void *pool = objc_autoreleasePoolPush();
	OFString *mode = (_mode == nil
	OFString *mode = (_mode == nil ? nil
	    ? nil
	    : [OFString stringWithFormat: @"%" PRIo16, [_mode uInt16Value]]);
	OFString *extensions = [[_extensions description]
	    : [OFString stringWithFormat: @"%" PRIo16, _mode.uInt16Value]);
	OFString *extensions = [_extensions.description
	    stringByReplacingOccurrencesOfString: @"\n"
				      withString: @"\n\t"];
	OFString *ret = [OFString stringWithFormat:
	    @"<%@:\n"
	    @"\tFile name = %@\n"
	    @"\tCompression method = %@\n"
	    @"\tCompressed size = %" @PRIu32 "\n"
782
783
784
785
786
787
788
789

790
791
792
793
794
795
796
797
798
799
800
782
783
784
785
786
787
788

789
790
791
792
793
794
795
796
797
798
799
800







-
+











	    @"\tUID = %@\n"
	    @"\tGID = %@\n"
	    @"\tOwner = %@\n"
	    @"\tGroup = %@\n"
	    @"\tModification date = %@\n"
	    @"\tExtensions: %@"
	    @">",
	    [self class], [self fileName], _compressionMethod, _compressedSize,
	    self.class, self.fileName, _compressionMethod, _compressedSize,
	    _uncompressedSize, _date, _headerLevel, _CRC16,
	    _operatingSystemIdentifier, _fileComment, mode, _UID, _GID, _owner,
	    _group, _modificationDate, extensions];

	[ret retain];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}
@end

Modified src/OFLHAArchive_LHStream.h from [40128881b3] to [3e10c9b21e].

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







-
+




















-
+





OF_ASSUME_NONNULL_BEGIN

#define OF_LHA_ARCHIVE_LHSTREAM_BUFFER_SIZE 4096

@interface OFLHAArchive_LHStream: OFStream
{
@public
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	uint8_t _distanceBits, _dictionaryBits;
	unsigned char _buffer[OF_LHA_ARCHIVE_LHSTREAM_BUFFER_SIZE];
	uint32_t _bytesConsumed;
	uint16_t _bufferIndex, _bufferLength;
	uint8_t _byte;
	uint8_t _bitIndex, _savedBitsLength;
	uint16_t _savedBits;
	unsigned char *_slidingWindow;
	uint32_t _slidingWindowIndex, _slidingWindowMask;
	int _state;
	uint16_t _symbolsLeft;
	struct of_huffman_tree *_Nullable _codeLenTree, *_Nullable _litLenTree;
	struct of_huffman_tree *_Nullable _distTree, *_Nullable _treeIter;
	uint16_t _codesCount, _codesReceived;
	bool _currentIsExtendedLength, _skip;
	uint8_t *_Nullable _codesLengths;
	uint16_t _length;
	uint32_t _distance;
}

- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFStream *)stream
		     distanceBits: (uint8_t)distanceBits
		   dictionaryBits: (uint8_t)dictionaryBits;
@end

OF_ASSUME_NONNULL_END

Modified src/OFLHAArchive_LHStream.m from [3034f7c67e] to [8ad89a82c7].

86
87
88
89
90
91
92
93

94
95
96
97
98
99
100
86
87
88
89
90
91
92

93
94
95
96
97
98
99
100







-
+







	stream->_savedBitsLength = 0;
	*bits = ret;

	return true;
}

@implementation OFLHAArchive_LHStream
- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFStream *)stream
		     distanceBits: (uint8_t)distanceBits
		   dictionaryBits: (uint8_t)dictionaryBits
{
	self = [super init];

	@try {
		_stream = [stream retain];
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151







-
+







	unsigned char *buffer = buffer_;
	uint16_t bits, value;
	size_t bytesWritten = 0;

	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	if ([_stream isAtEndOfStream] && _bufferLength - _bufferIndex == 0 &&
	if (_stream.atEndOfStream && _bufferLength - _bufferIndex == 0 &&
	    _state == STATE_BLOCK_HEADER)
		return 0;

start:
	switch ((enum state)_state) {
	case STATE_BLOCK_HEADER:
		if OF_UNLIKELY (!tryReadBits(self, &bits, 16))
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
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
516







-
+





+
-
+




-
+







}

- (bool)lowlevelIsAtEndOfStream
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return ([_stream isAtEndOfStream] &&
	return (_stream.atEndOfStream &&
	    _bufferLength - _bufferIndex == 0 && _state == STATE_BLOCK_HEADER);
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	return [_stream fileDescriptorForReading];
	    .fileDescriptorForReading;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer] ||
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer ||
	    _bufferLength - _bufferIndex > 0);
}

- (void)close
{
	/* Give back our buffer to the stream, in case it's shared */
	[_stream unreadFromBuffer: _buffer + _bufferIndex

Modified src/OFList.m from [f9d90df6d5] to [b8390d9c24].

40
41
42
43
44
45
46
47
48


49
50
51
52
53
54
55

56
57
58
59
60
61
62
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62







-
-
+
+






-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		for (OFXMLElement *child in
		    [element elementsForNamespace: OF_SERIALIZATION_NS]) {
			void *pool2 = objc_autoreleasePoolPush();

			[self appendObject: [child objectByDeserializing]];
			[self appendObject: child.objectByDeserializing];

			objc_autoreleasePoolPop(pool2);
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
212
213
214
215
216
217
218
219

220
221
222

223
224
225
226
227
228
229
212
213
214
215
216
217
218

219
220
221

222
223
224
225
226
227
228
229







-
+


-
+







		return true;

	if (![object isKindOfClass: [OFList class]])
		return false;

	list = object;

	if ([list count] != _count)
	if (list.count != _count)
		return false;

	for (iter = _firstListObject, iter2 = [list firstListObject];
	for (iter = _firstListObject, iter2 = list.firstListObject;
	    iter != NULL && iter2 != NULL;
	    iter = iter->next, iter2 = iter2->next)
		if (![iter->object isEqual: iter2->object])
			return false;

	/* One is bigger than the other even though we checked the count */
	assert(iter == NULL && iter2 == NULL);
352
353
354
355
356
357
358
359

360
361
362
363
364
365
366
352
353
354
355
356
357
358

359
360
361
362
363
364
365
366







-
+








	return ret;
}

- (OFXMLElement *)XMLElementBySerializing
{
	OFXMLElement *element =
	    [OFXMLElement elementWithName: [self className]
	    [OFXMLElement elementWithName: self.className
				namespace: OF_SERIALIZATION_NS];

	for (of_list_object_t *iter = _firstListObject;
	    iter != NULL; iter = iter->next) {
		void *pool = objc_autoreleasePoolPush();

		[element addChild: [iter->object XMLElementBySerializing]];
411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
411
412
413
414
415
416
417

418
419
420
421
422
423
424
425







-
+







@implementation OFListEnumerator
- (instancetype)initWithList: (OFList *)list
	    mutationsPointer: (unsigned long *)mutationsPtr
{
	self = [super init];

	_list = [list retain];
	_current = [list firstListObject];
	_current = _list.firstListObject;
	_mutations = *mutationsPtr;
	_mutationsPtr = mutationsPtr;

	return self;
}

- (void)dealloc
448
449
450
451
452
453
454
455

456
457
448
449
450
451
452
453
454

455
456
457







-
+



- (void)reset
{
	if (*_mutationsPtr != _mutations)
		@throw [OFEnumerationMutationException
		    exceptionWithObject: _list];

	_current = [_list firstListObject];
	_current = _list.firstListObject;
}
@end

Modified src/OFLocale.m from [076e9d8203] to [eba1e0de33].

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
183
184
185
186
187

188
189
190
191
192
193
194
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
183
184
185
186

187
188
189
190
191
192
193
194







-
+




-
+




-
+




-
+



















-
+







+ (OFLocale *)currentLocale
{
	return currentLocale;
}

+ (OFString *)language
{
	return [currentLocale language];
	return currentLocale.language;
}

+ (OFString *)territory
{
	return [currentLocale territory];
	return currentLocale.territory;
}

+ (of_string_encoding_t)encoding
{
	return [currentLocale encoding];
	return currentLocale.encoding;
}

+ (OFString *)decimalPoint
{
	return [currentLocale decimalPoint];
	return currentLocale.decimalPoint;
}

#ifdef OF_HAVE_FILES
+ (void)addLanguageDirectory: (OFString *)path
{
	[currentLocale addLanguageDirectory: path];
}
#endif

- (instancetype)init
{
	self = [super init];

	@try {
#ifndef OF_AMIGAOS
		char *locale, *messagesLocale = NULL;

		if (currentLocale != nil)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		_encoding = OF_STRING_ENCODING_UTF_8;
		_decimalPoint = @".";
		_localizedStrings = [[OFMutableArray alloc] init];

		if ((locale = setlocale(LC_ALL, "")) != NULL)
			_decimalPoint = [[OFString alloc]
319
320
321
322
323
324
325
326
327


328
329
330
331
332
333
334

335
336
337
338
339
340
341
342
319
320
321
322
323
324
325


326
327
328
329
330
331
332
333

334

335
336
337
338
339
340
341







-
-
+
+






-
+
-







	@try {
		map = [[OFString stringWithContentsOfFile: mapPath] JSONValue];
	} @catch (OFOpenItemFailedException *e) {
		objc_autoreleasePoolPop(pool);
		return;
	}

	language = [_language lowercaseString];
	territory = [_territory lowercaseString];
	language = _language.lowercaseString;
	territory = _territory.lowercaseString;

	if (territory == nil)
		territory = @"";

	languageFile = [[map objectForKey: language] objectForKey: territory];
	if (languageFile == nil)
		languageFile = [[map objectForKey: language]
		languageFile = [[map objectForKey: language] objectForKey: @""];
		    objectForKey: @""];

	if (languageFile == nil) {
		objc_autoreleasePoolPop(pool);
		return;
	}

	languageFile = [path stringByAppendingPathComponent:
385
386
387
388
389
390
391
392
393


394
395
396
397
398
399
400
384
385
386
387
388
389
390


391
392
393
394
395
396
397
398
399







-
-
+
+








		UTF8String = [string UTF8String];
		UTF8StringLength = [string UTF8StringLength];
		break;
	}

	if (UTF8String == NULL) {
		UTF8String = [fallback UTF8String];
		UTF8StringLength = [fallback UTF8StringLength];
		UTF8String = fallback.UTF8String;
		UTF8StringLength = fallback.UTF8StringLength;
	}

	state = 0;
	last = 0;
	for (size_t i = 0; i < UTF8StringLength; i++) {
		switch (state) {
		case 0:

Modified src/OFMD5Hash.m from [7e71ee5050] to [d8543cb4a1].

140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
140
141
142
143
144
145
146

147
148
149
150
151
152
153
154







-
+







- (instancetype)init
{
	self = [super init];

	@try {
		_iVarsData = [[OFSecureData alloc]
		    initWithCount: sizeof(*_iVars)];
		_iVars = [_iVarsData items];
		_iVars = _iVarsData.mutableItems;

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

168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
168
169
170
171
172
173
174

175
176
177
178
179
180
181
182







-
+







}

- (id)copy
{
	OFMD5Hash *copy = [[OFMD5Hash alloc] of_init];

	copy->_iVarsData = [_iVarsData copy];
	copy->_iVars = [copy->_iVarsData items];
	copy->_iVars = copy->_iVarsData.mutableItems;
	copy->_calculated = _calculated;

	return copy;
}

- (void)of_resetState
{

Modified src/OFMessagePackExtension.m from [a322670b7a] to [4d6e30d967].

40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
40
41
42
43
44
45
46

47
48
49
50
51
52
53
54







-
+








- (instancetype)initWithType: (int8_t)type
			data: (OFData *)data
{
	self = [super init];

	@try {
		if (data == nil || [data itemSize] != 1)
		if (data == nil || data.itemSize != 1)
			@throw [OFInvalidArgumentException exception];

		_type = type;
		_data = [data copy];
	} @catch (id e) {
		[self release];
		@throw e;
64
65
66
67
68
69
70
71

72
73
74
75
76
77
78
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78







-
+







	[super dealloc];
}

- (OFData *)messagePackRepresentation
{
	OFMutableData *ret;
	uint8_t prefix;
	size_t count = [_data count];
	size_t count = _data.count;

	if (count == 1) {
		ret = [OFMutableData dataWithCapacity: 3];

		prefix = 0xD4;
		[ret addItem: &prefix];

141
142
143
144
145
146
147
148
149


150
151
152
153
154
155
156
141
142
143
144
145
146
147


148
149
150
151
152
153
154
155
156







-
-
+
+







		length = OF_BSWAP32_IF_LE((uint32_t)count);
		[ret addItems: &length
			count: 4];

		[ret addItem: &_type];
	}

	[ret addItems: [_data items]
		count: [_data count]];
	[ret addItems: _data.items
		count: _data.count];

	[ret makeImmutable];

	return ret;
}

- (OFString *)description
180
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195
196
197
198
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198







-
+











- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD(hash, (uint8_t)_type);
	OF_HASH_ADD_HASH(hash, [_data hash]);
	OF_HASH_ADD_HASH(hash, _data.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (id)copy
{
	return [self retain];
}
@end

Modified src/OFMethodSignature.m from [65b8b721a8] to [90270cac7b].

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







-
+




-
+




-
+












	[_offsets release];

	[super dealloc];
}

- (size_t)numberOfArguments
{
	return [_typesPointers count] - 1;
	return _typesPointers.count - 1;
}

- (const char *)methodReturnType
{
	return *(const char **)[_typesPointers firstItem];
	return *(const char **)_typesPointers.firstItem;
}

- (size_t)frameLength
{
	return *(size_t *)[_offsets firstItem];
	return *(size_t *)_offsets.firstItem;
}

- (const char *)argumentTypeAtIndex: (size_t)idx
{
	return *(const char **)[_typesPointers itemAtIndex: idx + 1];
}

- (size_t)argumentOffsetAtIndex: (size_t)idx
{
	return *(size_t *)[_offsets itemAtIndex: idx + 1];
}
@end

Modified src/OFMutableArray.m from [652f7d9468] to [d1d4c770ab].

256
257
258
259
260
261
262
263

264
265
266
267
268
269

270
271
272
273
274
275
276
256
257
258
259
260
261
262

263
264
265
266
267
268

269
270
271
272
273
274
275
276







-
+





-
+







{
	return [[OFArray alloc] initWithArray: self];
}

- (void)addObject: (id)object
{
	[self insertObject: object
		   atIndex: [self count]];
		   atIndex: self.count];
}

- (void)addObjectsFromArray: (OFArray *)array
{
	[self insertObjectsFromArray: array
			     atIndex: [self count]];
			     atIndex: self.count];
}

- (void)insertObject: (id)object
	     atIndex: (size_t)idx
{
	OF_UNRECOGNIZED_SELECTOR
}
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
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







-
+


















-
+







	   withObject: (id)newObject
{
	size_t count;

	if (oldObject == nil || newObject == nil)
		@throw [OFInvalidArgumentException exception];

	count = [self count];
	count = self.count;

	for (size_t i = 0; i < count; i++) {
		if ([[self objectAtIndex: i] isEqual: oldObject]) {
			[self replaceObjectAtIndex: i
					withObject: newObject];
			return;
		}
	}
}

- (void)replaceObjectIdenticalTo: (id)oldObject
		      withObject: (id)newObject
{
	size_t count;

	if (oldObject == nil || newObject == nil)
		@throw [OFInvalidArgumentException exception];

	count = [self count];
	count = self.count;

	for (size_t i = 0; i < count; i++) {
		if ([self objectAtIndex: i] == oldObject) {
			[self replaceObjectAtIndex: i
					withObject: newObject];

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







-
+

















-
+


















-
+









-
+







- (void)removeObject: (id)object
{
	size_t count;

	if (object == nil)
		@throw [OFInvalidArgumentException exception];

	count = [self count];
	count = self.count;

	for (size_t i = 0; i < count; i++) {
		if ([[self objectAtIndex: i] isEqual: object]) {
			[self removeObjectAtIndex: i];

			return;
		}
	}
}

- (void)removeObjectIdenticalTo: (id)object
{
	size_t count;

	if (object == nil)
		@throw [OFInvalidArgumentException exception];

	count = [self count];
	count = self.count;

	for (size_t i = 0; i < count; i++) {
		if ([self objectAtIndex: i] == object) {
			[self removeObjectAtIndex: i];

			return;
		}
	}
}

- (void)removeObjectsInRange: (of_range_t)range
{
	for (size_t i = 0; i < range.length; i++)
		[self removeObjectAtIndex: range.location];
}

- (void)removeLastObject
{
	size_t count = [self count];
	size_t count = self.count;

	if (count == 0)
		return;

	[self removeObjectAtIndex: count - 1];
}

- (void)removeAllObjects
{
	[self removeObjectsInRange: of_range(0, [self count])];
	[self removeObjectsInRange: of_range(0, self.count)];
}

#ifdef OF_HAVE_BLOCKS
- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block
{
	[self enumerateObjectsUsingBlock: ^ (id object, size_t idx,
	    bool *stop) {
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
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







-
+











-
+










-
+













	[self sortUsingSelector: @selector(compare:)
			options: 0];
}

- (void)sortUsingSelector: (SEL)selector
		  options: (int)options
{
	size_t count = [self count];
	size_t count = self.count;

	if (count == 0 || count == 1)
		return;

	quicksort(self, 0, count - 1, selector, options);
}

#ifdef OF_HAVE_BLOCKS
- (void)sortUsingComparator: (of_comparator_t)comparator
		    options: (int)options
{
	size_t count = [self count];
	size_t count = self.count;

	if (count == 0 || count == 1)
		return;

	quicksortWithBlock(self, 0, count - 1, comparator, options);
}
#endif

- (void)reverse
{
	size_t i, j, count = [self count];
	size_t i, j, count = self.count;

	if (count == 0 || count == 1)
		return;

	for (i = 0, j = count - 1; i < j; i++, j--)
		[self exchangeObjectAtIndex: i
			  withObjectAtIndex: j];
}

- (void)makeImmutable
{
}
@end

Modified src/OFMutableArray_adjacent.m from [feb12f542d] to [e7c93457b6].

76
77
78
79
80
81
82
83
84


85
86
87
88
89
90
91
76
77
78
79
80
81
82


83
84
85
86
87
88
89
90
91







-
-
+
+








	_mutations++;
}

- (void)insertObjectsFromArray: (OFArray *)array
		       atIndex: (size_t)idx
{
	id const *objects = [array objects];
	size_t count = [array count];
	id const *objects = array.objects;
	size_t count = array.count;

	@try {
		[_array insertItems: objects
			    atIndex: idx
			      count: count];
	} @catch (OFOutOfRangeException *e) {
		@throw [OFOutOfRangeException exception];
102
103
104
105
106
107
108
109
110


111
112
113
114
115
116
117
102
103
104
105
106
107
108


109
110
111
112
113
114
115
116
117







-
-
+
+







{
	id *objects;
	size_t count;

	if (oldObject == nil || newObject == nil)
		@throw [OFInvalidArgumentException exception];

	objects = [_array items];
	count = [_array count];
	objects = _array.mutableItems;
	count = _array.count;

	for (size_t i = 0; i < count; i++) {
		if ([objects[i] isEqual: oldObject]) {
			[newObject retain];
			[objects[i] release];
			objects[i] = newObject;

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
183
184
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199


200
201
202
203
204
205
206
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
183
184
185
186
187
188
189
190
191

192
193
194
195
196
197


198
199
200
201
202
203
204
205
206







-
+

-
+
















-
-
+
+














-
+





-
-
+
+

















-
+





-
-
+
+







{
	id *objects;
	id oldObject;

	if (object == nil)
		@throw [OFInvalidArgumentException exception];

	objects = [_array items];
	objects = _array.mutableItems;

	if (idx >= [_array count])
	if (idx >= _array.count)
		@throw [OFOutOfRangeException exception];

	oldObject = objects[idx];
	objects[idx] = [object retain];
	[oldObject release];
}

- (void)replaceObjectIdenticalTo: (id)oldObject
		      withObject: (id)newObject
{
	id *objects;
	size_t count;

	if (oldObject == nil || newObject == nil)
		@throw [OFInvalidArgumentException exception];

	objects = [_array items];
	count = [_array count];
	objects = _array.mutableItems;
	count = _array.count;

	for (size_t i = 0; i < count; i++) {
		if (objects[i] == oldObject) {
			[newObject retain];
			[objects[i] release];
			objects[i] = newObject;

			return;
		}
	}
}

- (void)removeObject: (id)object
{
	id *objects;
	id const *objects;
	size_t count;

	if (object == nil)
		@throw [OFInvalidArgumentException exception];

	objects = [_array items];
	count = [_array count];
	objects = _array.items;
	count = _array.count;

	for (size_t i = 0; i < count; i++) {
		if ([objects[i] isEqual: object]) {
			object = objects[i];

			[_array removeItemAtIndex: i];
			_mutations++;

			[object release];

			return;
		}
	}
}

- (void)removeObjectIdenticalTo: (id)object
{
	id *objects;
	id const *objects;
	size_t count;

	if (object == nil)
		@throw [OFInvalidArgumentException exception];

	objects = [_array items];
	count = [_array count];
	objects = _array.items;
	count = _array.count;

	for (size_t i = 0; i < count; i++) {
		if (objects[i] == object) {
			[_array removeItemAtIndex: i];
			_mutations++;

			[object release];
219
220
221
222
223
224
225
226
227


228
229
230
231
232
233
234
235
236
237
238



239
240
241
242
243
244
245
219
220
221
222
223
224
225


226
227
228
229
230
231
232
233
234
235
236


237
238
239
240
241
242
243
244
245
246







-
-
+
+









-
-
+
+
+








	_mutations++;
#endif
}

- (void)removeAllObjects
{
	id *objects = [_array items];
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;

	for (size_t i = 0; i < count; i++)
		[objects[i] release];

	[_array removeAllItems];
}

- (void)removeObjectsInRange: (of_range_t)range
{
	id *objects = [_array items], *copy;
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;
	id *copy;

	if (range.length > SIZE_MAX - range.location ||
	    range.location >= count || range.length > count - range.location)
		@throw [OFOutOfRangeException exception];

	copy = [self allocMemoryWithSize: sizeof(*copy)
				   count: range.length];
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280


281
282
283
284
285
286
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
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
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279


280
281
282
283
284
285
286
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
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







-
+
















-
-
+
+












-
-
+
+















-
+


















-
+















-
-
+
+














-
-
+
+







		[self freeMemory: copy];
	}
}

- (void)removeLastObject
{
#ifndef __clang_analyzer__
	size_t count = [_array count];
	size_t count = _array.count;
	id object;

	if (count == 0)
		return;

	object = [self objectAtIndex: count - 1];
	[_array removeLastItem];
	[object release];

	_mutations++;
#endif
}

- (void)exchangeObjectAtIndex: (size_t)idx1
	    withObjectAtIndex: (size_t)idx2
{
	id *objects = [_array items];
	size_t count = [_array count];
	id *objects = _array.mutableItems;
	size_t count = _array.count;
	id tmp;

	if (idx1 >= count || idx2 >= count)
		@throw [OFOutOfRangeException exception];

	tmp = objects[idx1];
	objects[idx1] = objects[idx2];
	objects[idx2] = tmp;
}

- (void)reverse
{
	id *objects = [_array items];
	size_t i, j, count = [_array count];
	id *objects = _array.mutableItems;
	size_t i, j, count = _array.count;

	if (count == 0 || count == 1)
		return;

	for (i = 0, j = count - 1; i < j; i++, j--) {
		id tmp = objects[i];
		objects[i] = objects[j];
		objects[j] = tmp;
	}
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
			   objects: (id *)objects
			     count: (int)count_
{
	size_t count = [_array count];
	size_t count = _array.count;

	if (count > INT_MAX) {
		/*
		 * Use the implementation from OFArray (OFMutableArray does not
		 * have one), which is slower, but can enumerate in chunks, and
		 * set the mutations pointer.
		 */
		int ret = [super countByEnumeratingWithState: state
						     objects: objects
						       count: count_];
		state->mutationsPtr = &_mutations;
		return ret;
	}

	if (state->state >= count)
		return 0;

	state->state = (unsigned long)count;
	state->itemsPtr = [_array items];
	state->itemsPtr = _array.items;
	state->mutationsPtr = &_mutations;

	return (int)count;
}

- (OFEnumerator *)objectEnumerator
{
	return [[[OFArrayEnumerator alloc]
	    initWithArray: self
	     mutationsPtr: &_mutations] autorelease];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
{
	id *objects = [_array items];
	size_t count = [_array count];
	id const *objects = _array.items;
	size_t count = _array.count;
	bool stop = false;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < count && !stop; i++) {
		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];

		block(objects[i], i, &stop);
	}
}

- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block
{
	id *objects = [_array items];
	size_t count = [_array count];
	id *objects = _array.mutableItems;
	size_t count = _array.count;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < count; i++) {
		id new;

		if (_mutations != mutations)
			@throw [OFEnumerationMutationException

Modified src/OFMutableData.h from [55b86d5e3b] to [68ac1d26ec].

28
29
30
31
32
33
34










35
36
37
38
39
40
41
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51







+
+
+
+
+
+
+
+
+
+







 * @brief A class for storing and manipulating arbitrary data in an array.
 */
@interface OFMutableData: OFData
{
	size_t _capacity;
}

/*!
 * @brief All items of the OFMutableData as a C array.
 *
 * @warning The pointer is only valid until the OFMutableData is changed!
 *
 * Modifying the returned array directly is allowed and will change the contents
 * of the data.
 */
@property (readonly, nonatomic) void *mutableItems OF_RETURNS_INNER_POINTER;

/*!
 * @brief Creates a new OFMutableData with an item size of 1.
 *
 * @return A new autoreleased OFMutableData
 */
+ (instancetype)data;

102
103
104
105
106
107
108











109
110
111
112
113
114
115
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







+
+
+
+
+
+
+
+
+
+
+







 * @param itemSize The size of a single element in the OFMutableData
 * @param capacity The initial capacity for the OFMutableData
 * @return An initialized OFMutableData
 */
- (instancetype)initWithItemSize: (size_t)itemSize
			capacity: (size_t)capacity;

/*!
 * @brief Returns a specific item of the OFMutableData.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data.
 *
 * @param index The number of the item to return
 * @return The specified item of the OFMutableData
 */
- (void *)mutableItemAtIndex: (size_t)index OF_RETURNS_INNER_POINTER;

/*!
 * @brief Adds an item to the OFMutableData.
 *
 * @param item A pointer to an arbitrary item
 */
- (void)addItem: (const void *)item;

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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
197
198
199
200
201
202
203
















































204







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


/*!
 * @brief Converts the mutable URL to an immutable URL.
 */
- (void)makeImmutable;
@end

@interface OFMutableData (MutableRetrieving)
/* GCC does not like overriding properties with a different type. */
#if defined(__clang__) || defined(DOXYGEN)
/*!
 * @brief All items of the OFMutableData as a C array.
 *
 * @warning The pointer is only valid until the OFMutableData is changed!
 *
 * Modifying the returned array directly is allowed and will change the contents
 * of the data.
 */
@property (readonly, nonatomic) void *items OF_RETURNS_INNER_POINTER;

/*!
 * @brief The first item of the OFMutableData or `NULL`.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *firstItem
    OF_RETURNS_INNER_POINTER;

/*!
 * @brief Last item of the OFMutableData or `NULL`.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *lastItem
    OF_RETURNS_INNER_POINTER;
#else
- (void *)items;
- (nullable void *)firstItem;
- (nullable void *)lastItem;
#endif

/*!
 * @brief Returns a specific item of the OFMutableData.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data.
 *
 * @param index The number of the item to return
 * @return The specified item of the OFMutableData
 */
- (void *)itemAtIndex: (size_t)index OF_RETURNS_INNER_POINTER;
@end

OF_ASSUME_NONNULL_END

Modified src/OFMutableData.m from [fad07c6a98] to [4177ee034d].

137
138
139
140
141
142
143













144
145
146
147
148
149
150
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







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







{
	self = [super initWithStringRepresentation: string];

	_capacity = _count;

	return self;
}

- (void *)mutableItems
{
	return _items;
}

- (void *)mutableItemAtIndex: (size_t)idx
{
	if (idx >= _count)
		@throw [OFOutOfRangeException exception];

	return _items + idx * _itemSize;
}

- (OFData *)subdataWithRange: (of_range_t)range
{
	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _count)
		@throw [OFOutOfRangeException exception];

Modified src/OFMutableDictionary.m from [1ca29dfd97] to [08e850f34a].

183
184
185
186
187
188
189
190

191
192
193
194
195
196
197
183
184
185
186
187
188
189

190
191
192
193
194
195
196
197







-
+







	OF_UNRECOGNIZED_SELECTOR
}

- (void)removeAllObjects
{
	void *pool = objc_autoreleasePoolPush();

	for (id key in [self allKeys])
	for (id key in self.allKeys)
		[self removeObjectForKey: key];

	objc_autoreleasePoolPop(pool);
}

- (id)copy
{

Modified src/OFMutableSet.m from [d3bbc8f1ec] to [5d818f447d].

165
166
167
168
169
170
171
172

173
174
175
176
177
178
179
165
166
167
168
169
170
171

172
173
174
175
176
177
178
179







-
+







	for (id object in set)
		[self removeObject: object];
}

- (void)intersectSet: (OFSet *)set
{
	void *pool = objc_autoreleasePoolPush();
	size_t count = [self count];
	size_t count = self.count;
	id *cArray;

	cArray = [self allocMemoryWithSize: sizeof(id)
				     count: count];

	@try {
		size_t i;

Modified src/OFMutableString.m from [91653c54ba] to [3ed2ba1cf6].

235
236
237
238
239
240
241
242
243


244
245
246
247
248
249


250
251
252
253
254
255
256
235
236
237
238
239
240
241


242
243
244
245
246
247


248
249
250
251
252
253
254
255
256







-
-
+
+




-
-
+
+







	if (self == [OFMutableString class])
		return (id)&placeholder;

	return [super alloc];
}

#ifdef OF_HAVE_UNICODE_TABLES
- (void)of_convertWithWordStartTable: (const of_unichar_t *const[])startTable
		     wordMiddleTable: (const of_unichar_t *const[])middleTable
- (void)of_convertWithWordStartTable: (const of_unichar_t *const [])startTable
		     wordMiddleTable: (const of_unichar_t *const [])middleTable
		  wordStartTableSize: (size_t)startTableSize
		 wordMiddleTableSize: (size_t)middleTableSize
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;
	bool isStart = true;

	for (size_t i = 0; i < length; i++) {
		const of_unichar_t *const *table;
		size_t tableSize;
		of_unichar_t c = characters[i];

272
273
274
275
276
277
278
279
280


281
282
283
284
285
286
287
272
273
274
275
276
277
278


279
280
281
282
283
284
285
286
287







-
-
+
+







	objc_autoreleasePoolPop(pool);
}
#else
- (void)of_convertWithWordStartFunction: (char (*)(char))startFunction
		     wordMiddleFunction: (char (*)(char))middleFunction
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;
	bool isStart = true;

	for (size_t i = 0; i < length; i++) {
		char (*function)(char) =
		    (isStart ? startFunction : middleFunction);
		of_unichar_t c = characters[i];

310
311
312
313
314
315
316
317

318
319
320
321
322
323
324
310
311
312
313
314
315
316

317
318
319
320
321
322
323
324







-
+








	objc_autoreleasePoolPop(pool);
}

- (void)appendString: (OFString *)string
{
	[self insertString: string
		   atIndex: [self length]];
		   atIndex: self.length];
}

- (void)appendCharacters: (const of_unichar_t *)characters
		  length: (size_t)length
{
	void *pool = objc_autoreleasePoolPush();

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







-
+



















-
+







{
	char *UTF8String;
	int UTF8StringLength;

	if (format == nil)
		@throw [OFInvalidArgumentException exception];

	if ((UTF8StringLength = of_vasprintf(&UTF8String, [format UTF8String],
	if ((UTF8StringLength = of_vasprintf(&UTF8String, format.UTF8String,
	    arguments)) == -1)
		@throw [OFInvalidFormatException exception];

	@try {
		[self appendUTF8String: UTF8String
				length: UTF8StringLength];
	} @finally {
		free(UTF8String);
	}
}

- (void)prependString: (OFString *)string
{
	[self insertString: string
		   atIndex: 0];
}

- (void)reverse
{
	size_t i, j, length = [self length];
	size_t i, j, length = self.length;

	for (i = 0, j = length - 1; i < length / 2; i++, j--) {
		of_unichar_t tmp = [self characterAtIndex: j];
		[self setCharacter: [self characterAtIndex: i]
			   atIndex: j];
		[self setCharacter: tmp
			   atIndex: i];
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
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
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
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







-
+









-
-
-
+
+
+





-
+








-
+

















-
+








-
-
+
+



















-
+





-
+








- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
{
	[self replaceOccurrencesOfString: string
			      withString: replacement
				 options: 0
				   range: of_range(0, [self length])];
				   range: of_range(0, self.length)];
}

- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
			   options: (int)options
			     range: (of_range_t)range
{
	void *pool = objc_autoreleasePoolPush(), *pool2;
	const of_unichar_t *characters;
	const of_unichar_t *searchCharacters = [string characters];
	size_t searchLength = [string length];
	size_t replacementLength = [replacement length];
	const of_unichar_t *searchCharacters = string.characters;
	size_t searchLength = string.length;
	size_t replacementLength = replacement.length;

	if (string == nil || replacement == nil)
		@throw [OFInvalidArgumentException exception];

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > [self length])
	    range.location + range.length > self.length)
		@throw [OFOutOfRangeException exception];

	if (searchLength > range.length) {
		objc_autoreleasePoolPop(pool);
		return;
	}

	pool2 = objc_autoreleasePoolPush();
	characters = [self characters];
	characters = self.characters;

	for (size_t i = range.location; i <= range.length - searchLength; i++) {
		if (memcmp(characters + i, searchCharacters,
		    searchLength * sizeof(of_unichar_t)) != 0)
			continue;

		[self replaceCharactersInRange: of_range(i, searchLength)
				    withString: replacement];

		range.length -= searchLength;
		range.length += replacementLength;

		i += replacementLength - 1;

		objc_autoreleasePoolPop(pool2);
		pool2 = objc_autoreleasePoolPush();

		characters = [self characters];
		characters = self.characters;
	}

	objc_autoreleasePoolPop(pool);
}

- (void)deleteLeadingWhitespaces
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t i, length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t i, length = self.length;

	for (i = 0; i < length; i++) {
		of_unichar_t c = characters[i];

		if (!of_ascii_isspace(c))
			break;
	}

	objc_autoreleasePoolPop(pool);

	[self deleteCharactersInRange: of_range(0, i)];
}

- (void)deleteTrailingWhitespaces
{
	void *pool;
	const of_unichar_t *characters, *p;
	size_t length, d;

	length = [self length];
	length = self.length;

	if (length == 0)
		return;

	pool = objc_autoreleasePoolPush();
	characters = [self characters];
	characters = self.characters;

	d = 0;
	for (p = characters + length - 1; p >= characters; p--) {
		if (!of_ascii_isspace(*p))
			break;

		d++;

Modified src/OFMutableString_UTF8.m from [b9817e13bd] to [afad633464].

100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114







-
+







			if ((t = table[0][(uint8_t)_s->cString[i]]) != 0)
				_s->cString[i] = t;
		}

		return;
	}

	unicodeLen = [self length];
	unicodeLen = self.length;
	unicodeString = [self allocMemoryWithSize: sizeof(of_unichar_t)
					    count: unicodeLen];

	i = j = 0;
	newCStringLength = 0;

	while (i < _s->cStringLength) {
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
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







-
+





-
+



-
+







- (void)appendString: (OFString *)string
{
	size_t UTF8StringLength;

	if (string == nil)
		@throw [OFInvalidArgumentException exception];

	UTF8StringLength = [string UTF8StringLength];
	UTF8StringLength = string.UTF8StringLength;

	_s->hashed = false;
	_s->cString = [self resizeMemory: _s->cString
				    size: _s->cStringLength +
					  UTF8StringLength + 1];
	memcpy(_s->cString + _s->cStringLength, [string UTF8String],
	memcpy(_s->cString + _s->cStringLength, string.UTF8String,
	    UTF8StringLength);

	_s->cStringLength += UTF8StringLength;
	_s->length += [string length];
	_s->length += string.length;

	_s->cString[_s->cStringLength] = 0;

	if ([string isKindOfClass: [OFString_UTF8 class]] ||
	    [string isKindOfClass: [OFMutableString_UTF8 class]]) {
		if (((OFString_UTF8 *)string)->_s->isUTF8)
			_s->isUTF8 = true;
427
428
429
430
431
432
433
434

435
436
437
438
439
440
441
427
428
429
430
431
432
433

434
435
436
437
438
439
440
441







-
+







{
	char *UTF8String;
	int UTF8StringLength;

	if (format == nil)
		@throw [OFInvalidArgumentException exception];

	if ((UTF8StringLength = of_vasprintf(&UTF8String, [format UTF8String],
	if ((UTF8StringLength = of_vasprintf(&UTF8String, format.UTF8String,
	    arguments)) == -1)
		@throw [OFInvalidFormatException exception];

	@try {
		[self appendUTF8String: UTF8String
				length: UTF8StringLength];
	} @finally {
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
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







-
+




-
+

-
-
+
+



-
+







	if (idx > _s->length)
		@throw [OFOutOfRangeException exception];

	if (_s->isUTF8)
		idx = of_string_utf8_get_position(_s->cString, idx,
		    _s->cStringLength);

	newCStringLength = _s->cStringLength + [string UTF8StringLength];
	newCStringLength = _s->cStringLength + string.UTF8StringLength;
	_s->hashed = false;
	_s->cString = [self resizeMemory: _s->cString
				    size: newCStringLength + 1];

	memmove(_s->cString + idx + [string UTF8StringLength],
	memmove(_s->cString + idx + string.UTF8StringLength,
	    _s->cString + idx, _s->cStringLength - idx);
	memcpy(_s->cString + idx, [string UTF8String],
	    [string UTF8StringLength]);
	memcpy(_s->cString + idx, string.UTF8String,
	    string.UTF8StringLength);
	_s->cString[newCStringLength] = '\0';

	_s->cStringLength = newCStringLength;
	_s->length += [string length];
	_s->length += string.length;

	if ([string isKindOfClass: [OFString_UTF8 class]] ||
	    [string isKindOfClass: [OFMutableString_UTF8 class]]) {
		if (((OFString_UTF8 *)string)->_s->isUTF8)
			_s->isUTF8 = true;
	} else
		_s->isUTF8 = true;
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
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







-
+









-
+














-
+

-
-
+
+








	if (replacement == nil)
		@throw [OFInvalidArgumentException exception];

	if (range.length > SIZE_MAX - range.location || end > _s->length)
		@throw [OFOutOfRangeException exception];

	newLength = _s->length - range.length + [replacement length];
	newLength = _s->length - range.length + replacement.length;

	if (_s->isUTF8) {
		start = of_string_utf8_get_position(_s->cString, start,
		    _s->cStringLength);
		end = of_string_utf8_get_position(_s->cString, end,
		    _s->cStringLength);
	}

	newCStringLength = _s->cStringLength - (end - start) +
	    [replacement UTF8StringLength];
	    replacement.UTF8StringLength;
	_s->hashed = false;

	/*
	 * If the new string is bigger, we need to resize it first so we can
	 * memmove() the rest of the string to the end.
	 *
	 * We must not resize the string if the new string is smaller, because
	 * then we can't memmove() the rest of the string forward as the rest is
	 * lost due to the resize!
	 */
	if (newCStringLength > _s->cStringLength)
		_s->cString = [self resizeMemory: _s->cString
					    size: newCStringLength + 1];

	memmove(_s->cString + start + [replacement UTF8StringLength],
	memmove(_s->cString + start + replacement.UTF8StringLength,
	    _s->cString + end, _s->cStringLength - end);
	memcpy(_s->cString + start, [replacement UTF8String],
	    [replacement UTF8StringLength]);
	memcpy(_s->cString + start, replacement.UTF8String,
	    replacement.UTF8StringLength);
	_s->cString[newCStringLength] = '\0';

	/*
	 * If the new string is smaller, we can safely resize it now as we're
	 * done with memmove().
	 */
	if (newCStringLength < _s->cStringLength)
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
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







-
-
-
-
+
+
+
+







-
+










-
+












-
-
-
-
+
+
+
+










-
+







}

- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
			   options: (int)options
			     range: (of_range_t)range
{
	const char *searchString = [string UTF8String];
	const char *replacementString = [replacement UTF8String];
	size_t searchLength = [string UTF8StringLength];
	size_t replacementLength = [replacement UTF8StringLength];
	const char *searchString = string.UTF8String;
	const char *replacementString = replacement.UTF8String;
	size_t searchLength = string.UTF8StringLength;
	size_t replacementLength = replacement.UTF8StringLength;
	size_t last, newCStringLength, newLength;
	char *newCString;

	if (string == nil || replacement == nil)
		@throw [OFInvalidArgumentException exception];

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > [self length])
	    range.location + range.length > self.length)
		@throw [OFOutOfRangeException exception];

	if (_s->isUTF8) {
		range.location = of_string_utf8_get_position(_s->cString,
		    range.location, _s->cStringLength);
		range.length = of_string_utf8_get_position(
		    _s->cString + range.location, range.length,
		    _s->cStringLength - range.location);
	}

	if ([string UTF8StringLength] > range.length)
	if (string.UTF8StringLength > range.length)
		return;

	newCString = NULL;
	newCStringLength = 0;
	newLength = _s->length;
	last = 0;

	for (size_t i = range.location; i <= range.length - searchLength; i++) {
		if (memcmp(_s->cString + i, searchString, searchLength) != 0)
			continue;

		@try {
			newCString = [self
			    resizeMemory: newCString
				    size: newCStringLength + i - last +
					  replacementLength + 1];
			newCString = [self resizeMemory: newCString
						   size: newCStringLength +
							 i - last +
							 replacementLength + 1];
		} @catch (id e) {
			[self freeMemory: newCString];
			@throw e;
		}
		memcpy(newCString + newCStringLength, _s->cString + last,
		    i - last);
		memcpy(newCString + newCStringLength + i - last,
		    replacementString, replacementLength);

		newCStringLength += i - last + replacementLength;
		newLength = newLength - [string length] + [replacement length];
		newLength = newLength - string.length + replacement.length;

		i += searchLength - 1;
		last = i + 1;
	}

	@try {
		newCString = [self resizeMemory: newCString

Modified src/OFMutableURL.m from [281bdc699b] to [4c8969afe8].

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







-
+



-
+


-
+


-
+







}

- (void)setPathComponents: (OFArray *)components
{
	void *pool = objc_autoreleasePoolPush();

	if (components == nil) {
		[self setPath: nil];
		self.path = nil;
		return;
	}

	if ([components count] == 0)
	if (components.count == 0)
		@throw [OFInvalidFormatException exception];

	if ([[components firstObject] length] != 0)
	if ([components.firstObject length] != 0)
		@throw [OFInvalidFormatException exception];

	[self setPath: [components componentsJoinedByString: @"/"]];
	self.path = [components componentsJoinedByString: @"/"];

	objc_autoreleasePoolPop(pool);
}

- (void)setQuery: (OFString *)query
{
	void *pool = objc_autoreleasePoolPush();
267
268
269
270
271
272
273
274

275
276
277

278
279
280

281
282
283
284
285
286


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
267
268
269
270
271
272
273

274
275
276

277
278
279

280
281
282
283
284


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







-
+


-
+


-
+




-
-
+
+


-
+






-
+
















-
+












		return;

	pool = objc_autoreleasePoolPush();

	array = [[[_URLEncodedPath
	    componentsSeparatedByString: @"/"] mutableCopy] autorelease];

	if ([[array firstObject] length] != 0)
	if ([array.firstObject length] != 0)
		@throw [OFInvalidFormatException exception];

	endsWithEmpty = ([[array lastObject] length] == 0);
	endsWithEmpty = ([array.lastObject length] == 0);

	while (!done) {
		size_t length = [array count];
		size_t length = array.count;

		done = true;

		for (size_t i = 0; i < length; i++) {
			id object = [array objectAtIndex: i];
			id parent =
			OFString *current = [array objectAtIndex: i];
			OFString *parent =
			    (i > 0 ? [array objectAtIndex: i - 1] : nil);

			if ([object isEqual: @"."] || [object length] == 0) {
			if ([current isEqual: @"."] || current.length == 0) {
				[array removeObjectAtIndex: i];

				done = false;
				break;
			}

			if ([object isEqual: @".."] && parent != nil &&
			if ([current isEqual: @".."] && parent != nil &&
			    ![parent isEqual: @".."]) {
				[array removeObjectsInRange:
				    of_range(i - 1, 2)];

				done = false;
				break;
			}
		}
	}

	[array insertObject: @""
		    atIndex: 0];
	if (endsWithEmpty)
		[array addObject: @""];

	path = [array componentsJoinedByString: @"/"];
	if ([path length] == 0)
	if (path.length == 0)
		path = @"/";

	[self setURLEncodedPath: path];

	objc_autoreleasePoolPop(pool);
}

- (void)makeImmutable
{
	object_setClass(self, [OFURL class]);
}
@end

Modified src/OFMutableZIPArchiveEntry.m from [477a94e0e9] to [b63548e22a].

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







-
+














-
+














-
+


-
+







}

- (void)setFileName: (OFString *)fileName
{
	void *pool = objc_autoreleasePoolPush();
	OFString *old;

	if ([fileName UTF8StringLength] > UINT16_MAX)
	if (fileName.UTF8StringLength > UINT16_MAX)
		@throw [OFOutOfRangeException exception];

	old = _fileName;
	_fileName = [fileName copy];
	[old release];

	objc_autoreleasePoolPop(pool);
}

- (void)setFileComment: (OFString *)fileComment
{
	void *pool = objc_autoreleasePoolPush();
	OFString *old;

	if ([fileComment UTF8StringLength] > UINT16_MAX)
	if (fileComment.UTF8StringLength > UINT16_MAX)
		@throw [OFOutOfRangeException exception];

	old = _fileComment;
	_fileComment = [fileComment copy];
	[old release];

	objc_autoreleasePoolPop(pool);
}

- (void)setExtraField: (OFData *)extraField
{
	void *pool = objc_autoreleasePoolPush();
	OFData *old;

	if ([extraField itemSize] != 1)
	if (extraField.itemSize != 1)
		@throw [OFInvalidArgumentException exception];

	if ([extraField count] > UINT16_MAX)
	if (extraField.count > UINT16_MAX)
		@throw [OFOutOfRangeException exception];

	old = _extraField;
	_extraField = [extraField copy];
	[old release];

	objc_autoreleasePoolPop(pool);
99
100
101
102
103
104
105
106
107
108
109
110





111
112
113
114
115
116
117
99
100
101
102
103
104
105





106
107
108
109
110
111
112
113
114
115
116
117







-
-
-
-
-
+
+
+
+
+







	_minVersionNeeded = minVersionNeeded;
}

- (void)setModificationDate: (OFDate *)date
{
	void *pool = objc_autoreleasePoolPush();

	_lastModifiedFileDate = ((([date localYear] - 1980) & 0xFF) << 9) |
	    (([date localMonthOfYear] & 0x0F) << 5) |
	    ([date localDayOfMonth] & 0x1F);
	_lastModifiedFileTime = (([date localHour] & 0x1F) << 11) |
	    (([date localMinute] & 0x3F) << 5) | (([date second] >> 1) & 0x0F);
	_lastModifiedFileDate = (((date.localYear - 1980) & 0xFF) << 9) |
	    ((date.localMonthOfYear & 0x0F) << 5) |
	    (date.localDayOfMonth & 0x1F);
	_lastModifiedFileTime = ((date.localHour & 0x1F) << 11) |
	    ((date.localMinute & 0x3F) << 5) | ((date.second >> 1) & 0x0F);

	objc_autoreleasePoolPop(pool);
}

- (void)setCompressionMethod: (uint16_t)compressionMethod
{
	_compressionMethod = compressionMethod;

Modified src/OFMutex.m from [08bcd2f7b5] to [99a3d0e9e5].

34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48







-
+







}

- (instancetype)init
{
	self = [super init];

	if (!of_mutex_new(&_mutex)) {
		Class c = [self class];
		Class c = self.class;
		[self release];
		@throw [OFInitializationFailedException exceptionWithClass: c];
	}

	_initialized = true;

	return self;
75
76
77
78
79
80
81
82

83
84

85
86
87
75
76
77
78
79
80
81

82
83

84

85
86







-
+

-
+
-


	if (!of_mutex_unlock(&_mutex))
		@throw [OFUnlockFailedException exceptionWithLock: self];
}

- (OFString *)description
{
	if (_name == nil)
		return [super description];
		return super.description;

	return [OFString stringWithFormat: @"<%@: %@>",
	return [OFString stringWithFormat: @"<%@: %@>", self.className, _name];
					   [self className], _name];
}
@end

Modified src/OFNull.m from [353afe99b3] to [50ff4e3845].

46
47
48
49
50
51
52
53
54


55
56
57
58
59
60
61
46
47
48
49
50
51
52


53
54
55
56
57
58
59
60
61







-
-
+
+







{
	void *pool;

	[self release];

	pool = objc_autoreleasePoolPush();

	if (![[element name] isEqual: [self className]] ||
	    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
	if (![element.name isEqual: self.className] ||
	    ![element.namespace isEqual: OF_SERIALIZATION_NS])
		@throw [OFInvalidArgumentException exception];

	objc_autoreleasePoolPop(pool);

	return [OFNull null];
}

70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84







-
+







}

- (OFXMLElement *)XMLElementBySerializing
{
	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *element;

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

	[element retain];

	objc_autoreleasePoolPop(pool);

	return [element autorelease];

Modified src/OFNumber.m from [bef2101a40] to [402455fc05].

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







-
-
+
+


-
+
















-
+


-
+







-
+










-
+







{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFString *typeString;

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		typeString = [[element attributeForName: @"type"] stringValue];
		typeString = [element attributeForName: @"type"].stringValue;

		if ([typeString isEqual: @"boolean"]) {
			_type = OF_NUMBER_TYPE_BOOL;

			if ([[element stringValue] isEqual: @"true"])
				_value.bool_ = true;
			else if ([[element stringValue] isEqual: @"false"])
				_value.bool_ = false;
			else
				@throw [OFInvalidArgumentException exception];
		} else if ([typeString isEqual: @"unsigned"]) {
			/*
			 * FIXME: This will fail if the value is bigger than
			 *	  INTMAX_MAX!
			 */
			_type = OF_NUMBER_TYPE_UINTMAX;
			_value.uIntMax = [element decimalValue];
			_value.uIntMax = element.decimalValue;
		} else if ([typeString isEqual: @"signed"]) {
			_type = OF_NUMBER_TYPE_INTMAX;
			_value.intMax = [element decimalValue];
			_value.intMax = element.decimalValue;
		} else if ([typeString isEqual: @"float"]) {
			union {
				float f;
				uint32_t u;
			} f;

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

			_type = OF_NUMBER_TYPE_FLOAT;
			_value.float_ = OF_BSWAP_FLOAT_IF_LE(f.f);
		} else if ([typeString isEqual: @"double"]) {
			union {
				double d;
				uint64_t u;
			} d;

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

			_type = OF_NUMBER_TYPE_DOUBLE;
			_value.double_ = OF_BSWAP_DOUBLE_IF_LE(d.d);
		} else
			@throw [OFInvalidArgumentException exception];

		objc_autoreleasePoolPop(pool);
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
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

1092
1093
1094
1095
1096
1097
1098
1099
1100

1101
1102
1103
1104
1105
1106
1107
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
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
1092
1093
1094
1095
1096
1097
1098
1099

1100
1101
1102
1103
1104
1105
1106
1107







-
-
+
+











-
+

-
+













-
-
+
+









-
-
+
+








-
-
+
+
















-
+




-
+


-
+




-
+












-
+


-
+




-
+








-
+







	if (![object isKindOfClass: [OFNumber class]])
		return false;

	number = object;

	if (_type & OF_NUMBER_TYPE_FLOAT ||
	    number->_type & OF_NUMBER_TYPE_FLOAT) {
		double value1 = [number doubleValue];
		double value2 = [self doubleValue];
		double value1 = number.doubleValue;
		double value2 = self.doubleValue;

		if (isnan(value1) && isnan(value2))
			return true;
		if (isnan(value1) || isnan(value2))
			return false;

		return (value1 == value2);
	}

	if (_type & OF_NUMBER_TYPE_SIGNED ||
	    number->_type & OF_NUMBER_TYPE_SIGNED)
		return ([number intMaxValue] == [self intMaxValue]);
		return (number.intMaxValue == self.intMaxValue);

	return ([number uIntMaxValue] == [self uIntMaxValue]);
	return (number.uIntMaxValue == self.uIntMaxValue);
}

- (of_comparison_result_t)compare: (id <OFComparing>)object
{
	OFNumber *number;

	if (![(id)object isKindOfClass: [OFNumber class]])
		@throw [OFInvalidArgumentException exception];

	number = (OFNumber *)object;

	if (_type & OF_NUMBER_TYPE_FLOAT ||
	    number->_type & OF_NUMBER_TYPE_FLOAT) {
		double double1 = [self doubleValue];
		double double2 = [number doubleValue];
		double double1 = self.doubleValue;
		double double2 = number.doubleValue;

		if (double1 > double2)
			return OF_ORDERED_DESCENDING;
		if (double1 < double2)
			return OF_ORDERED_ASCENDING;

		return OF_ORDERED_SAME;
	} else if (_type & OF_NUMBER_TYPE_SIGNED ||
	    number->_type & OF_NUMBER_TYPE_SIGNED) {
		intmax_t int1 = [self intMaxValue];
		intmax_t int2 = [number intMaxValue];
		intmax_t int1 = self.intMaxValue;
		intmax_t int2 = number.intMaxValue;

		if (int1 > int2)
			return OF_ORDERED_DESCENDING;
		if (int1 < int2)
			return OF_ORDERED_ASCENDING;

		return OF_ORDERED_SAME;
	} else {
		uintmax_t uint1 = [self uIntMaxValue];
		uintmax_t uint2 = [number uIntMaxValue];
		uintmax_t uint1 = self.uIntMaxValue;
		uintmax_t uint2 = number.uIntMaxValue;

		if (uint1 > uint2)
			return OF_ORDERED_DESCENDING;
		if (uint1 < uint2)
			return OF_ORDERED_ASCENDING;

		return OF_ORDERED_SAME;
	}
}

- (uint32_t)hash
{
	of_number_type_t type = _type;
	uint32_t hash;

	/* Do we really need signed to represent this number? */
	if (type & OF_NUMBER_TYPE_SIGNED && [self intMaxValue] >= 0)
	if (type & OF_NUMBER_TYPE_SIGNED && self.intMaxValue >= 0)
		type &= ~OF_NUMBER_TYPE_SIGNED;

	/* Do we really need floating point to represent this number? */
	if (type & OF_NUMBER_TYPE_FLOAT) {
		double v = [self doubleValue];
		double v = self.doubleValue;

		if (v < 0) {
			if (v == [self intMaxValue]) {
			if (v == self.intMaxValue) {
				type &= ~OF_NUMBER_TYPE_FLOAT;
				type |= OF_NUMBER_TYPE_SIGNED;
			}
		} else {
			if (v == [self uIntMaxValue])
			if (v == self.uIntMaxValue)
				type &= ~OF_NUMBER_TYPE_FLOAT;
		}
	}

	OF_HASH_INIT(hash);

	if (type & OF_NUMBER_TYPE_FLOAT) {
		union {
			double d;
			uint8_t b[sizeof(double)];
		} d;

		if (isnan([self doubleValue]))
		if (isnan(self.doubleValue))
			return 0;

		d.d = OF_BSWAP_DOUBLE_IF_BE([self doubleValue]);
		d.d = OF_BSWAP_DOUBLE_IF_BE(self.doubleValue);

		for (uint_fast8_t i = 0; i < sizeof(double); i++)
			OF_HASH_ADD(hash, d.b[i]);
	} else if (type & OF_NUMBER_TYPE_SIGNED) {
		intmax_t v = [self intMaxValue] * -1;
		intmax_t v = self.intMaxValue * -1;

		while (v != 0) {
			OF_HASH_ADD(hash, v & 0xFF);
			v >>= 8;
		}

		OF_HASH_ADD(hash, 1);
	} else {
		uintmax_t v = [self uIntMaxValue];
		uintmax_t v = self.uIntMaxValue;

		while (v != 0) {
			OF_HASH_ADD(hash, v & 0xFF);
			v >>= 8;
		}
	}

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







-
+













-
+







	case OF_NUMBER_TYPE_UINT8:
	case OF_NUMBER_TYPE_UINT16:
	case OF_NUMBER_TYPE_UINT32:
	case OF_NUMBER_TYPE_UINT64:
	case OF_NUMBER_TYPE_SIZE:
	case OF_NUMBER_TYPE_UINTMAX:
	case OF_NUMBER_TYPE_UINTPTR:
		return [OFString stringWithFormat: @"%ju", [self uIntMaxValue]];
		return [OFString stringWithFormat: @"%ju", self.uIntMaxValue];
	case OF_NUMBER_TYPE_CHAR:
	case OF_NUMBER_TYPE_SHORT:
	case OF_NUMBER_TYPE_INT:
	case OF_NUMBER_TYPE_LONG:
	case OF_NUMBER_TYPE_LONGLONG:
	case OF_NUMBER_TYPE_INT8:
	case OF_NUMBER_TYPE_INT16:
	case OF_NUMBER_TYPE_INT32:
	case OF_NUMBER_TYPE_INT64:
	case OF_NUMBER_TYPE_SSIZE:
	case OF_NUMBER_TYPE_INTMAX:
	case OF_NUMBER_TYPE_PTRDIFF:
	case OF_NUMBER_TYPE_INTPTR:
		return [OFString stringWithFormat: @"%jd", [self intMaxValue]];
		return [OFString stringWithFormat: @"%jd", self.intMaxValue];
	case OF_NUMBER_TYPE_FLOAT:
		ret = [OFMutableString stringWithFormat: @"%g", _value.float_];

		if (![ret containsString: @"."])
			[ret appendString: @".0"];

		[ret makeImmutable];
1173
1174
1175
1176
1177
1178
1179
1180

1181
1182

1183
1184
1185
1186
1187
1188
1189
1173
1174
1175
1176
1177
1178
1179

1180
1181

1182
1183
1184
1185
1186
1187
1188
1189







-
+

-
+







}

- (OFXMLElement *)XMLElementBySerializing
{
	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *element;

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

	switch (_type) {
	case OF_NUMBER_TYPE_BOOL:
		[element addAttributeWithName: @"type"
				  stringValue: @"boolean"];
		break;
	case OF_NUMBER_TYPE_UCHAR:
1223
1224
1225
1226
1227
1228
1229
1230

1231
1232

1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245

1246
1247

1248
1249
1250
1251
1252
1253
1254
1223
1224
1225
1226
1227
1228
1229

1230
1231

1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244

1245
1246

1247
1248
1249
1250
1251
1252
1253
1254







-
+

-
+












-
+

-
+







			uint32_t u;
		} f;

		f.f = OF_BSWAP_FLOAT_IF_LE(_value.float_);

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

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

		d.d = OF_BSWAP_DOUBLE_IF_LE(_value.double_);

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

		break;
	default:
		@throw [OFInvalidFormatException exception];
	}

	[element retain];
1274
1275
1276
1277
1278
1279
1280
1281

1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292

1293
1294
1295
1296
1297
1298
1299
1274
1275
1276
1277
1278
1279
1280

1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291

1292
1293
1294
1295
1296
1297
1298
1299







-
+










-
+







					 depth: (size_t)depth
{
	double doubleValue;

	if (_type == OF_NUMBER_TYPE_BOOL)
		return (_value.bool_ ? @"true" : @"false");

	doubleValue = [self doubleValue];
	doubleValue = self.doubleValue;
	if (isinf(doubleValue)) {
		if (options & OF_JSON_REPRESENTATION_JSON5) {
			if (doubleValue > 0)
				return @"Infinity";
			else
				return @"-Infinity";
		} else
			@throw [OFInvalidArgumentException exception];
	}

	return [self description];
	return self.description;
}

- (OFData *)messagePackRepresentation
{
	OFMutableData *data;

	if (_type == OF_NUMBER_TYPE_BOOL) {
1318
1319
1320
1321
1322
1323
1324
1325

1326
1327
1328
1329
1330
1331
1332
1318
1319
1320
1321
1322
1323
1324

1325
1326
1327
1328
1329
1330
1331
1332







-
+







		data = [OFMutableData dataWithItemSize: 1
					      capacity: 9];

		[data addItem: &type];
		[data addItems: &tmp
			 count: sizeof(tmp)];
	} else if (_type & OF_NUMBER_TYPE_SIGNED) {
		intmax_t value = [self intMaxValue];
		intmax_t value = self.intMaxValue;

		if (value >= -32 && value < 0) {
			uint8_t tmp = 0xE0 | ((uint8_t)(value - 32) & 0x1F);

			data = [OFMutableData dataWithItems: &tmp
						      count: 1];
		} else if (value >= INT8_MIN && value <= INT8_MAX) {
1367
1368
1369
1370
1371
1372
1373
1374

1375
1376
1377
1378
1379
1380
1381
1367
1368
1369
1370
1371
1372
1373

1374
1375
1376
1377
1378
1379
1380
1381







-
+








			[data addItem: &type];
			[data addItems: &tmp
				 count: sizeof(tmp)];
		} else
			@throw [OFOutOfRangeException exception];
	} else {
		uintmax_t value = [self uIntMaxValue];
		uintmax_t value = self.uIntMaxValue;

		if (value <= 127) {
			uint8_t tmp = ((uint8_t)value & 0x7F);

			data = [OFMutableData dataWithItems: &tmp
						      count: 1];
		} else if (value <= UINT8_MAX) {

Modified src/OFObject+KeyValueCoding.m from [06ea9a409d] to [96857463c3].

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







-
+








-
+








-
+














-
+






-
+




-
+







#import "OFUndefinedKeyException.h"

int _OFObject_KeyValueCoding_reference;

@implementation OFObject (KeyValueCoding)
- (id)valueForKey: (OFString *)key
{
	SEL selector = sel_registerName([key UTF8String]);
	SEL selector = sel_registerName(key.UTF8String);
	OFMethodSignature *methodSignature =
	    [self methodSignatureForSelector: selector];
	id ret;

	if (methodSignature == nil) {
		size_t keyLength;
		char *name;

		if ((keyLength = [key UTF8StringLength]) < 1)
		if ((keyLength = key.UTF8StringLength) < 1)
			return [self valueForUndefinedKey: key];

		if ((name = malloc(keyLength + 3)) == NULL)
			@throw [OFOutOfMemoryException
			    exceptionWithRequestedSize: keyLength + 3];

		@try {
			memcpy(name, "is", 2);
			memcpy(name + 2, [key UTF8String], keyLength);
			memcpy(name + 2, key.UTF8String, keyLength);
			name[keyLength + 2] = '\0';

			name[2] = of_ascii_toupper(name[2]);

			selector = sel_registerName(name);
		} @finally {
			free(name);
		}

		methodSignature = [self methodSignatureForSelector: selector];

		if (methodSignature == NULL)
			return [self valueForUndefinedKey: key];

		switch (*[methodSignature methodReturnType]) {
		switch (*methodSignature.methodReturnType) {
		case '@':
		case '#':
			return [self valueForUndefinedKey: key];
		}
	}

	if ([methodSignature numberOfArguments] != 2 ||
	if (methodSignature.numberOfArguments != 2 ||
	    *[methodSignature argumentTypeAtIndex: 0] != '@' ||
	    *[methodSignature argumentTypeAtIndex: 1] != ':')
		return [self valueForUndefinedKey: key];

	switch (*[methodSignature methodReturnType]) {
	switch (*methodSignature.methodReturnType) {
	case '@':
	case '#':
		ret = [self performSelector: selector];
		break;
#define CASE(encoding, type, method)					  \
	case encoding:							  \
		{							  \
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
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







-
+











-
+












-
-
+
+







{
	size_t keyLength;
	char *name;
	SEL selector;
	OFMethodSignature *methodSignature;
	const char *valueType;

	if ((keyLength = [key UTF8StringLength]) < 1) {
	if ((keyLength = key.UTF8StringLength) < 1) {
		[self	 setValue: value
		  forUndefinedKey: key];
		return;
	}

	if ((name = malloc(keyLength + 5)) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: keyLength + 5];

	@try {
		memcpy(name, "set", 3);
		memcpy(name + 3, [key UTF8String], keyLength);
		memcpy(name + 3, key.UTF8String, keyLength);
		memcpy(name + keyLength + 3, ":", 2);

		name[3] = of_ascii_toupper(name[3]);

		selector = sel_registerName(name);
	} @finally {
		free(name);
	}

	methodSignature = [self methodSignatureForSelector: selector];

	if (methodSignature == nil ||
	    [methodSignature numberOfArguments] != 3 ||
	    *[methodSignature methodReturnType] != 'v' ||
	    methodSignature.numberOfArguments != 3 ||
	    *methodSignature.methodReturnType != 'v' ||
	    *[methodSignature argumentTypeAtIndex: 0] != '@' ||
	    *[methodSignature argumentTypeAtIndex: 1] != ':') {
		[self    setValue: value
		  forUndefinedKey: key];
		return;
	}

Modified src/OFObject+Serialization.m from [b584ed859f] to [1406fa2657].

37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51







-
+








	if (![self conformsToProtocol: @protocol(OFSerialization)]) {
		[self doesNotRecognizeSelector: _cmd];
		abort();
	}

	pool = objc_autoreleasePoolPush();
	element = [(id)self XMLElementBySerializing];
	element = ((id <OFSerialization>)self).XMLElementBySerializing;

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

Modified src/OFObject.m from [edba45d06c] to [2b218f823b].

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







-
+


















-
+




















-
+







	  waitUntilDone: (bool)waitUntilDone
{
	void *pool = objc_autoreleasePoolPush();
	OFTimer *timer = [OFTimer timerWithTimeInterval: 0
						 target: self
					       selector: selector
						repeats: false];
	[[thread runLoop] addTimer: timer];
	[thread.runLoop addTimer: timer];

	if (waitUntilDone)
		[timer waitUntilDone];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (id)object
	  waitUntilDone: (bool)waitUntilDone
{
	void *pool = objc_autoreleasePoolPush();
	OFTimer *timer = [OFTimer timerWithTimeInterval: 0
						 target: self
					       selector: selector
						 object: object
						repeats: false];
	[[thread runLoop] addTimer: timer];
	[thread.runLoop addTimer: timer];

	if (waitUntilDone)
		[timer waitUntilDone];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (id)object1
	     withObject: (id)object2
	  waitUntilDone: (bool)waitUntilDone
{
	void *pool = objc_autoreleasePoolPush();
	OFTimer *timer = [OFTimer timerWithTimeInterval: 0
						 target: self
					       selector: selector
						 object: object1
						 object: object2
						repeats: false];
	[[thread runLoop] addTimer: timer];
	[thread.runLoop addTimer: timer];

	if (waitUntilDone)
		[timer waitUntilDone];

	objc_autoreleasePoolPop(pool);
}

735
736
737
738
739
740
741
742

743
744
745
746
747
748
749
735
736
737
738
739
740
741

742
743
744
745
746
747
748
749







-
+







	OFTimer *timer = [OFTimer timerWithTimeInterval: 0
						 target: self
					       selector: selector
						 object: object1
						 object: object2
						 object: object3
						repeats: false];
	[[thread runLoop] addTimer: timer];
	[thread.runLoop addTimer: timer];

	if (waitUntilDone)
		[timer waitUntilDone];

	objc_autoreleasePoolPop(pool);
}

760
761
762
763
764
765
766
767

768
769
770
771
772
773
774
760
761
762
763
764
765
766

767
768
769
770
771
772
773
774







-
+







						 target: self
					       selector: selector
						 object: object1
						 object: object2
						 object: object3
						 object: object4
						repeats: false];
	[[thread runLoop] addTimer: timer];
	[thread.runLoop addTimer: timer];

	if (waitUntilDone)
		[timer waitUntilDone];

	objc_autoreleasePoolPop(pool);
}

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







-
-
-
-
+
+
+
+











-
-
-
-
-
+
+
+
+
+












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













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














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








- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     afterDelay: (of_time_interval_t)delay
{
	void *pool = objc_autoreleasePoolPush();

	[[thread runLoop] addTimer: [OFTimer timerWithTimeInterval: delay
							    target: self
							  selector: selector
							   repeats: false]];
	[thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay
							  target: self
							selector: selector
							 repeats: false]];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (id)object
	     afterDelay: (of_time_interval_t)delay
{
	void *pool = objc_autoreleasePoolPush();

	[[thread runLoop] addTimer: [OFTimer timerWithTimeInterval: delay
							    target: self
							  selector: selector
							    object: object
							   repeats: false]];
	[thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay
							  target: self
							selector: selector
							  object: object
							 repeats: false]];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (id)object1
	     withObject: (id)object2
	     afterDelay: (of_time_interval_t)delay
{
	void *pool = objc_autoreleasePoolPush();

	[[thread runLoop] addTimer: [OFTimer timerWithTimeInterval: delay
							    target: self
							  selector: selector
							    object: object1
							    object: object2
							   repeats: false]];
	[thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay
							  target: self
							selector: selector
							  object: object1
							  object: object2
							 repeats: false]];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (id)object1
	     withObject: (id)object2
	     withObject: (id)object3
	     afterDelay: (of_time_interval_t)delay
{
	void *pool = objc_autoreleasePoolPush();

	[[thread runLoop] addTimer: [OFTimer timerWithTimeInterval: delay
							    target: self
							  selector: selector
							    object: object1
							    object: object2
							    object: object3
							   repeats: false]];
	[thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay
							  target: self
							selector: selector
							  object: object1
							  object: object2
							  object: object3
							 repeats: false]];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (id)object1
	     withObject: (id)object2
	     withObject: (id)object3
	     withObject: (id)object4
	     afterDelay: (of_time_interval_t)delay
{
	void *pool = objc_autoreleasePoolPush();

	[[thread runLoop] addTimer: [OFTimer timerWithTimeInterval: delay
							    target: self
							  selector: selector
							    object: object1
							    object: object2
							    object: object3
							    object: object4
							   repeats: false]];
	[thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay
							  target: self
							selector: selector
							  object: object1
							  object: object2
							  object: object3
							  object: object4
							 repeats: false]];

	objc_autoreleasePoolPop(pool);
}
#endif

- (OFMethodSignature *)methodSignatureForSelector: (SEL)selector
{
996
997
998
999
1000
1001
1002
1003

1004
1005
1006
1007
1008
1009
1010
996
997
998
999
1000
1001
1002

1003
1004
1005
1006
1007
1008
1009
1010







-
+







	return hash;
}

- (OFString *)description
{
	/* Classes containing data should reimplement this! */

	return [OFString stringWithFormat: @"<%@>", [self className]];
	return [OFString stringWithFormat: @"<%@>", self.className];
}

- (void *)allocMemoryWithSize: (size_t)size
{
	void *pointer;
	struct pre_mem *preMem;

Modified src/OFOptionsParser.m from [dbad6653d1] to [6af56770b0].

23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37







-
+







#import "OFMapTable.h"

#import "OFInvalidArgumentException.h"

static uint32_t
stringHash(void *object)
{
	return [(OFString *)object hash];
	return ((OFString *)object).hash;
}

static bool
stringEqual(void *object1, void *object2)
{
	return [(OFString *)object1 isEqual: (OFString *)object2];
}
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177
178
179

180
181
182
183
184
185
186
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186







-
+










-
+







}

- (of_unichar_t)nextOption
{
	of_options_parser_option_t *iter;
	OFString *argument;

	if (_done || _index >= [_arguments count])
	if (_done || _index >= _arguments.count)
		return '\0';

	[_lastLongOption release];
	[_argument release];
	_lastLongOption = nil;
	_argument = nil;

	argument = [_arguments objectAtIndex: _index];

	if (_subIndex == 0) {
		if ([argument length] < 2 ||
		if (argument.length < 2 ||
		    [argument characterAtIndex: 0] != '-') {
			_done = true;
			return '\0';
		}

		if ([argument isEqual: @"--"]) {
			_done = true;
195
196
197
198
199
200
201
202

203
204
205
206

207
208
209
210
211
212
213
195
196
197
198
199
200
201

202
203
204
205

206
207
208
209
210
211
212
213







-
+



-
+








			_lastOption = '-';
			_index++;

			if ((pos = [argument rangeOfString: @"="].location) !=
			    OF_NOT_FOUND) {
				of_range_t range = of_range(pos + 1,
				    [argument length] - pos - 1);
				    argument.length - pos - 1);
				_argument = [[argument
				    substringWithRange: range] copy];
			} else
				pos = [argument length];
				pos = argument.length;

			_lastLongOption = [[argument substringWithRange:
			    of_range(2, pos - 2)] copy];

			objc_autoreleasePoolPop(pool);

			option = [_longOptions objectForKey: _lastLongOption];
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259

260
261
262
263
264
265
266
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

254
255
256
257
258

259
260
261
262
263
264
265
266







-
+














-
+




-
+







		}

		_subIndex = 1;
	}

	_lastOption = [argument characterAtIndex: _subIndex++];

	if (_subIndex >= [argument length]) {
	if (_subIndex >= argument.length) {
		_index++;
		_subIndex = 0;
	}

	for (iter = _options;
	    iter->shortOption != '\0' || iter->longOption != nil; iter++) {
		if (iter->shortOption == _lastOption) {
			if (iter->hasArgument == 0) {
				if (iter->isSpecifiedPtr != NULL)
					*iter->isSpecifiedPtr = true;

				return _lastOption;
			}

			if (_index >= [_arguments count])
			if (_index >= _arguments.count)
				return ':';

			argument = [_arguments objectAtIndex: _index];
			argument = [argument substringWithRange:
			    of_range(_subIndex, [argument length] - _subIndex)];
			    of_range(_subIndex, argument.length - _subIndex)];

			_argument = [argument copy];

			if (iter->isSpecifiedPtr != NULL)
				*iter->isSpecifiedPtr = true;
			if (iter->argumentPtr != NULL)
				*iter->argumentPtr =
275
276
277
278
279
280
281
282

283
284
275
276
277
278
279
280
281

282
283
284







-
+



	return '?';
}

- (OFArray *)remainingArguments
{
	return [_arguments objectsInRange:
	    of_range(_index, [_arguments count] - _index)];
	    of_range(_index, _arguments.count - _index)];
}
@end

Modified src/OFPlugin.m from [edc663b796] to [503261dce9].

38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52







-
+







{
#ifndef OF_WINDOWS
	return dlopen([path cStringWithEncoding: [OFLocale encoding]], flags);
#else
	if (path == nil)
		return GetModuleHandle(NULL);

	return LoadLibraryW([path UTF16String]);
	return LoadLibraryW(path.UTF16String);
#endif
}

void *
of_dlsym(of_plugin_handle_t handle, const char *symbol)
{
#ifndef OF_WINDOWS
83
84
85
86
87
88
89
90

91
92
93

94
95
96
97
98
99
100
83
84
85
86
87
88
89

90
91
92

93
94
95
96
97
98
99
100







-
+


-
+







	void *pool = objc_autoreleasePoolPush();
	of_plugin_handle_t handle;
	init_plugin_t initPlugin;
	OFPlugin *plugin;

#if defined(OF_MACOS)
	path = [path stringByAppendingFormat: @".bundle/Contents/MacOS/%@",
					      [path lastPathComponent]];
					      path.lastPathComponent];
#elif defined(OF_IOS)
	path = [path stringByAppendingFormat: @".bundle/%@",
					      [path lastPathComponent]];
					      path.lastPathComponent];
#else
	path = [path stringByAppendingString: @PLUGIN_SUFFIX];
#endif

	if ((handle = of_dlopen(path, OF_RTLD_LAZY)) == NULL)
		@throw [OFLoadPluginFailedException
		    exceptionWithPath: path

Modified src/OFProcess.m from [ebfcdb4565] to [c46d227848].

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

214
215
216
217
218
219
220
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
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

213
214
215
216
217
218
219
220







-
+















-
+





-
+












-
+





-
+





-
+



















-
+







#ifndef OF_WINDOWS
		void *pool = objc_autoreleasePoolPush();
		const char *path;
		char **argv;

		if (pipe(_readPipe) != 0 || pipe(_writePipe) != 0)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		path = [program cStringWithEncoding: [OFLocale encoding]];
		[self of_getArgv: &argv
		  forProgramName: programName
		    andArguments: arguments];

		@try {
			char **env = [self
			    of_environmentForDictionary: environment];
# ifdef HAVE_POSIX_SPAWNP
			posix_spawn_file_actions_t actions;
			posix_spawnattr_t attr;

			if (posix_spawn_file_actions_init(&actions) != 0)
				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
				    exceptionWithClass: self.class];

			if (posix_spawnattr_init(&attr) != 0) {
				posix_spawn_file_actions_destroy(&actions);

				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
				    exceptionWithClass: self.class];
			}

			@try {
				if (posix_spawn_file_actions_addclose(&actions,
				    _readPipe[0]) != 0 ||
				    posix_spawn_file_actions_addclose(&actions,
				    _writePipe[1]) != 0 ||
				    posix_spawn_file_actions_adddup2(&actions,
				    _writePipe[0], 0) != 0 ||
				    posix_spawn_file_actions_adddup2(&actions,
				    _readPipe[1], 1) != 0)
					@throw [OFInitializationFailedException
					    exceptionWithClass: [self class]];
					    exceptionWithClass: self.class];

#  ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
				if (posix_spawnattr_setflags(&attr,
				    POSIX_SPAWN_CLOEXEC_DEFAULT) != 0)
					@throw [OFInitializationFailedException
					    exceptionWithClass: [self class]];
					    exceptionWithClass: self.class];
#  endif

				if (posix_spawnp(&_pid, path, &actions, &attr,
				    argv, env) != 0)
					@throw [OFInitializationFailedException
					    exceptionWithClass: [self class]];
					    exceptionWithClass: self.class];
			} @finally {
				posix_spawn_file_actions_destroy(&actions);
				posix_spawnattr_destroy(&attr);
			}
# else
			if ((_pid = vfork()) == 0) {
				environ = env;

				close(_readPipe[0]);
				close(_writePipe[1]);
				dup2(_writePipe[0], 0);
				dup2(_readPipe[1], 1);
				execvp(path, argv);

				_exit(EXIT_FAILURE);
			}

			if (_pid == -1)
				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
				    exceptionWithClass: self.class];
# endif
		} @finally {
			close(_readPipe[1]);
			close(_writePipe[0]);
			[self freeMemory: argv];
		}

230
231
232
233
234
235
236
237

238
239
240
241

242
243
244
245

246
247
248
249
250

251
252
253
254
255
256
257
230
231
232
233
234
235
236

237
238
239
240

241
242
243
244

245
246
247
248
249

250
251
252
253
254
255
256
257







-
+



-
+



-
+




-
+








		sa.nLength = sizeof(sa);
		sa.bInheritHandle = TRUE;
		sa.lpSecurityDescriptor = NULL;

		if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		if (!SetHandleInformation(_writePipe[1],
		    HANDLE_FLAG_INHERIT, 0))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		memset(&pi, 0, sizeof(pi));
		memset(&si, 0, sizeof(si));

		si.cb = sizeof(si);
		si.hStdInput = _writePipe[0];
		si.hStdOutput = _readPipe[1];
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
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







-
+


-
-
+
+

-
+





-
+








			[argumentsString appendString: tmp];

			if (containsSpaces)
				[argumentsString appendString: @"\""];
		}

		length = [argumentsString UTF16StringLength];
		length = argumentsString.UTF16StringLength;
		argumentsCopy = [self allocMemoryWithSize: sizeof(of_char16_t)
						    count: length + 1];
		memcpy(argumentsCopy, [argumentsString UTF16String],
		    ([argumentsString UTF16StringLength] + 1) * 2);
		memcpy(argumentsCopy, argumentsString.UTF16String,
		    (argumentsString.UTF16StringLength + 1) * 2);
		@try {
			if (!CreateProcessW([program UTF16String],
			if (!CreateProcessW(program.UTF16String,
			    argumentsCopy, NULL, NULL, TRUE,
			    CREATE_UNICODE_ENVIRONMENT,
			    [self of_environmentForDictionary: environment],
			    NULL, &si, &pi))
				@throw [OFInitializationFailedException
				    exceptionWithClass: [self class]];
				    exceptionWithClass: self.class];
		} @finally {
			[self freeMemory: argumentsCopy];
		}

		objc_autoreleasePoolPop(pool);

		_process = pi.hProcess;
334
335
336
337
338
339
340
341
342


343
344
345
346
347
348
349
334
335
336
337
338
339
340


341
342
343
344
345
346
347
348
349







-
-
+
+







}

#ifndef OF_WINDOWS
- (void)of_getArgv: (char ***)argv
    forProgramName: (OFString *)programName
      andArguments: (OFArray *)arguments
{
	OFString *const *objects = [arguments objects];
	size_t i, count = [arguments count];
	OFString *const *objects = arguments.objects;
	size_t i, count = arguments.count;
	of_string_encoding_t encoding;

	*argv = [self allocMemoryWithSize: sizeof(char *)
				    count: count + 2];

	encoding = [OFLocale encoding];

364
365
366
367
368
369
370
371

372
373
374
375
376
377
378
364
365
366
367
368
369
370

371
372
373
374
375
376
377
378







-
+







	of_string_encoding_t encoding;

	if (environment == nil)
		return NULL;

	encoding = [OFLocale encoding];

	count = [environment count];
	count = environment.count;
	envp = [self allocMemoryWithSize: sizeof(char *)
				   count: count + 1];

	keyEnumerator = [environment keyEnumerator];
	objectEnumerator = [environment objectEnumerator];

	for (i = 0; i < count; i++) {
413
414
415
416
417
418
419
420
421


422
423
424
425


426
427
428
429
430
431
432

433
434
435
436
437
438
439
413
414
415
416
417
418
419


420
421
422
423


424
425
426
427
428
429
430
431

432
433
434
435
436
437
438
439







-
-
+
+


-
-
+
+






-
+








	env = [OFMutableData dataWithItemSize: sizeof(of_char16_t)];

	keyEnumerator = [environment keyEnumerator];
	objectEnumerator = [environment objectEnumerator];
	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		[env addItems: [key UTF16String]
			count: [key UTF16StringLength]];
		[env addItems: key.UTF16String
			count: key.UTF16StringLength];
		[env addItems: &equal
			count: 1];
		[env addItems: [object UTF16String]
			count: [object UTF16StringLength]];
		[env addItems: object.UTF16String
			count: object.UTF16StringLength];
		[env addItems: &zero
			count: 1];
	}
	[env addItems: zero
		count: 2];

	return [env items];
	return env.items;
}
#endif

- (bool)lowlevelIsAtEndOfStream
{
#ifndef OF_WINDOWS
	if (_readPipe[0] == -1)

Modified src/OFRIPEMD160Hash.m from [089b540858] to [3842b26a7e].

154
155
156
157
158
159
160
161

162
163
164
165
166
167
168
154
155
156
157
158
159
160

161
162
163
164
165
166
167
168







-
+







- (instancetype)init
{
	self = [super init];

	@try {
		_iVarsData = [[OFSecureData alloc]
		    initWithCount: sizeof(*_iVars)];
		_iVars = [_iVarsData items];
		_iVars = _iVarsData.mutableItems;

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

182
183
184
185
186
187
188
189

190
191
192
193
194
195
196
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196







-
+







}

- (id)copy
{
	OFRIPEMD160Hash *copy = [[OFRIPEMD160Hash alloc] of_init];

	copy->_iVarsData = [_iVarsData copy];
	copy->_iVars = [copy->_iVarsData items];
	copy->_iVars = copy->_iVarsData.mutableItems;
	copy->_calculated = _calculated;

	return copy;
}

- (void)of_resetState
{

Modified src/OFRecursiveMutex.m from [866049a019] to [2beeb530a3].

34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48







-
+







}

- (instancetype)init
{
	self = [super init];

	if (!of_rmutex_new(&_rmutex)) {
		Class c = [self class];
		Class c = self.class;
		[self release];
		@throw [OFInitializationFailedException exceptionWithClass: c];
	}

	_initialized = true;

	return self;
75
76
77
78
79
80
81
82

83
84

85
86
87
75
76
77
78
79
80
81

82
83

84

85
86







-
+

-
+
-


	if (!of_rmutex_unlock(&_rmutex))
		@throw [OFUnlockFailedException exceptionWithLock: self];
}

- (OFString *)description
{
	if (_name == nil)
		return [super description];
		return super.description;

	return [OFString stringWithFormat: @"<%@: %@>",
	return [OFString stringWithFormat: @"<%@: %@>", self.className, _name];
					   [self className], _name];
}
@end

Modified src/OFRunLoop+Private.h from [3fce6b275d] to [b6012d804d].

24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
24
25
26
27
28
29
30

31
32
33
34
35
36
37
38







-
+








OF_ASSUME_NONNULL_BEGIN

@class OFRunLoop_State;

#ifdef OF_HAVE_SOCKETS
@protocol OFTCPSocketDelegate_Private <OFObject>
- (void)of_socketDidConnect: (OF_KINDOF(OFTCPSocket *))socket
- (void)of_socketDidConnect: (OFTCPSocket *)socket
		  exception: (nullable id)exception;
@end
#endif

@interface OFRunLoop ()
+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop;
#ifdef OF_HAVE_SOCKETS

Modified src/OFRunLoop.m from [f76ad8e6f6] to [355a023a1d].

179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
179
180
181
182
183
184
185

186
187
188
189
190
191
192
193







-
+







	self = [super init];

	@try {
		_timersQueue = [[OFSortedList alloc] init];

#if defined(OF_HAVE_SOCKETS)
		_kernelEventObserver = [[OFKernelEventObserver alloc] init];
		[_kernelEventObserver setDelegate: self];
		_kernelEventObserver.delegate = self;

		_readQueues = [[OFMutableDictionary alloc] init];
		_writeQueues = [[OFMutableDictionary alloc] init];
#elif defined(OF_HAVE_THREADS)
		_condition = [[OFCondition alloc] init];
#endif
	} @catch (id e) {
221
222
223
224
225
226
227
228
229


230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

248
249
250
251
252
253
254
221
222
223
224
225
226
227


228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

247
248
249
250
251
252
253
254







-
-
+
+

















-
+







	 */
	OFList OF_GENERIC(OF_KINDOF(OFRunLoop_ReadQueueItem *)) *queue =
	    [[_readQueues objectForKey: object] retain];

	assert(queue != nil);

	@try {
		if (![[queue firstObject] handleObject: object]) {
			of_list_object_t *listObject = [queue firstListObject];
		if (![queue.firstObject handleObject: object]) {
			of_list_object_t *listObject = queue.firstListObject;

			/*
			 * The handler might have called -[cancelAsyncRequests]
			 * so that our queue is now empty, in which case we
			 * should do nothing.
			 */
			if (listObject != NULL) {
				/*
				 * Make sure we keep the target until after we
				 * are done removing the object. The reason for
				 * this is that the target might call
				 * -[cancelAsyncRequests] in its dealloc.
				 */
				[[listObject->object retain] autorelease];

				[queue removeListObject: listObject];

				if ([queue count] == 0) {
				if (queue.count == 0) {
					[_kernelEventObserver
					    removeObjectForReading: object];
					[_readQueues
					    removeObjectForKey: object];
				}
			}
		}
264
265
266
267
268
269
270
271
272


273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
264
265
266
267
268
269
270


271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289

290
291
292
293
294
295
296
297







-
-
+
+

















-
+







	 * handler called -[cancelAsyncRequests].
	 */
	OFList *queue = [[_writeQueues objectForKey: object] retain];

	assert(queue != nil);

	@try {
		if (![[queue firstObject] handleObject: object]) {
			of_list_object_t *listObject = [queue firstListObject];
		if (![queue.firstObject handleObject: object]) {
			of_list_object_t *listObject = queue.firstListObject;

			/*
			 * The handler might have called -[cancelAsyncRequests]
			 * so that our queue is now empty, in which case we
			 * should do nothing.
			 */
			if (listObject != NULL) {
				/*
				 * Make sure we keep the target until after we
				 * are done removing the object. The reason for
				 * this is that the target might call
				 * -[cancelAsyncRequests] in its dealloc.
				 */
				[[listObject->object retain] autorelease];

				[queue removeListObject: listObject];

				if ([queue count] == 0) {
				if (queue.count == 0) {
					[_kernelEventObserver
					    removeObjectForWriting: object];
					[_writeQueues
					    removeObjectForKey: object];
				}
			}
		}
459
460
461
462
463
464
465
466

467
468
469
470

471
472
473
474
475
476
477
459
460
461
462
463
464
465

466
467
468
469

470
471
472
473
474
475
476
477







-
+



-
+







@end

@implementation OFRunLoop_WriteDataQueueItem
- (bool)handleObject: (id)object
{
	size_t length;
	id exception = nil;
	size_t dataLength = [_data count] * [_data itemSize];
	size_t dataLength = _data.count * _data.itemSize;
	OFData *newData, *oldData;

	@try {
		const char *dataItems = [_data items];
		const char *dataItems = _data.items;

		length = [object writeBuffer: dataItems + _writtenLength
				      length: dataLength - _writtenLength];
	} @catch (id e) {
		length = 0;
		exception = e;
	}
716
717
718
719
720
721
722
723
724


725
726
727
728
729
730
731
716
717
718
719
720
721
722


723
724
725
726
727
728
729
730
731







-
-
+
+







@implementation OFRunLoop_UDPSendQueueItem
- (bool)handleObject: (id)object
{
	id exception = nil;
	OFData *newData, *oldData;

	@try {
		[object sendBuffer: [_data items]
			    length: [_data count] * [_data itemSize]
		[object sendBuffer: _data.items
			    length: _data.count * _data.itemSize
			  receiver: &_receiver];
	} @catch (id e) {
		exception = e;
	}

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL) {
782
783
784
785
786
787
788
789

790
791
792
793
794
795
796
782
783
784
785
786
787
788

789
790
791
792
793
794
795
796







-
+







{
	return mainRunLoop;
}

+ (OFRunLoop *)currentRunLoop
{
#ifdef OF_HAVE_THREADS
	return [[OFThread currentThread] runLoop];
	return [OFThread currentThread].runLoop;
#else
	return [self mainRunLoop];
#endif
}

+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop
{
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
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







-
+


-
+


















-
+







						   create: true];	\
	OFList *queue = [state->_readQueues objectForKey: object];	\
	type *queueItem;						\
									\
	if (queue == nil) {						\
		queue = [OFList list];					\
		[state->_readQueues setObject: queue			\
					 forKey: object];		\
				       forKey: object];			\
	}								\
									\
	if ([queue count] == 0)						\
	if (queue.count == 0)						\
		[state->_kernelEventObserver				\
		    addObjectForReading: object];			\
									\
	queueItem = [[[type alloc] init] autorelease];
# define NEW_WRITE(type, object, mode)					\
	void *pool = objc_autoreleasePoolPush();			\
	OFRunLoop *runLoop = [self currentRunLoop];			\
	OFRunLoop_State *state = [runLoop of_stateForMode: mode		\
						   create: true];	\
	OFList *queue = [state->_writeQueues objectForKey: object];	\
	type *queueItem;						\
									\
	if (queue == nil) {						\
		queue = [OFList list];					\
		[state->_writeQueues setObject: queue			\
					  forKey: object];		\
	}								\
									\
	if ([queue count] == 0)						\
	if (queue.count == 0)						\
		[state->_kernelEventObserver				\
		    addObjectForWriting: object];			\
									\
	queueItem = [[[type alloc] init] autorelease];
#define QUEUE_ITEM							\
	[queue appendObject: queueItem];				\
									\
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
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







-
+












-
+







						   create: false];
	OFList *queue;

	if (state == nil)
		return;

	if ((queue = [state->_writeQueues objectForKey: object]) != nil) {
		assert([queue count] > 0);
		assert(queue.count > 0);

		/*
		 * Clear the queue now, in case this has been called from a
		 * handler, as otherwise, we'd do the cleanups below twice.
		 */
		[queue removeAllObjects];

		[state->_kernelEventObserver removeObjectForWriting: object];
		[state->_writeQueues removeObjectForKey: object];
	}

	if ((queue = [state->_readQueues objectForKey: object]) != nil) {
		assert([queue count] > 0);
		assert(queue.count > 0);

		/*
		 * Clear the queue now, in case this has been called from a
		 * handler, as otherwise, we'd do the cleanups below twice.
		 */
		[queue removeAllObjects];

1178
1179
1180
1181
1182
1183
1184
1185

1186
1187
1188
1189
1190
1191
1192
1178
1179
1180
1181
1182
1183
1184

1185
1186
1187
1188
1189
1190
1191
1192







-
+








#ifdef OF_HAVE_THREADS
	[state->_timersQueueMutex lock];
	@try {
#endif
		of_list_object_t *iter;

		for (iter = [state->_timersQueue firstListObject]; iter != NULL;
		for (iter = state->_timersQueue.firstListObject; iter != NULL;
		    iter = iter->next) {
			if ([iter->object isEqual: timer]) {
				[state->_timersQueue removeListObject: iter];
				break;
			}
		}
#ifdef OF_HAVE_THREADS
1202
1203
1204
1205
1206
1207
1208
1209

1210
1211
1212
1213
1214
1215
1216
1202
1203
1204
1205
1206
1207
1208

1209
1210
1211
1212
1213
1214
1215
1216







-
+







}

- (void)runUntilDate: (OFDate *)deadline
{
	_stop = false;

	while (!_stop &&
	    (deadline == nil || [deadline timeIntervalSinceNow] >= 0))
	    (deadline == nil || deadline.timeIntervalSinceNow >= 0))
		[self runMode: of_run_loop_mode_default
		   beforeDate: deadline];
}

- (void)runMode: (of_run_loop_mode_t)mode
     beforeDate: (OFDate *)deadline
{
1230
1231
1232
1233
1234
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
1260
1261
1262
1263
1264
1230
1231
1232
1233
1234
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
1260
1261
1262
1263
1264







-
+

-
-
+
+
















-
+







			OFTimer *timer;

#ifdef OF_HAVE_THREADS
			[state->_timersQueueMutex lock];
			@try {
#endif
				of_list_object_t *listObject =
				    [state->_timersQueue firstListObject];
				    state->_timersQueue.firstListObject;

				if (listObject != NULL && [[listObject->object
				    fireDate] timeIntervalSinceNow] <= 0) {
				if (listObject != NULL && [listObject->object
				    fireDate].timeIntervalSinceNow <= 0) {
					timer = [[listObject->object
					    retain] autorelease];

					[state->_timersQueue
					    removeListObject: listObject];

					[timer of_setInRunLoop: nil
							  mode: nil];
				} else
					break;
#ifdef OF_HAVE_THREADS
			} @finally {
				[state->_timersQueueMutex unlock];
			}
#endif

			if ([timer isValid]) {
			if (timer.valid) {
				[timer fire];
				return;
			}
		}

#ifdef OF_HAVE_THREADS
		[state->_timersQueueMutex lock];
1273
1274
1275
1276
1277
1278
1279
1280

1281
1282

1283
1284
1285


1286
1287
1288
1289
1290
1291
1292
1293
1294
1295

1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315

1316
1317
1318
1319
1320
1321
1322
1273
1274
1275
1276
1277
1278
1279

1280
1281

1282
1283


1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294

1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314

1315
1316
1317
1318
1319
1320
1321
1322







-
+

-
+

-
-
+
+









-
+



















-
+







#endif

		/* Watch for I/O events until the next timer is due */
		if (nextTimer != nil || deadline != nil) {
			of_time_interval_t timeout;

			if (nextTimer != nil && deadline == nil)
				timeout = [nextTimer timeIntervalSinceNow];
				timeout = nextTimer.timeIntervalSinceNow;
			else if (nextTimer == nil && deadline != nil)
				timeout = [deadline timeIntervalSinceNow];
				timeout = deadline.timeIntervalSinceNow;
			else
				timeout = [[nextTimer earlierDate: deadline]
				    timeIntervalSinceNow];
				timeout = [nextTimer earlierDate: deadline]
				    .timeIntervalSinceNow;

			if (timeout < 0)
				timeout = 0;

#if defined(OF_HAVE_SOCKETS)
			@try {
				[state->_kernelEventObserver
				    observeForTimeInterval: timeout];
			} @catch (OFObserveFailedException *e) {
				if ([e errNo] != EINTR)
				if (e.errNo != EINTR)
					@throw e;
			}
#elif defined(OF_HAVE_THREADS)
			[state->_condition lock];
			[state->_condition waitForTimeInterval: timeout];
			[state->_condition unlock];
#else
			[OFThread sleepForTimeInterval: timeout];
#endif
		} else {
			/*
			 * No more timers and no deadline: Just watch for I/O
			 * until we get an event. If a timer is added by
			 * another thread, it cancels the observe.
			 */
#if defined(OF_HAVE_SOCKETS)
			@try {
				[state->_kernelEventObserver observe];
			} @catch (OFObserveFailedException *e) {
				if ([e errNo] != EINTR)
				if (e.errNo != EINTR)
					@throw e;
			}
#elif defined(OF_HAVE_THREADS)
			[state->_condition lock];
			[state->_condition wait];
			[state->_condition unlock];
#else

Modified src/OFSHA1Hash.m from [6f8e28171c] to [15c7c9a7a5].

114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128







-
+







- (instancetype)init
{
	self = [super init];

	@try {
		_iVarsData = [[OFSecureData alloc]
		    initWithCount: sizeof(*_iVars)];
		_iVars = [_iVarsData items];
		_iVars = _iVarsData.mutableItems;

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

142
143
144
145
146
147
148
149

150
151
152
153
154
155
156
142
143
144
145
146
147
148

149
150
151
152
153
154
155
156







-
+







}

- (id)copy
{
	OFSHA1Hash *copy = [[OFSHA1Hash alloc] of_init];

	copy->_iVarsData = [_iVarsData copy];
	copy->_iVars = [copy->_iVarsData items];
	copy->_iVars = copy->_iVarsData.mutableItems;
	copy->_calculated = _calculated;

	return copy;
}

- (void)of_resetState
{

Modified src/OFSHA224Or256Hash.m from [86260419b7] to [01186e5528].

136
137
138
139
140
141
142
143

144
145

146
147
148
149
150
151
152
136
137
138
139
140
141
142

143
144

145
146
147
148
149
150
151
152







-
+

-
+







- (instancetype)init
{
	self = [super init];

	@try {
		_iVarsData = [[OFSecureData alloc]
		    initWithCount: sizeof(*_iVars)];
		_iVars = [_iVarsData items];
		_iVars = _iVarsData.mutableItems;

		if ([self class] == [OFSHA224Or256Hash class]) {
		if (self.class == [OFSHA224Or256Hash class]) {
			[self doesNotRecognizeSelector: _cmd];
			abort();
		}

		[self of_resetState];
	} @catch (id e) {
		[self release];
169
170
171
172
173
174
175
176

177
178
179
180
181
182
183
169
170
171
172
173
174
175

176
177
178
179
180
181
182
183







-
+







}

- (id)copy
{
	OFSHA224Or256Hash *copy = [[[self class] alloc] of_init];

	copy->_iVarsData = [_iVarsData copy];
	copy->_iVars = [copy->_iVarsData items];
	copy->_iVars = copy->_iVarsData.mutableItems;
	copy->_calculated = _calculated;

	return copy;
}

- (void)updateWithBuffer: (const void *)buffer_
		  length: (size_t)length

Modified src/OFSHA384Or512Hash.m from [9b71b4cd6a] to [af9afb2e15].

147
148
149
150
151
152
153
154

155
156

157
158
159
160
161
162
163
147
148
149
150
151
152
153

154
155

156
157
158
159
160
161
162
163







-
+

-
+







- (instancetype)init
{
	self = [super init];

	@try {
		_iVarsData = [[OFSecureData alloc]
		    initWithCount: sizeof(*_iVars)];
		_iVars = [_iVarsData items];
		_iVars = _iVarsData.mutableItems;

		if ([self class] == [OFSHA384Or512Hash class]) {
		if (self.class == [OFSHA384Or512Hash class]) {
			[self doesNotRecognizeSelector: _cmd];
			abort();
		}

		[self of_resetState];
	} @catch (id e) {
		[self release];
180
181
182
183
184
185
186
187

188
189
190
191
192
193
194
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194







-
+







}

- (id)copy
{
	OFSHA384Or512Hash *copy = [[[self class] alloc] of_init];

	copy->_iVarsData = [_iVarsData copy];
	copy->_iVars = [copy->_iVarsData items];
	copy->_iVars = copy->_iVarsData.mutableItems;
	copy->_calculated = _calculated;

	return copy;
}

- (void)updateWithBuffer: (const void *)buffer_
		  length: (size_t)length

Modified src/OFSecureData.h from [6e70789148] to [6b81b595f7].

33
34
35
36
37
38
39








40
41
42
43
44
45
46
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54







+
+
+
+
+
+
+
+







	struct page *_page;
}

#ifdef OF_HAVE_CLASS_PROPERTIES
@property (class, readonly, nonatomic, getter=isSecure) bool secure;
#endif

/*!
 * @brief All items of the OFSecureData as a C array.
 *
 * Modifying the returned array directly is allowed and will change the contents
 * of the data.
 */
@property (readonly, nonatomic) void *mutableItems OF_RETURNS_INNER_POINTER;

/*!
 * @brief Whether OFSecureData is secure, meaning preventing the data from
 *	  being swapped out is supported.
 */
+ (bool)isSecure;

/*!
101
102
103
104
105
106
107











108
109
110
111
112
113
114
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







+
+
+
+
+
+
+
+
+
+
+







 * @param itemSize The size of a single item in the OFSecureData in bytes
 * @param count The number of zero items the OFSecureData should contain
 * @return An initialized OFSecureData
 */
- (instancetype)initWithItemSize: (size_t)itemSize
			   count: (size_t)count;

/*!
 * @brief Returns a specific item of the OFSecureData.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data array.
 *
 * @param index The number of the item to return
 * @return The specified item of the OFSecureData
 */
- (void *)mutableItemAtIndex: (size_t)index OF_RETURNS_INNER_POINTER;

/*!
 * @brief Checks the OFSecureData for equality to another object.
 *
 * If the specified object is a subclass of @ref OFData, the comparison is
 * performed in constant time.
 *
 * @param object The object which should be tested for equality
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
183
184
185
186
187
153
154
155
156
157
158
159














































160







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

- (void)writeToFile: (OFString *)path OF_UNAVAILABLE;
#endif
- (void)writeToURL: (OFURL *)URL OF_UNAVAILABLE;
- (OFXMLElement *)XMLElementBySerializing OF_UNAVAILABLE;
- (OFData *)messagePackRepresentation OF_UNAVAILABLE;
@end

@interface OFSecureData (MutableRetrieving)
/* GCC does not like overriding properties with a different type. */
#if defined(__clang__) || defined(DOXYGEN)
/*!
 * @brief All items of the OFSecureData as a C array.
 *
 * Modifying the returned array directly is allowed and will change the contents
 * of the data.
 */
@property (readonly, nonatomic) void *items OF_RETURNS_INNER_POINTER;

/*!
 * @brief The first item of the OFSecureData or `NULL`.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *firstItem
    OF_RETURNS_INNER_POINTER;

/*!
 * @brief Last item of the OFSecureData or `NULL`.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *lastItem
    OF_RETURNS_INNER_POINTER;
#else
- (void *)items;
- (nullable void *)firstItem;
- (nullable void *)lastItem;
#endif

/*!
 * @brief Returns a specific item of the OFSecureData.
 *
 * Modifying the returned item directly is allowed and will change the contents
 * of the data array.
 *
 * @param index The number of the item to return
 * @return The specified item of the OFSecureData
 */
- (void *)itemAtIndex: (size_t)index OF_RETURNS_INNER_POINTER;
@end

OF_ASSUME_NONNULL_END

Modified src/OFSecureData.m from [e8696d3e65] to [e075377cde].

504
505
506
507
508
509
510













511
512
513
514
515
516
517
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







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







			freeMemory(_page, _items, _count * _itemSize);

		removePageIfEmpty(_page);
	}

	[super dealloc];
}

- (void *)mutableItems
{
	return _items;
}

- (void *)mutableItemAtIndex: (size_t)idx
{
	if (idx >= _count)
		@throw [OFOutOfRangeException exception];

	return _items + idx * _itemSize;
}

- (void)zero
{
	of_explicit_memset(_items, 0, _count * _itemSize);
}

- (id)copy

Modified src/OFSet.m from [dff1ba0f37] to [136b012e98].

215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257







-
+







-
+



















-
+







- (id)valueForKey: (OFString *)key
{
	id ret;

	if ([key hasPrefix: @"@"]) {
		void *pool = objc_autoreleasePoolPush();

		key = [key substringWithRange: of_range(1, [key length] - 1)];
		key = [key substringWithRange: of_range(1, key.length - 1)];
		ret = [[super valueForKey: key] retain];

		objc_autoreleasePoolPop(pool);

		return [ret autorelease];
	}

	ret = [OFMutableSet setWithCapacity: [self count]];
	ret = [OFMutableSet setWithCapacity: self.count];

	for (id object in self) {
		id value = [object valueForKey: key];

		if (value != nil)
			[ret addObject: value];
	}

	[ret makeImmutable];

	return ret;
}

- (void)setValue: (id)value
	  forKey: (OFString *)key
{
	if ([key hasPrefix: @"@"]) {
		void *pool = objc_autoreleasePoolPush();

		key = [key substringWithRange: of_range(1, [key length] - 1)];
		key = [key substringWithRange: of_range(1, key.length - 1)];
		[super setValue: value
			 forKey: key];

		objc_autoreleasePoolPop(pool);
		return;
	}

285
286
287
288
289
290
291
292

293
294
295
296
297
298
299
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299







-
+







		return true;

	if (![object isKindOfClass: [OFSet class]])
		return false;

	set = object;

	if ([set count] != [self count])
	if (set.count != self.count)
		return false;

	return [set isSubsetOfSet: self];
}

- (uint32_t)hash
{
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322







-
+







	return hash;
}

- (OFString *)description
{
	void *pool;
	OFMutableString *ret;
	size_t i, count = [self count];
	size_t i, count = self.count;

	if (count == 0)
		return @"{()}";

	ret = [OFMutableString stringWithString: @"{(\n"];

	pool = objc_autoreleasePoolPush();
382
383
384
385
386
387
388
389

390
391
392
393
394
395
396
382
383
384
385
386
387
388

389
390
391
392
393
394
395
396







-
+







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

	for (id <OFSerialization> object in self) {
		void *pool2 = objc_autoreleasePoolPush();

		[element addChild: [object XMLElementBySerializing]];
		[element addChild: object.XMLElementBySerializing];

		objc_autoreleasePoolPop(pool2);
	}

	[element retain];

	objc_autoreleasePoolPop(pool);

Modified src/OFSet_hashtable.m from [bc1b122bdb] to [58bc1233e4].

88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
88
89
90
91
92
93
94

95
96
97
98
99
100
101
102







-
+







{
	size_t count;

	if (set == nil)
		return [self init];

	@try {
		count = [set count];
		count = set.count;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithCapacity: count];

116
117
118
119
120
121
122
123

124
125
126
127
128
129
130
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130







-
+







{
	size_t count;

	if (array == nil)
		return self;

	@try {
		count = [array count];
		count = array.count;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithCapacity: count];

193
194
195
196
197
198
199
200
201
202



203
204
205
206
207
208
209
193
194
195
196
197
198
199



200
201
202
203
204
205
206
207
208
209







-
-
-
+
+
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if ((![[element name] isEqual: @"OFSet"] &&
		    ![[element name] isEqual: @"OFMutableSet"]) ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if ((![element.name isEqual: @"OFSet"] &&
		    ![element.name isEqual: @"OFMutableSet"]) ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		for (OFXMLElement *child in
		    [element elementsForNamespace: OF_SERIALIZATION_NS]) {
			void *pool2  = objc_autoreleasePoolPush();

			[_mapTable setObject: (void *)1

Modified src/OFSettings_INIFile.m from [3e8385c835] to [4d0ca9211c].

65
66
67
68
69
70
71
72

73
74
75
76
77
78
79
65
66
67
68
69
70
71

72
73
74
75
76
77
78
79







-
+







		*category = @"";
		*key = path;
		return;
	}

	*category = [path substringWithRange: of_range(0, pos)];
	*key = [path substringWithRange:
	    of_range(pos + 1, [path length] - pos - 1)];
	    of_range(pos + 1, path.length - pos - 1)];
}

- (void)setString: (OFString *)string
	  forPath: (OFString *)path
{
	void *pool = objc_autoreleasePoolPush();
	OFString *category, *key;

Modified src/OFStdIOStream.m from [0fdbb22bb2] to [416043c557].

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







-
+










-
+







	OFDate *date;
	OFString *dateString, *me, *msg;
	va_list arguments;

	date = [OFDate date];
	dateString = [date localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"];
#ifdef OF_HAVE_FILES
	me = [[OFApplication programName] lastPathComponent];
	me = [OFApplication programName].lastPathComponent;
#else
	me = [OFApplication programName];
#endif

	va_start(arguments, format);
	msg = [[[OFString alloc] initWithFormat: format
				      arguments: arguments] autorelease];
	va_end(arguments);

	[of_stderr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString,
				[date microsecond] / 1000, me, getpid(), msg];
				date.microsecond / 1000, me, getpid(), msg];

	objc_autoreleasePoolPop(pool);
}

@implementation OFStdIOStream
#ifndef OF_WINDOWS
+ (void)load

Modified src/OFStdIOStream_Win32Console.m from [8796f50f42] to [801fb56bc9].

164
165
166
167
168
169
170
171
172


173
174
175
176
177
178
179
164
165
166
167
168
169
170


171
172
173
174
175
176
177
178
179







-
-
+
+







			if ((c & 0xFC00) == 0xD800) {
				of_char16_t next;

				if (UTF16Len <= i + 1) {
					_incompleteUTF16Surrogate = c;

					if (rest != nil) {
						char *items = [rest items];
						size_t count = [rest count];
						char *items = rest.items;
						size_t count = rest.count;

						[self unreadFromBuffer: items
								length: count];
					}

					objc_autoreleasePoolPop(pool);

204
205
206
207
208
209
210
211
212


213
214
215
216
217
218
219
204
205
206
207
208
209
210


211
212
213
214
215
216
217
218
219







-
-
+
+








				[rest addItems: UTF8
					 count: UTF8Len];
			}
		}

		if (rest != nil)
			[self unreadFromBuffer: [rest items]
					length: [rest count]];
			[self unreadFromBuffer: rest.items
					length: rest.count];
	} @finally {
		[self freeMemory: UTF16];
	}

	objc_autoreleasePoolPop(pool);

	return j;

Modified src/OFStream.h from [ea84bca9b5] to [437fb045ff].

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







-
+
-
-
+












-
+
-
-
+














-
+
















-
+




















-
+














-
+















-
+

















-
+







 * @param stream The stream on which data was read
 * @param buffer A buffer with the data that has been read
 * @param length The length of the data that has been read
 * @param exception An exception which occurred while reading or `nil` on
 *		    success
 * @return A bool whether the same block should be used for the next read
 */
typedef bool (^of_stream_async_read_block_t)(
typedef bool (^of_stream_async_read_block_t)(OFStream *_Nonnull stream,
    OF_KINDOF(OFStream *) _Nonnull stream, void *_Nonnull buffer,
    size_t length, id _Nullable exception);
    void *_Nonnull buffer, size_t length, id _Nullable exception);

/*!
 * @brief A block which is called when a line was read asynchronously from a
 *	  stream.
 *
 * @param stream The stream on which a line was read
 * @param line The line which has been read or `nil` when the end of stream
 *	       occurred
 * @param exception An exception which occurred while reading or `nil` on
 *		    success
 * @return A bool whether the same block should be used for the next read
 */
typedef bool (^of_stream_async_read_line_block_t)(
typedef bool (^of_stream_async_read_line_block_t)(OFStream *_Nonnull stream,
    OF_KINDOF(OFStream *) _Nonnull stream, OFString *_Nullable line,
    id _Nullable exception);
    OFString *_Nullable line, id _Nullable exception);

/*!
 * @brief A block which is called when data was written asynchronously to a
 *	  stream.
 *
 * @param data The data which was written to the stream
 * @param bytesWritten The number of bytes which have been written. This
 *		       matches the length of the specified data on the
 *		       asynchronous write if no exception was encountered.
 * @param exception An exception which occurred while writing or `nil` on
 *		    success
 * @return The data to repeat the write with or nil if it should not repeat
 */
typedef OFData *_Nullable (^of_stream_async_write_data_block_t)(
    OF_KINDOF(OFStream *) _Nonnull stream, OFData *_Nonnull data,
    OFStream *_Nonnull stream, OFData *_Nonnull data,
    size_t bytesWritten, id _Nullable exception);

/*!
 * @brief A block which is called when a string was written asynchronously to a
 *	  stream.
 *
 * @param string The string which was written to the stream
 * @param bytesWritten The number of bytes which have been written. This
 *		       matches the length of the specified data on the
 *		       asynchronous write if no exception was encountered.
 * @param encoding The encoding in which the string was written
 * @param exception An exception which occurred while writing or `nil` on
 *		    success
 * @return The string to repeat the write with or nil if it should not repeat
 */
typedef OFString *_Nullable (^of_stream_async_write_string_block_t)(
    OF_KINDOF(OFStream *) _Nonnull stream, OFString *_Nonnull string,
    OFStream *_Nonnull stream, OFString *_Nonnull string,
    of_string_encoding_t encoding, size_t bytesWritten, id _Nullable exception);
#endif

/*!
 * @protocol OFStreamDelegate OFStream.h ObjFW/OFStream.h
 *
 * A delegate for OFStream.
 */
@protocol OFStreamDelegate <OFObject>
@optional
/*!
 * @brief This method is called when data was read asynchronously from a
 *	  stream.
 *
 * @param stream The stream on which data was read
 * @param buffer A buffer with the data that has been read
 * @param length The length of the data that has been read
 * @param exception An exception that occurred while reading, or nil on success
 * @return A bool whether the read should be repeated
 */
-      (bool)stream: (OF_KINDOF(OFStream *))stream
-      (bool)stream: (OFStream *)stream
  didReadIntoBuffer: (void *)buffer
	     length: (size_t)length
	  exception: (nullable id)exception;

/*!
 * @brief This method is called when a line was read asynchronously from a
 *	  stream.
 *
 * @param stream The stream on which a line was read
 * @param line The line which has been read or `nil` when the end of stream
 *	       occurred
 * @param exception An exception that occurred while reading, or nil on success
 * @return A bool whether the read should be repeated
 */
- (bool)stream: (OF_KINDOF(OFStream *))stream
- (bool)stream: (OFStream *)stream
   didReadLine: (nullable OFString *)line
     exception: (nullable id)exception;

/*!
 * @brief This method is called when data was written asynchronously to a
 *	  stream.
 *
 * @param stream The stream to which data was written
 * @param data The data which was written to the stream
 * @param bytesWritten The number of bytes which have been written. This
 *		       matches the length of the specified data on the
 *		       asynchronous write if no exception was encountered.
 * @param exception An exception that occurred while writing, or nil on success
 * @return The data to repeat the write with or nil if it should not repeat
 */
- (nullable OFData *)stream: (OF_KINDOF(OFStream *))stream
- (nullable OFData *)stream: (OFStream *)stream
	       didWriteData: (OFData *)data
	       bytesWritten: (size_t)bytesWritten
		  exception: (nullable id)exception;

/*!
 * @brief This method is called when a string was written asynchronously to a
 *	  stream.
 *
 * @param stream The stream to which a string was written
 * @param string The string which was written to the stream
 * @param encoding The encoding in which the string was written
 * @param bytesWritten The number of bytes which have been written. This
 *		       matches the length of the specified data on the
 *		       asynchronous write if no exception was encountered.
 * @param exception An exception that occurred while writing, or nil on success
 * @return The string to repeat the write with or nil if it should not repeat
 */
- (nullable OFString *)stream: (OF_KINDOF(OFStream *))stream
- (nullable OFString *)stream: (OFStream *)stream
	       didWriteString: (OFString *)string
		     encoding: (of_string_encoding_t)encoding
		 bytesWritten: (size_t)bytesWritten
		    exception: (nullable id)exception;
@end

/*!

Modified src/OFStream.m from [3a06b598ab] to [9042aa5323].

182
183
184
185
186
187
188
189

190
191
192
193
194
195
196
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196







-
+








- (void)readIntoBuffer: (void *)buffer
	   exactLength: (size_t)length
{
	size_t readLength = 0;

	while (readLength < length) {
		if ([self isAtEndOfStream])
		if (self.atEndOfStream)
			@throw [OFTruncatedDataException exception];

		readLength += [self readIntoBuffer: (char *)buffer + readLength
					    length: length - readLength];
	}
}

658
659
660
661
662
663
664
665

666
667
668
669
670
671
672
658
659
660
661
662
663
664

665
666
667
668
669
670
671
672







-
+







- (OFData *)readDataUntilEndOfStream
{
	OFMutableData *data = [OFMutableData data];
	size_t pageSize = [OFSystemInfo pageSize];
	char *buffer = [self allocMemoryWithSize: pageSize];

	@try {
		while (![self isAtEndOfStream]) {
		while (!self.atEndOfStream) {
			size_t length;

			length = [self readIntoBuffer: buffer
					       length: pageSize];
			[data addItems: buffer
				 count: length];
		}
863
864
865
866
867
868
869
870

871
872
873
874
875
876
877
863
864
865
866
867
868
869

870
871
872
873
874
875
876
877







-
+







}

- (OFString *)readLineWithEncoding: (of_string_encoding_t)encoding
{
	OFString *line = nil;

	while ((line = [self tryReadLineWithEncoding: encoding]) == nil)
		if ([self isAtEndOfStream])
		if (self.atEndOfStream)
			return nil;

	return line;
}

#ifdef OF_HAVE_SOCKETS
- (void)asyncReadLine
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120

1121
1122
1123
1124
1125
1126
1127
1110
1111
1112
1113
1114
1115
1116

1117
1118

1119
1120
1121
1122
1123
1124
1125
1126







-


-
+







}

- (OFString *)readTillDelimiter: (OFString *)delimiter
		       encoding: (of_string_encoding_t)encoding
{
	OFString *ret = nil;


	while ((ret = [self tryReadTillDelimiter: delimiter
					encoding: encoding]) == nil)
		if ([self isAtEndOfStream])
		if (self.atEndOfStream)
			return nil;

	return ret;
}

- (OFString *)tryReadTillDelimiter: (OFString *)delimiter
{
1692
1693
1694
1695
1696
1697
1698
1699

1700
1701

1702
1703
1704
1705
1706
1707
1708
1691
1692
1693
1694
1695
1696
1697

1698
1699

1700
1701
1702
1703
1704
1705
1706
1707







-
+

-
+







	void *pool;
	size_t length;

	if (data == nil)
		@throw [OFInvalidArgumentException exception];

	pool = objc_autoreleasePoolPush();
	length = [data count] * [data itemSize];
	length = data.count * data.itemSize;

	[self writeBuffer: [data items]
	[self writeBuffer: data.items
		   length: length];

	objc_autoreleasePoolPop(pool);

	return length;
}

1778
1779
1780
1781
1782
1783
1784
1785

1786
1787
1788
1789
1790
1791
1792
1777
1778
1779
1780
1781
1782
1783

1784
1785
1786
1787
1788
1789
1790
1791







-
+







{
	char *UTF8String;
	int length;

	if (format == nil)
		@throw [OFInvalidArgumentException exception];

	if ((length = of_vasprintf(&UTF8String, [format UTF8String],
	if ((length = of_vasprintf(&UTF8String, format.UTF8String,
	    arguments)) == -1)
		@throw [OFInvalidFormatException exception];

	@try {
		[self writeBuffer: UTF8String
			   length: length];
	} @finally {
1810
1811
1812
1813
1814
1815
1816
1817
1818


1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833


1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844


1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859


1860
1861
1862
1863
1864
1865
1866
1809
1810
1811
1812
1813
1814
1815


1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830


1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841


1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856


1857
1858
1859
1860
1861
1862
1863
1864
1865







-
-
+
+













-
-
+
+









-
-
+
+













-
-
+
+







{
#if defined(HAVE_FCNTL)
	bool readImplemented = false, writeImplemented = false;

	@try {
		int readFlags;

		readFlags =
		    fcntl([(id)self fileDescriptorForReading], F_GETFL, 0);
		readFlags = fcntl(((id <OFReadyForReadingObserving>)self)
		    .fileDescriptorForReading, F_GETFL, 0);

		readImplemented = true;

		if (readFlags == -1)
			@throw [OFSetOptionFailedException
			    exceptionWithObject: self
					  errNo: errno];

		if (enable)
			readFlags &= ~O_NONBLOCK;
		else
			readFlags |= O_NONBLOCK;

		if (fcntl([(id)self fileDescriptorForReading], F_SETFL,
		    readFlags) == -1)
		if (fcntl(((id <OFReadyForReadingObserving>)self)
		    .fileDescriptorForReading, F_SETFL, readFlags) == -1)
			@throw [OFSetOptionFailedException
			    exceptionWithObject: self
					  errNo: errno];
	} @catch (OFNotImplementedException *e) {
	}

	@try {
		int writeFlags;

		writeFlags =
		    fcntl([(id)self fileDescriptorForWriting], F_GETFL, 0);
		writeFlags = fcntl(((id <OFReadyForWritingObserving>)self)
		    .fileDescriptorForWriting, F_GETFL, 0);

		writeImplemented = true;

		if (writeFlags == -1)
			@throw [OFSetOptionFailedException
			    exceptionWithObject: self
					  errNo: errno];

		if (enable)
			writeFlags &= ~O_NONBLOCK;
		else
			writeFlags |= O_NONBLOCK;

		if (fcntl([(id)self fileDescriptorForWriting], F_SETFL,
		    writeFlags) == -1)
		if (fcntl(((id <OFReadyForWritingObserving>)self)
		    .fileDescriptorForWriting, F_SETFL, writeFlags) == -1)
			@throw [OFSetOptionFailedException
			    exceptionWithObject: self
					  errNo: errno];
	} @catch (OFNotImplementedException *e) {
	}

	if (!readImplemented && !writeImplemented)

Modified src/OFString+CryptoHashing.m from [cd0a1a49d0] to [d7c7a2d4d1].

34
35
36
37
38
39
40
41
42
43



44
45
46
47
48
49
50
34
35
36
37
38
39
40



41
42
43
44
45
46
47
48
49
50







-
-
-
+
+
+







{
	void *pool = objc_autoreleasePoolPush();
	id <OFCryptoHash> hash = [class cryptoHash];
	size_t digestSize = [class digestSize];
	const unsigned char *digest;
	char cString[digestSize * 2];

	[hash updateWithBuffer: [self UTF8String]
			length: [self UTF8StringLength]];
	digest = [hash digest];
	[hash updateWithBuffer: self.UTF8String
			length: self.UTF8StringLength];
	digest = hash.digest;

	for (size_t i = 0; i < digestSize; i++) {
		uint8_t high, low;

		high = digest[i] >> 4;
		low  = digest[i] & 0x0F;

Modified src/OFString+JSONValue.m from [487fb8caf6] to [8c09849227].

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







-
+


-
+






-
+







	string = [[OFString alloc] initWithUTF8String: *pointer
					       length: i];
	*pointer += i;

	@try {
		if (hasDecimal)
			number = [OFNumber numberWithDouble:
			    [string doubleValue]];
			    string.doubleValue];
		else if (isHex)
			number = [OFNumber numberWithIntMax:
			    [string hexadecimalValue]];
			    string.hexadecimalValue];
		else if ([string isEqual: @"Infinity"])
			number = [OFNumber numberWithDouble: INFINITY];
		else if ([string isEqual: @"-Infinity"])
			number = [OFNumber numberWithDouble: -INFINITY];
		else
			number = [OFNumber numberWithIntMax:
			    [string decimalValue]];
			    string.decimalValue];
	} @finally {
		[string release];
	}

	return number;
}

646
647
648
649
650
651
652
653
654


655
656
657
658
659
660
661
646
647
648
649
650
651
652


653
654
655
656
657
658
659
660
661







-
-
+
+







{
	return [self JSONValueWithDepthLimit: 32];
}

- (id)JSONValueWithDepthLimit: (size_t)depthLimit
{
	void *pool = objc_autoreleasePoolPush();
	const char *pointer = [self UTF8String];
	const char *stop = pointer + [self UTF8StringLength];
	const char *pointer = self.UTF8String;
	const char *stop = pointer + self.UTF8StringLength;
	id object;
	size_t line = 1;

#ifdef __clang_analyzer__
	assert(pointer != NULL);
#endif

Modified src/OFString+PathAdditions_AmigaOS.m from [a9beed535a] to [c3941b3928].

28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42







-
+







+ (OFString *)pathWithComponents: (OFArray *)components
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	bool firstAfterDevice = true;

	for (OFString *component in components) {
		if ([component length] == 0)
		if (component.length == 0)
			continue;

		if (!firstAfterDevice)
			[ret appendString: @"/"];

		[ret appendString: component];

56
57
58
59
60
61
62
63
64


65
66
67
68
69
70
71
56
57
58
59
60
61
62


63
64
65
66
67
68
69
70
71







-
-
+
+







	return [self containsString: @":"];
}

- (OFArray *)pathComponents
{
	OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	const char *cString = [self UTF8String];
	size_t i, last = 0, cStringLength = [self UTF8StringLength];
	const char *cString = self.UTF8String;
	size_t i, last = 0, cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return ret;
	}

	for (i = 0; i < cStringLength; i++) {
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
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
213

214
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
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
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

213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228
229

230
231
232
233
234
235
236
237







-
+












-
+








-
+













-
-
+
+



-
-
+
+









-
+














-
+



-
-
+
+









-
+

















-
+


-
+

-
+







-
+








-
+







{
	/*
	 * AmigaOS needs the full parsing to determine the last path component.
	 * This could be optimized by not creating the temporary objects,
	 * though.
	 */
	void *pool = objc_autoreleasePoolPush();
	OFString *ret = [[self pathComponents] lastObject];
	OFString *ret = self.pathComponents.lastObject;

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)pathExtension
{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = [self lastPathComponent];
	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringWithRange:
	    of_range(pos + 1, [fileName length] - pos - 1)];
	    of_range(pos + 1, fileName.length - pos - 1)];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByDeletingLastPathComponent
{
	/*
	 * AmigaOS needs the full parsing to delete the last path component.
	 * This could be optimized, though.
	 */
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components = [self pathComponents];
	size_t count = [components count];
	OFArray OF_GENERIC(OFString *) *components = self.pathComponents;
	size_t count = components.count;
	OFString *ret;

	if (count < 2) {
		if ([[components firstObject] hasSuffix: @":"]) {
			ret = [[components firstObject] retain];
		if ([components.firstObject hasSuffix: @":"]) {
			ret = [components.firstObject retain];
			objc_autoreleasePoolPop(pool);
			return [ret autorelease];
		}

		objc_autoreleasePoolPop(pool);
		return @"";
	}

	components = [components objectsInRange:
	    of_range(0, [components count] - 1)];
	    of_range(0, components.count - 1)];
	ret = [OFString pathWithComponents: components];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByDeletingPathExtension
{
	void *pool;
	OFMutableArray OF_GENERIC(OFString *) *components;
	OFString *ret, *fileName;
	size_t pos;

	if ([self length] == 0)
	if (self.length == 0)
		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[[self pathComponents] mutableCopy] autorelease];
	fileName = [components lastObject];
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringWithRange: of_range(0, pos)];
	[components replaceObjectAtIndex: [components count] - 1
	[components replaceObjectAtIndex: components.count - 1
			      withObject: fileName];

	ret = [OFString pathWithComponents: components];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByStandardizingPath
{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components;
	OFMutableArray OF_GENERIC(OFString *) *array;
	OFString *ret;
	bool done = false;

	if ([self length] == 0)
	if (self.length == 0)
		return @"";

	components = [self pathComponents];
	components = self.pathComponents;

	if ([components count] == 1) {
	if (components.count == 1) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	array = [[components mutableCopy] autorelease];

	while (!done) {
		size_t length = [array count];
		size_t length = array.count;

		done = true;

		for (size_t i = 0; i < length; i++) {
			OFString *component = [array objectAtIndex: i];
			OFString *parent =
			    (i > 0 ? [array objectAtIndex: i - 1] : 0);

			if ([component length] == 0) {
			if (component.length == 0) {
				[array removeObjectAtIndex: i];

				done = false;
				break;
			}

			if ([component isEqual: @"/"] &&

Modified src/OFString+PathAdditions_DOS.m from [3467d9c05a] to [b920b866ec].

28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42







-
+







+ (OFString *)pathWithComponents: (OFArray *)components
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	bool first = true;

	for (OFString *component in components) {
		if ([component length] == 0)
		if (component.length == 0)
			continue;

		if ([component isEqual: @"\\"] || [component isEqual: @"/"])
			continue;

		if (!first && ![ret hasSuffix: @"\\"] && ![ret hasSuffix: @"/"])
			[ret appendString: @"\\"];
61
62
63
64
65
66
67
68
69


70
71
72
73
74
75
76
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75
76







-
-
+
+







	return ([self containsString: @":\\"] || [self containsString: @":/"]);
}

- (OFArray *)pathComponents
{
	OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	const char *cString = [self UTF8String];
	size_t i, last = 0, cStringLength = [self UTF8StringLength];
	const char *cString = self.UTF8String;
	size_t i, last = 0, cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return ret;
	}

	for (i = 0; i < cStringLength; i++) {
101
102
103
104
105
106
107
108
109


110
111
112
113
114
115
116
101
102
103
104
105
106
107


108
109
110
111
112
113
114
115
116







-
-
+
+







	size_t cStringLength;
	ssize_t i;
	OFString *ret;

	if ([self hasSuffix: @":\\"] || [self hasSuffix: @":/"])
		return self;

	cString = [self UTF8String];
	cStringLength = [self UTF8StringLength];
	cString = self.UTF8String;
	cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	if (cString[cStringLength - 1] == '\\' ||
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
183


184
185
186
187
188
189
190
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
183
184
185
186
187
188
189
190







-
+








-
+
















-
-
+
+








- (OFString *)pathExtension
{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = [self lastPathComponent];
	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringWithRange:
	    of_range(pos + 1, [fileName length] - pos - 1)];
	    of_range(pos + 1, fileName.length - pos - 1)];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByDeletingLastPathComponent
{
	void *pool = objc_autoreleasePoolPush();
	const char *cString;
	size_t cStringLength;
	OFString *ret;

	if ([self hasSuffix: @":\\"] || [self hasSuffix: @":/"])
		return self;

	cString = [self UTF8String];
	cStringLength = [self UTF8StringLength];
	cString = self.UTF8String;
	cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	if (cString[cStringLength - 1] == '\\' ||
215
216
217
218
219
220
221
222

223
224
225
226
227


228
229
230
231
232
233
234
235
236
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

256
257
258

259
260

261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276
277
278

279
280
281
282
283
284
285
215
216
217
218
219
220
221

222
223
224
225


226
227
228
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

255
256
257

258
259

260
261
262
263
264
265
266
267

268
269
270
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285







-
+



-
-
+
+









-
+

















-
+


-
+

-
+







-
+









-
+







- (OFString *)stringByDeletingPathExtension
{
	void *pool;
	OFMutableArray OF_GENERIC(OFString *) *components;
	OFString *ret, *fileName;
	size_t pos;

	if ([self length] == 0)
	if (self.length == 0)
		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[[self pathComponents] mutableCopy] autorelease];
	fileName = [components lastObject];
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringWithRange: of_range(0, pos)];
	[components replaceObjectAtIndex: [components count] - 1
	[components replaceObjectAtIndex: components.count - 1
			      withObject: fileName];

	ret = [OFString pathWithComponents: components];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByStandardizingPath
{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components;
	OFMutableArray OF_GENERIC(OFString *) *array;
	OFString *ret;
	bool done = false;

	if ([self length] == 0)
	if (self.length == 0)
		return @"";

	components = [self pathComponents];
	components = self.pathComponents;

	if ([components count] == 1) {
	if (components.count == 1) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	array = [[components mutableCopy] autorelease];

	while (!done) {
		size_t length = [array count];
		size_t length = array.count;

		done = true;

		for (size_t i = 0; i < length; i++) {
			OFString *component = [array objectAtIndex: i];
			OFString *parent =
			    (i > 0 ? [array objectAtIndex: i - 1] : 0);

			if ([component isEqual: @"."] ||
			   [component length] == 0) {
			   component.length == 0) {
				[array removeObjectAtIndex: i];

				done = false;
				break;
			}

			if ([component isEqual: @".."] &&

Modified src/OFString+PathAdditions_UNIX.m from [e75f2cd214] to [f40ca2e186].

28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42







-
+







+ (OFString *)pathWithComponents: (OFArray *)components
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	bool first = true;

	for (OFString *component in components) {
		if ([component length] == 0)
		if (component.length == 0)
			continue;

		if (!first && [component isEqual: @"/"])
			continue;

		if (!first && ![ret hasSuffix: @"/"])
			[ret appendString: @"/"];
58
59
60
61
62
63
64
65
66


67
68
69
70
71
72
73
58
59
60
61
62
63
64


65
66
67
68
69
70
71
72
73







-
-
+
+







	return [self hasPrefix: @"/"];
}

- (OFArray *)pathComponents
{
	OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	const char *cString = [self UTF8String];
	size_t i, last = 0, cStringLength = [self UTF8StringLength];
	const char *cString = self.UTF8String;
	size_t i, last = 0, cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return ret;
	}

	for (i = 0; i < cStringLength; i++) {
92
93
94
95
96
97
98
99
100


101
102
103
104
105
106
107
92
93
94
95
96
97
98


99
100
101
102
103
104
105
106
107







-
-
+
+








	return ret;
}

- (OFString *)lastPathComponent
{
	void *pool = objc_autoreleasePoolPush();
	const char *cString = [self UTF8String];
	size_t cStringLength = [self UTF8StringLength];
	const char *cString = self.UTF8String;
	size_t cStringLength = self.UTF8StringLength;
	ssize_t i;
	OFString *ret;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}
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
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







-
+








-
+









-
-
+
+








- (OFString *)pathExtension
{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = [self lastPathComponent];
	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringWithRange:
	    of_range(pos + 1, [fileName length] - pos - 1)];
	    of_range(pos + 1, fileName.length - pos - 1)];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByDeletingLastPathComponent
{
	void *pool = objc_autoreleasePoolPush();
	const char *cString = [self UTF8String];
	size_t cStringLength = [self UTF8StringLength];
	const char *cString = self.UTF8String;
	size_t cStringLength = self.UTF8StringLength;
	OFString *ret;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

205
206
207
208
209
210
211
212

213
214
215
216
217


218
219
220
221
222
223
224
205
206
207
208
209
210
211

212
213
214
215


216
217
218
219
220
221
222
223
224







-
+



-
-
+
+







- (OFString *)stringByDeletingPathExtension
{
	void *pool;
	OFMutableArray OF_GENERIC(OFString *) *components;
	OFString *ret, *fileName;
	size_t pos;

	if ([self length] == 0)
	if (self.length == 0)
		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[[self pathComponents] mutableCopy] autorelease];
	fileName = [components lastObject];
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}
238
239
240
241
242
243
244
245

246
247
248

249
250

251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
238
239
240
241
242
243
244

245
246
247

248
249

250
251
252
253
254
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
271

272
273
274
275
276
277
278
279







-
+


-
+

-
+











-
+









-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components;
	OFMutableArray OF_GENERIC(OFString *) *array;
	OFString *ret;
	bool done = false, startsWithSlash;

	if ([self length] == 0)
	if (self.length == 0)
		return @"";

	components = [self pathComponents];
	components = self.pathComponents;

	if ([components count] == 1) {
	if (components.count == 1) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	array = [[components mutableCopy] autorelease];
	startsWithSlash = [self hasPrefix: @"/"];

	if (startsWithSlash)
		[array removeObjectAtIndex: 0];

	while (!done) {
		size_t length = [array count];
		size_t length = array.count;

		done = true;

		for (size_t i = 0; i < length; i++) {
			OFString *component = [array objectAtIndex: i];
			OFString *parent =
			    (i > 0 ? [array objectAtIndex: i - 1] : 0);

			if ([component isEqual: @"."] ||
			   [component length] == 0) {
			   component.length == 0) {
				[array removeObjectAtIndex: i];

				done = false;
				break;
			}

			if ([component isEqual: @".."] &&

Modified src/OFString+PathAdditions_libfat.m from [7ddc0d03b5] to [d93f3d266a].

28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42







-
+







+ (OFString *)pathWithComponents: (OFArray *)components
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	bool first = true;

	for (OFString *component in components) {
		if ([component length] == 0)
		if (component.length == 0)
			continue;

		if ([component isEqual: @"/"])
			continue;

		if (!first && ![ret hasSuffix: @"/"])
			[ret appendString: @"/"];
61
62
63
64
65
66
67
68
69


70
71
72
73
74
75
76
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75
76







-
-
+
+







	return [self containsString: @":/"];
}

- (OFArray *)pathComponents
{
	OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	const char *cString = [self UTF8String];
	size_t i, last = 0, cStringLength = [self UTF8StringLength];
	const char *cString = self.UTF8String;
	size_t i, last = 0, cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return ret;
	}

	for (i = 0; i < cStringLength; i++) {
101
102
103
104
105
106
107
108
109


110
111
112
113
114
115
116
101
102
103
104
105
106
107


108
109
110
111
112
113
114
115
116







-
-
+
+







	size_t cStringLength;
	ssize_t i;
	OFString *ret;

	if ([self hasSuffix: @":/"])
		return self;

	cString = [self UTF8String];
	cStringLength = [self UTF8StringLength];
	cString = self.UTF8String;
	cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	if (cString[cStringLength - 1] == '/')
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


183
184
185
186
187
188
189
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
183
184
185
186
187
188
189







-
+








-
+
















-
-
+
+








- (OFString *)pathExtension
{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = [self lastPathComponent];
	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringWithRange:
	    of_range(pos + 1, [fileName length] - pos - 1)];
	    of_range(pos + 1, fileName.length - pos - 1)];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByDeletingLastPathComponent
{
	void *pool = objc_autoreleasePoolPush();
	const char *cString;
	size_t cStringLength;
	OFString *ret;

	if ([self hasSuffix: @":/"])
		return self;

	cString = [self UTF8String];
	cStringLength = [self UTF8StringLength];
	cString = self.UTF8String;
	cStringLength = self.UTF8StringLength;

	if (cStringLength == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	if (cString[cStringLength - 1] == '/')
213
214
215
216
217
218
219
220

221
222
223
224
225


226
227
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

254
255
256

257
258

259
260
261
262
263
264
265
266

267
268
269
270
271
272
273
274
275
276

277
278
279
280
281
282
283
213
214
215
216
217
218
219

220
221
222
223


224
225
226
227
228
229
230
231
232
233
234

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

253
254
255

256
257

258
259
260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275

276
277
278
279
280
281
282
283







-
+



-
-
+
+









-
+

















-
+


-
+

-
+







-
+









-
+







- (OFString *)stringByDeletingPathExtension
{
	void *pool;
	OFMutableArray OF_GENERIC(OFString *) *components;
	OFString *ret, *fileName;
	size_t pos;

	if ([self length] == 0)
	if (self.length == 0)
		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[[self pathComponents] mutableCopy] autorelease];
	fileName = [components lastObject];
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringWithRange: of_range(0, pos)];
	[components replaceObjectAtIndex: [components count] - 1
	[components replaceObjectAtIndex: components.count - 1
			      withObject: fileName];

	ret = [OFString pathWithComponents: components];

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)stringByStandardizingPath
{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *components;
	OFMutableArray OF_GENERIC(OFString *) *array;
	OFString *ret;
	bool done = false;

	if ([self length] == 0)
	if (self.length == 0)
		return @"";

	components = [self pathComponents];
	components = self.pathComponents;

	if ([components count] == 1) {
	if (components.count == 1) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	array = [[components mutableCopy] autorelease];

	while (!done) {
		size_t length = [array count];
		size_t length = array.count;

		done = true;

		for (size_t i = 0; i < length; i++) {
			OFString *component = [array objectAtIndex: i];
			OFString *parent =
			    (i > 0 ? [array objectAtIndex: i - 1] : 0);

			if ([component isEqual: @"."] ||
			   [component length] == 0) {
			   component.length == 0) {
				[array removeObjectAtIndex: i];

				done = false;
				break;
			}

			if ([component isEqual: @".."] &&

Modified src/OFString+PropertyListValue.m from [97be60a350] to [06291ad3fb].

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







-
+














-
+



-
+





-
-
+
+



-
+












-
+





-
+





-
+






-
+








-
+








-
+





-
+
-







-
+
-


-
+








static OFArray *
parseArrayElement(OFXMLElement *element)
{
	OFMutableArray *ret = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();

	for (OFXMLElement *child in [element elements])
	for (OFXMLElement *child in element.elements)
		[ret addObject: parseElement(child)];

	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}

static OFDictionary *
parseDictElement(OFXMLElement *element)
{
	OFMutableDictionary *ret = [OFMutableDictionary dictionary];
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFXMLElement *) *children = [element elements];
	OFArray OF_GENERIC(OFXMLElement *) *children = element.elements;
	OFEnumerator OF_GENERIC(OFXMLElement *) *enumerator;
	OFXMLElement *key, *object;

	if ([children count] % 2 != 0)
	if (children.count % 2 != 0)
		@throw [OFInvalidFormatException exception];

	enumerator = [children objectEnumerator];
	while ((key = [enumerator nextObject]) &&
	    (object = [enumerator nextObject])) {
		if ([key namespace] != nil || [[key attributes] count] != 0 ||
		    ![[key name] isEqual: @"key"])
		if (key.namespace != nil || key.attributes.count != 0 ||
		    ![key.name isEqual: @"key"])
			@throw [OFInvalidFormatException exception];

		[ret setObject: parseElement(object)
			forKey: [key stringValue]];
			forKey: key.stringValue];
	}

	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}

static OFString *
parseStringElement(OFXMLElement *element)
{
	return [element stringValue];
	return element.stringValue;
}

static OFData *
parseDataElement(OFXMLElement *element)
{
	return [OFData dataWithBase64EncodedString: [element stringValue]];
	return [OFData dataWithBase64EncodedString: element.stringValue];
}

static OFDate *
parseDateElement(OFXMLElement *element)
{
	return [OFDate dateWithDateString: [element stringValue]
	return [OFDate dateWithDateString: element.stringValue
				   format: @"%Y-%m-%dT%H:%M:%SZ"];
}

static OFNumber *
parseTrueElement(OFXMLElement *element)
{
	if ([[element children] count] != 0)
	if (element.children.count != 0)
		@throw [OFInvalidFormatException exception];

	return [OFNumber numberWithBool: true];
}

static OFNumber *
parseFalseElement(OFXMLElement *element)
{
	if ([[element children] count] != 0)
	if (element.children.count != 0)
		@throw [OFInvalidFormatException exception];

	return [OFNumber numberWithBool: false];
}

static OFNumber *
parseRealElement(OFXMLElement *element)
{
	return [OFNumber numberWithDouble: [[element stringValue] doubleValue]];
	return [OFNumber numberWithDouble: element.stringValue.doubleValue];
}

static OFNumber *
parseIntegerElement(OFXMLElement *element)
{
	return [OFNumber numberWithIntMax:
	return [OFNumber numberWithIntMax: element.stringValue.decimalValue];
	    [[element stringValue] decimalValue]];
}

static id
parseElement(OFXMLElement *element)
{
	OFString *elementName;

	if ([element namespace] != nil ||
	if (element.namespace != nil || element.attributes.count != 0)
	    [[element attributes] count] != 0)
		@throw [OFInvalidFormatException exception];

	elementName = [element name];
	elementName = element.name;

	if ([elementName isEqual: @"array"])
		return parseArrayElement(element);
	else if ([elementName isEqual: @"dict"])
		return parseDictElement(element);
	else if ([elementName isEqual: @"string"])
		return parseStringElement(element);
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
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







-
-
+
+







-
+



-
+

-
+


-
+






{
	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *rootElement = [OFXMLElement elementWithXMLString: self];
	OFXMLAttribute *versionAttribute;
	OFArray OF_GENERIC(OFXMLElement *) *elements;
	id ret;

	if (![[rootElement name] isEqual: @"plist"] ||
	    [rootElement namespace] != nil)
	if (![rootElement.name isEqual: @"plist"] ||
	    rootElement.namespace != nil)
		@throw [OFInvalidFormatException exception];

	versionAttribute = [rootElement attributeForName: @"version"];

	if (versionAttribute == nil)
		@throw [OFInvalidFormatException exception];

	if (![[versionAttribute stringValue] isEqual: @"1.0"])
	if (![versionAttribute.stringValue isEqual: @"1.0"])
		@throw [OFUnsupportedVersionException
		    exceptionWithVersion: [versionAttribute stringValue]];

	elements = [rootElement elements];
	elements = rootElement.elements;

	if ([elements count] != 1)
	if (elements.count != 1)
		@throw [OFInvalidFormatException exception];

	ret = parseElement([elements firstObject]);
	ret = parseElement(elements.firstObject);

	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}
@end

Modified src/OFString+Serialization.m from [bfb40bb476] to [323b28b85f].

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







-
+



-
+





-
+


-
+






		root = [OFXMLElement elementWithXMLString: self];
	} @catch (OFMalformedXMLException *e) {
		@throw [OFInvalidArgumentException exception];
	} @catch (OFUnboundNamespaceException *e) {
		@throw [OFInvalidArgumentException exception];
	}

	version = [[root attributeForName: @"version"] stringValue];
	version = [root attributeForName: @"version"].stringValue;
	if (version == nil)
		@throw [OFInvalidArgumentException exception];

	if ([version decimalValue] != 1)
	if (version.decimalValue != 1)
		@throw [OFUnsupportedVersionException
		    exceptionWithVersion: version];

	elements = [root elementsForNamespace: OF_SERIALIZATION_NS];

	if ([elements count] != 1)
	if (elements.count != 1)
		@throw [OFInvalidArgumentException exception];

	object = [[[elements firstObject] objectByDeserializing] retain];
	object = [[elements.firstObject objectByDeserializing] retain];

	objc_autoreleasePoolPop(pool);

	return [object autorelease];
}
@end

Modified src/OFString+URLEncoding.m from [eb3c914e3d] to [b31ee5c6f5].

32
33
34
35
36
37
38
39
40


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


39
40
41
42
43
44
45
46
47







-
-
+
+








@implementation OFString (URLEncoding)
- (OFString *)stringByURLEncodingWithAllowedCharacters:
    (OFCharacterSet *)allowedCharacters
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;
	bool (*characterIsMember)(id, SEL, of_unichar_t) =
	    (bool (*)(id, SEL, of_unichar_t))[allowedCharacters
	    methodForSelector: @selector(characterIsMember:)];

	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = characters[i];

78
79
80
81
82
83
84
85
86


87
88
89
90
91
92
93
78
79
80
81
82
83
84


85
86
87
88
89
90
91
92
93







-
-
+
+








	return ret;
}

- (OFString *)stringByURLDecoding
{
	void *pool = objc_autoreleasePoolPush();
	const char *string = [self UTF8String];
	size_t length = [self UTF8StringLength];
	const char *string = self.UTF8String;
	size_t length = self.UTF8StringLength;
	char *retCString, *retCString2;
	char byte = 0;
	int state = 0;
	size_t i = 0;

	if ((retCString = malloc(length + 1)) == NULL)
		@throw [OFOutOfMemoryException

Modified src/OFString+XMLEscaping.m from [57e70e6dc2] to [93579edbe8].

33
34
35
36
37
38
39
40
41


42
43
44
45
46
47
48
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48







-
-
+
+







	void *pool = objc_autoreleasePoolPush();
	char *retCString;
	const char *string, *append;
	size_t length, retLength, appendLen;
	size_t j;
	OFString *ret;

	string = [self UTF8String];
	length = [self UTF8StringLength];
	string = self.UTF8String;
	length = self.UTF8StringLength;

	j = 0;
	retLength = length;

	/*
	 * We can't use allocMemoryWithSize: here as it might be a @"" literal
	 */

Modified src/OFString+XMLUnescaping.m from [ca15662616] to [8d9a1c8db6].

84
85
86
87
88
89
90
91
92


93
94
95
96
97
98
99
84
85
86
87
88
89
90


91
92
93
94
95
96
97
98
99







-
-
+
+







	size_t i, last, length;
	bool inEntity;

	ret = [OFMutableString string];

	pool = objc_autoreleasePoolPush();

	string = [self UTF8String];
	length = [self UTF8StringLength];
	string = self.UTF8String;
	length = self.UTF8StringLength;

	last = 0;
	inEntity = false;

	for (i = 0; i < length; i++) {
		if (!inEntity && string[i] == '&') {
			[ret appendUTF8String: string + last

Modified src/OFString.m from [b076cd8540] to [fd85923ed1].

144
145
146
147
148
149
150
151

152
153
154
155
156
157
158
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158







-
+








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

	string = [string lowercaseString];
	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"])
336
337
338
339
340
341
342
343
344


345
346
347
348
349
350
351
336
337
338
339
340
341
342


343
344
345
346
347
348
349
350
351







-
-
+
+








#ifdef OF_HAVE_UNICODE_TABLES
static OFString *
decomposedString(OFString *self, const char *const *const *table, size_t size)
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;

	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = characters[i];
		const char *const *page;

		if (c >= size) {
			[ret appendCharacters: &c
871
872
873
874
875
876
877
878

879
880
881
882
883
884
885

886
887

888
889
890
891
892
893
894
871
872
873
874
875
876
877

878
879
880
881
882
883
884

885
886

887
888
889
890
891
892
893
894







-
+






-
+

-
+







	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithData: (OFData *)data
		    encoding: (of_string_encoding_t)encoding
{
	@try {
		if ([data itemSize] != 1)
		if (data.itemSize != 1)
			@throw [OFInvalidArgumentException exception];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithCString: [data items]
	self = [self initWithCString: data.items
			    encoding: encoding
			      length: [data count]];
			      length: data.count];

	return self;
}

- (instancetype)initWithString: (OFString *)string
{
	OF_INVALID_INIT_METHOD
993
994
995
996
997
998
999
1000
1001


1002
1003
1004
1005
1006

1007
1008
1009
1010
1011
1012
1013
993
994
995
996
997
998
999


1000
1001
1002
1003
1004
1005

1006
1007
1008
1009
1010
1011
1012
1013







-
-
+
+




-
+







	uintmax_t fileSize;

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFFile *file = nil;

		@try {
			fileSize = [[[OFFileManager defaultManager]
			    attributesOfItemAtPath: path] fileSize];
			fileSize = [[OFFileManager defaultManager]
			    attributesOfItemAtPath: path].fileSize;
		} @catch (OFRetrieveItemAttributesFailedException *e) {
			@throw [OFOpenItemFailedException
			    exceptionWithPath: path
					 mode: @"r"
					errNo: errno];
					errNo: e.errNo];
		}

		objc_autoreleasePoolPop(pool);

# if UINTMAX_MAX > SIZE_MAX
		if (fileSize > SIZE_MAX)
			@throw [OFOutOfRangeException exception];
1076
1077
1078
1079
1080
1081
1082
1083

1084
1085

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
1076
1077
1078
1079
1080
1081
1082

1083
1084

1085
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







-
+

-
+












-
+



-
+


-
+



-
+

















-
-
+
+







	@try {
		data = [OFData dataWithContentsOfURL: URL];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithCString: [data items]
	self = [self initWithCString: data.items
			    encoding: encoding
			      length: [data count]];
			      length: data.count * data.itemSize];

	objc_autoreleasePoolPop(pool);

	return self;
}

- (instancetype)initWithSerialization: (OFXMLElement *)element
{
	void *pool = objc_autoreleasePoolPush();
	OFString *stringValue;

	@try {
		if (![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		if ([self isKindOfClass: [OFMutableString class]]) {
			if (![[element name] isEqual: @"OFMutableString"])
			if (![element.name isEqual: @"OFMutableString"])
				@throw [OFInvalidArgumentException exception];
		} else {
			if (![[element name] isEqual: @"OFString"])
			if (![element.name isEqual: @"OFString"])
				@throw [OFInvalidArgumentException exception];
		}

		stringValue = [element stringValue];
		stringValue = element.stringValue;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithString: stringValue];

	objc_autoreleasePoolPop(pool);

	return self;
}

- (size_t)of_getCString: (char *)cString
	      maxLength: (size_t)maxLength
	       encoding: (of_string_encoding_t)encoding
		  lossy: (bool)lossy
{
	const of_unichar_t *characters = [self characters];
	size_t i, length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t i, length = self.length;

	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:;
		size_t j = 0;

		for (i = 0; i < length; i++) {
			char buffer[4];
1370
1371
1372
1373
1374
1375
1376
1377

1378
1379
1380
1381
1382
1383
1384
1370
1371
1372
1373
1374
1375
1376

1377
1378
1379
1380
1381
1382
1383
1384







-
+







			     lossy: true];
}

- (const char *)of_cStringWithEncoding: (of_string_encoding_t)encoding
				 lossy: (bool)lossy
{
	OFObject *object = [[[OFObject alloc] init] autorelease];
	size_t length = [self length];
	size_t length = self.length;
	char *cString;

	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:;
		size_t cStringLength;

		cString = [object allocMemoryWithSize: (length * 4) + 1];
1449
1450
1451
1452
1453
1454
1455
1456
1457


1458
1459
1460
1461
1462
1463
1464
1449
1450
1451
1452
1453
1454
1455


1456
1457
1458
1459
1460
1461
1462
1463
1464







-
-
+
+







- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding
{
	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:;
		const of_unichar_t *characters;
		size_t length, UTF8StringLength = 0;

		characters = [self characters];
		length = [self length];
		characters = self.characters;
		length = self.length;

		for (size_t i = 0; i < length; i++) {
			char buffer[4];
			size_t len = of_string_utf8_encode(characters[i],
			    buffer);

			if (len == 0)
1477
1478
1479
1480
1481
1482
1483
1484

1485
1486
1487
1488
1489
1490
1491
1477
1478
1479
1480
1481
1482
1483

1484
1485
1486
1487
1488
1489
1490
1491







-
+







	case OF_STRING_ENCODING_WINDOWS_1252:
	case OF_STRING_ENCODING_CODEPAGE_437:
	case OF_STRING_ENCODING_CODEPAGE_850:
	case OF_STRING_ENCODING_CODEPAGE_858:
	case OF_STRING_ENCODING_MAC_ROMAN:
	case OF_STRING_ENCODING_KOI8_R:
	case OF_STRING_ENCODING_KOI8_U:
		return [self length];
		return self.length;
	default:
		@throw [OFInvalidEncodingException exception];
	}
}

- (size_t)UTF8StringLength
{
1514
1515
1516
1517
1518
1519
1520
1521

1522
1523

1524
1525
1526
1527
1528
1529


1530
1531
1532
1533
1534
1535
1536
1514
1515
1516
1517
1518
1519
1520

1521
1522

1523
1524
1525
1526
1527


1528
1529
1530
1531
1532
1533
1534
1535
1536







-
+

-
+




-
-
+
+







	if (object == self)
		return true;

	if (![object isKindOfClass: [OFString class]])
		return false;

	otherString = object;
	length = [self length];
	length = self.length;

	if ([otherString length] != length)
	if (otherString.length != length)
		return false;

	pool = objc_autoreleasePoolPush();

	characters = [self characters];
	otherCharacters = [otherString characters];
	characters = self.characters;
	otherCharacters = otherString.characters;

	if (memcmp(characters, otherCharacters,
	    length * sizeof(of_unichar_t)) != 0) {
		objc_autoreleasePoolPop(pool);
		return false;
	}

1559
1560
1561
1562
1563
1564
1565
1566
1567


1568
1569
1570
1571
1572


1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588

1589
1590

1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608




1609
1610
1611
1612
1613
1614
1615
1559
1560
1561
1562
1563
1564
1565


1566
1567
1568
1569
1570


1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587

1588
1589

1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604




1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615







-
-
+
+



-
-
+
+















-
+

-
+














-
-
-
-
+
+
+
+







	if (object == self)
		return OF_ORDERED_SAME;

	if (![(id)object isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];

	otherString = (OFString *)object;
	minimumLength = ([self length] > [otherString length]
	    ? [otherString length] : [self length]);
	minimumLength = (self.length > otherString.length
	    ? otherString.length : self.length);

	pool = objc_autoreleasePoolPush();

	characters = [self characters];
	otherCharacters = [otherString characters];
	characters = self.characters;
	otherCharacters = otherString.characters;

	for (size_t i = 0; i < minimumLength; i++) {
		if (characters[i] > otherCharacters[i]) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_DESCENDING;
		}

		if (characters[i] < otherCharacters[i]) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_ASCENDING;
		}
	}

	objc_autoreleasePoolPop(pool);

	if ([self length] > [otherString length])
	if (self.length > otherString.length)
		return OF_ORDERED_DESCENDING;
	if ([self length] < [otherString length])
	if (self.length < otherString.length)
		return OF_ORDERED_ASCENDING;

	return OF_ORDERED_SAME;
}

- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)otherString
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters, *otherCharacters;
	size_t length, otherLength, minimumLength;

	if (otherString == self)
		return OF_ORDERED_SAME;

	characters = [self characters];
	otherCharacters = [otherString characters];
	length = [self length];
	otherLength = [otherString length];
	characters = self.characters;
	otherCharacters = otherString.characters;
	length = self.length;
	otherLength = otherString.length;

	minimumLength = (length > otherLength ? otherLength : length);

	for (size_t i = 0; i < minimumLength; i++) {
		of_unichar_t c = characters[i];
		of_unichar_t oc = otherCharacters[i];

1651
1652
1653
1654
1655
1656
1657
1658
1659


1660
1661
1662
1663
1664
1665
1666
1667
1668
1669


1670
1671
1672
1673
1674
1675
1676
1651
1652
1653
1654
1655
1656
1657


1658
1659
1660
1661
1662
1663
1664
1665
1666
1667


1668
1669
1670
1671
1672
1673
1674
1675
1676







-
-
+
+








-
-
+
+







		return OF_ORDERED_ASCENDING;

	return OF_ORDERED_SAME;
}

- (uint32_t)hash
{
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;
	uint32_t hash;

	OF_HASH_INIT(hash);

	for (size_t i = 0; i < length; i++) {
		const of_unichar_t c = characters[i];

		OF_HASH_ADD(hash, (c & 0xFF0000) >> 16);
		OF_HASH_ADD(hash, (c & 0x00FF00) >>  8);
		OF_HASH_ADD(hash,  c & 0x0000FF);
		OF_HASH_ADD(hash, (c & 0x00FF00) >> 8);
		OF_HASH_ADD(hash, c & 0x0000FF);
	}

	OF_HASH_FINALIZE(hash);

	return hash;
}

1733
1734
1735
1736
1737
1738
1739
1740

1741
1742
1743
1744
1745
1746
1747
1733
1734
1735
1736
1737
1738
1739

1740
1741
1742
1743
1744
1745
1746
1747







-
+







			      withString: @"\\t"];

	if (options & OF_JSON_REPRESENTATION_JSON5) {
		[JSON replaceOccurrencesOfString: @"\n"
				      withString: @"\\\n"];

		if (options & OF_JSON_REPRESENTATION_IDENTIFIER) {
			const char *cString = [self UTF8String];
			const char *cString = self.UTF8String;

			if ((!of_ascii_isalpha(cString[0]) &&
			    cString[0] != '_' && cString[0] != '$') ||
			    strpbrk(cString, " \n\r\t\b\f\\\"'") != NULL) {
				[JSON prependString: @"\""];
				[JSON appendString: @"\""];
			}
1763
1764
1765
1766
1767
1768
1769
1770

1771
1772
1773
1774
1775
1776
1777
1763
1764
1765
1766
1767
1768
1769

1770
1771
1772
1773
1774
1775
1776
1777







-
+







}

- (OFData *)messagePackRepresentation
{
	OFMutableData *data;
	size_t length;

	length = [self UTF8StringLength];
	length = self.UTF8StringLength;

	if (length <= 31) {
		uint8_t tmp = 0xA0 | ((uint8_t)length & 0x1F);

		data = [OFMutableData dataWithItemSize: 1
					      capacity: length + 1];

1804
1805
1806
1807
1808
1809
1810
1811

1812
1813
1814
1815
1816
1817
1818
1819
1820
1821

1822
1823
1824
1825
1826
1827
1828
1829

1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841

1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852

1853
1854
1855
1856
1857
1858
1859
1804
1805
1806
1807
1808
1809
1810

1811
1812
1813
1814
1815
1816
1817
1818
1819
1820

1821
1822
1823
1824
1825
1826
1827
1828

1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840

1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851

1852
1853
1854
1855
1856
1857
1858
1859







-
+









-
+







-
+











-
+










-
+








		[data addItem: &type];
		[data addItems: &tmp
			 count: sizeof(tmp)];
	} else
		@throw [OFOutOfRangeException exception];

	[data addItems: [self UTF8String]
	[data addItems: self.UTF8String
		 count: length];

	return data;
}

- (of_range_t)rangeOfString: (OFString *)string
{
	return [self rangeOfString: string
			   options: 0
			     range: of_range(0, [self length])];
			     range: of_range(0, self.length)];
}

- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
{
	return [self rangeOfString: string
			   options: options
			     range: of_range(0, [self length])];
			     range: of_range(0, self.length)];
}

- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
		      range: (of_range_t)range
{
	void *pool;
	const of_unichar_t *searchCharacters;
	of_unichar_t *characters;
	size_t searchLength;

	if ((searchLength = [string length]) == 0)
	if ((searchLength = string.length) == 0)
		return of_range(0, 0);

	if (searchLength > range.length)
		return of_range(OF_NOT_FOUND, 0);

	if (range.length > SIZE_MAX / sizeof(of_unichar_t))
		@throw [OFOutOfRangeException exception];

	pool = objc_autoreleasePoolPush();

	searchCharacters = [string characters];
	searchCharacters = string.characters;

	if ((characters = malloc(range.length * sizeof(of_unichar_t))) == NULL)
		@throw [OFOutOfMemoryException exceptionWithRequestedSize:
		    range.length * sizeof(of_unichar_t)];

	@try {
		[self getCharacters: characters
1892
1893
1894
1895
1896
1897
1898
1899

1900
1901
1902
1903
1904
1905
1906
1907

1908
1909
1910
1911
1912
1913
1914
1892
1893
1894
1895
1896
1897
1898

1899
1900
1901
1902
1903
1904
1905
1906

1907
1908
1909
1910
1911
1912
1913
1914







-
+







-
+







	return of_range(OF_NOT_FOUND, 0);
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
{
	return [self indexOfCharacterFromSet: characterSet
				     options: 0
				       range: of_range(0, [self length])];
				       range: of_range(0, self.length)];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
{
	return [self indexOfCharacterFromSet: characterSet
				     options: options
				       range: of_range(0, [self length])];
				       range: of_range(0, self.length)];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
			    range: (of_range_t)range
{
	bool (*characterIsMember)(id, SEL, of_unichar_t) =
1957
1958
1959
1960
1961
1962
1963
1964

1965
1966
1967

1968
1969
1970
1971
1972
1973


1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994

1995
1996
1997
1998
1999

2000
2001
2002
2003
2004
2005
2006
1957
1958
1959
1960
1961
1962
1963

1964
1965
1966

1967
1968
1969
1970
1971


1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993

1994
1995
1996
1997
1998

1999
2000
2001
2002
2003
2004
2005
2006







-
+


-
+




-
-
+
+




















-
+




-
+








- (bool)containsString: (OFString *)string
{
	void *pool;
	const of_unichar_t *characters, *searchCharacters;
	size_t length, searchLength;

	if ((searchLength = [string length]) == 0)
	if ((searchLength = string.length) == 0)
		return true;

	if (searchLength > (length = [self length]))
	if (searchLength > (length = self.length))
		return false;

	pool = objc_autoreleasePoolPush();

	characters = [self characters];
	searchCharacters = [string characters];
	characters = self.characters;
	searchCharacters = string.characters;

	for (size_t i = 0; i <= length - searchLength; i++) {
		if (memcmp(characters + i, searchCharacters,
		    searchLength * sizeof(of_unichar_t)) == 0) {
			objc_autoreleasePoolPop(pool);
			return true;
		}
	}

	objc_autoreleasePoolPop(pool);

	return false;
}

- (OFString *)substringWithRange: (of_range_t)range
{
	void *pool;
	OFString *ret;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > [self length])
	    range.location + range.length > self.length)
		@throw [OFOutOfRangeException exception];

	pool = objc_autoreleasePoolPush();
	ret = [[OFString alloc]
	    initWithCharacters: [self characters] + range.location
	    initWithCharacters: self.characters + range.location
			length: range.length];
	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}

- (OFString *)stringByAppendingString: (OFString *)string
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159

2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171

2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189

2190
2191
2192

2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203

2204
2205
2206
2207
2208
2209
2210
2148
2149
2150
2151
2152
2153
2154

2155
2156
2157

2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168


2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186

2187
2188
2189

2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200

2201
2202
2203
2204
2205
2206
2207
2208







-



-
+










-
-
+

















-
+


-
+










-
+








	return new;
}

- (bool)hasPrefix: (OFString *)prefix
{
	of_unichar_t *tmp;
	const of_unichar_t *prefixCharacters;
	size_t prefixLength;
	bool hasPrefix;

	if ((prefixLength = [prefix length]) > [self length])
	if ((prefixLength = prefix.length) > self.length)
		return false;

	tmp = [self allocMemoryWithSize: sizeof(of_unichar_t)
				  count: prefixLength];
	@try {
		void *pool = objc_autoreleasePoolPush();

		[self getCharacters: tmp
			    inRange: of_range(0, prefixLength)];

		prefixCharacters = [prefix characters];
		hasPrefix = (memcmp(tmp, prefixCharacters,
		hasPrefix = (memcmp(tmp, prefix.characters,
		    prefixLength * sizeof(of_unichar_t)) == 0);

		objc_autoreleasePoolPop(pool);
	} @finally {
		[self freeMemory: tmp];
	}

	return hasPrefix;
}

- (bool)hasSuffix: (OFString *)suffix
{
	of_unichar_t *tmp;
	const of_unichar_t *suffixCharacters;
	size_t length, suffixLength;
	bool hasSuffix;

	if ((suffixLength = [suffix length]) > [self length])
	if ((suffixLength = suffix.length) > self.length)
		return false;

	length = [self length];
	length = self.length;

	tmp = [self allocMemoryWithSize: sizeof(of_unichar_t)
				  count: suffixLength];
	@try {
		void *pool = objc_autoreleasePoolPush();

		[self getCharacters: tmp
			    inRange: of_range(length - suffixLength,
					 suffixLength)];

		suffixCharacters = [suffix characters];
		suffixCharacters = suffix.characters;
		hasSuffix = (memcmp(tmp, suffixCharacters,
		    suffixLength * sizeof(of_unichar_t)) == 0);

		objc_autoreleasePoolPop(pool);
	} @finally {
		[self freeMemory: tmp];
	}
2221
2222
2223
2224
2225
2226
2227
2228
2229


2230
2231
2232
2233
2234
2235
2236


2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254

2255
2256
2257
2258
2259
2260
2261

2262
2263
2264
2265
2266
2267
2268
2219
2220
2221
2222
2223
2224
2225


2226
2227
2228
2229
2230
2231
2232


2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251

2252
2253
2254
2255
2256
2257
2258

2259
2260
2261
2262
2263
2264
2265
2266







-
-
+
+





-
-
+
+

















-
+






-
+







- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
				 options: (int)options
{
	void *pool;
	OFMutableArray *array = [OFMutableArray array];
	const of_unichar_t *characters, *delimiterCharacters;
	bool skipEmpty = (options & OF_STRING_SKIP_EMPTY);
	size_t length = [self length];
	size_t delimiterLength = [delimiter length];
	size_t length = self.length;
	size_t delimiterLength = delimiter.length;
	size_t last;
	OFString *component;

	pool = objc_autoreleasePoolPush();

	characters = [self characters];
	delimiterCharacters = [delimiter characters];
	characters = self.characters;
	delimiterCharacters = delimiter.characters;

	if (delimiterLength > length) {
		[array addObject: [[self copy] autorelease]];
		[array makeImmutable];

		objc_autoreleasePoolPop(pool);

		return array;
	}

	last = 0;
	for (size_t i = 0; i <= length - delimiterLength; i++) {
		if (memcmp(characters + i, delimiterCharacters,
		    delimiterLength * sizeof(of_unichar_t)) != 0)
			continue;

		component = [self substringWithRange: of_range(last, i - last)];
		if (!skipEmpty || [component length] > 0)
		if (!skipEmpty || component.length > 0)
			[array addObject: component];

		i += delimiterLength - 1;
		last = i + 1;
	}
	component = [self substringWithRange: of_range(last, length - last)];
	if (!skipEmpty || [component length] > 0)
	if (!skipEmpty || component.length > 0)
		[array addObject: component];

	[array makeImmutable];

	objc_autoreleasePoolPop(pool);

	return array;
2278
2279
2280
2281
2282
2283
2284
2285
2286


2287
2288
2289
2290
2291
2292
2293
2276
2277
2278
2279
2280
2281
2282


2283
2284
2285
2286
2287
2288
2289
2290
2291







-
-
+
+







- (OFArray *)
   componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet
				options: (int)options
{
	OFMutableArray *array = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	bool skipEmpty = (options & OF_STRING_SKIP_EMPTY);
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;
	bool (*characterIsMember)(id, SEL, of_unichar_t) =
	    (bool (*)(id, SEL, of_unichar_t))[characterSet
	    methodForSelector: @selector(characterIsMember:)];
	size_t last;

	last = 0;
	for (size_t i = 0; i < length; i++) {
2314
2315
2316
2317
2318
2319
2320
2321
2322


2323
2324
2325
2326
2327
2328
2329
2312
2313
2314
2315
2316
2317
2318


2319
2320
2321
2322
2323
2324
2325
2326
2327







-
-
+
+








	return array;
}

- (intmax_t)decimalValue
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t i = 0, length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t i = 0, length = self.length;
	intmax_t value = 0;
	bool expectWhitespace = false;

	while (length > 0 && of_ascii_isspace(*characters)) {
		characters++;
		length--;
	}
2363
2364
2365
2366
2367
2368
2369
2370
2371


2372
2373
2374
2375
2376
2377
2378
2361
2362
2363
2364
2365
2366
2367


2368
2369
2370
2371
2372
2373
2374
2375
2376







-
-
+
+








	return value;
}

- (uintmax_t)hexadecimalValue
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t i = 0, length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t i = 0, length = self.length;
	uintmax_t value = 0;
	bool expectWhitespace = false, foundValue = false;

	while (length > 0 && of_ascii_isspace(*characters)) {
		characters++;
		length--;
	}
2426
2427
2428
2429
2430
2431
2432
2433
2434


2435
2436
2437
2438
2439
2440
2441
2424
2425
2426
2427
2428
2429
2430


2431
2432
2433
2434
2435
2436
2437
2438
2439







-
-
+
+








	return value;
}

- (uintmax_t)octalValue
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t i = 0, length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t i = 0, length = self.length;
	uintmax_t value = 0;
	bool expectWhitespace = false;

	while (length > 0 && of_ascii_isspace(*characters)) {
		characters++;
		length--;
	}
2475
2476
2477
2478
2479
2480
2481
2482

2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493

2494
2495
2496
2497
2498
2499
2500

2501
2502

2503
2504
2505
2506
2507
2508
2509
2473
2474
2475
2476
2477
2478
2479

2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490

2491
2492
2493
2494
2495
2496
2497

2498
2499

2500
2501
2502
2503
2504
2505
2506
2507







-
+










-
+






-
+

-
+







}

- (float)floatValue
{
	void *pool = objc_autoreleasePoolPush();

#if defined(OF_AMIGAOS_M68K) || defined(OF_MORPHOS)
	OFString *stripped = [self stringByDeletingEnclosingWhitespaces];
	OFString *stripped = self.stringByDeletingEnclosingWhitespaces;

	if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME)
		return INFINITY;
	if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME)
		return -INFINITY;
#endif

#ifdef HAVE_STRTOF_L
	const char *UTF8String = [self UTF8String];
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtof_l, we have no other choice but to replace "."
	 * with the locale's decimal point.
	 */
	OFString *decimalPoint = [OFLocale decimalPoint];
	const char *UTF8String = [[self
	const char *UTF8String = [self
	    stringByReplacingOccurrencesOfString: @"."
				      withString: decimalPoint] UTF8String];
				      withString: decimalPoint].UTF8String;
#endif
	char *endPointer = NULL;
	float value;

	while (of_ascii_isspace(*UTF8String))
		UTF8String++;

2525
2526
2527
2528
2529
2530
2531
2532

2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543

2544
2545
2546
2547
2548
2549
2550

2551
2552

2553
2554
2555
2556
2557
2558
2559
2523
2524
2525
2526
2527
2528
2529

2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540

2541
2542
2543
2544
2545
2546
2547

2548
2549

2550
2551
2552
2553
2554
2555
2556
2557







-
+










-
+






-
+

-
+







}

- (double)doubleValue
{
	void *pool = objc_autoreleasePoolPush();

#if defined(OF_AMIGAOS_M68K) || defined(OF_MORPHOS)
	OFString *stripped = [self stringByDeletingEnclosingWhitespaces];
	OFString *stripped = self.stringByDeletingEnclosingWhitespaces;

	if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME)
		return INFINITY;
	if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME)
		return -INFINITY;
#endif

#ifdef HAVE_STRTOD_L
	const char *UTF8String = [self UTF8String];
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtod_l, we have no other choice but to replace "."
	 * with the locale's decimal point.
	 */
	OFString *decimalPoint = [OFLocale decimalPoint];
	const char *UTF8String = [[self
	const char *UTF8String = [self
	    stringByReplacingOccurrencesOfString: @"."
				      withString: decimalPoint] UTF8String];
				      withString: decimalPoint].UTF8String;
#endif
	char *endPointer = NULL;
	double value;

	while (of_ascii_isspace(*UTF8String))
		UTF8String++;

2573
2574
2575
2576
2577
2578
2579
2580

2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601


2602
2603
2604
2605
2606
2607
2608
2571
2572
2573
2574
2575
2576
2577

2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597


2598
2599
2600
2601
2602
2603
2604
2605
2606







-
+



















-
-
+
+








	return value;
}

- (const of_unichar_t *)characters
{
	OFObject *object = [[[OFObject alloc] init] autorelease];
	size_t length = [self length];
	size_t length = self.length;
	of_unichar_t *ret;

	ret = [object allocMemoryWithSize: sizeof(of_unichar_t)
				    count: length];
	[self getCharacters: ret
		    inRange: of_range(0, length)];

	return ret;
}

- (const of_char16_t *)UTF16String
{
	return [self UTF16StringWithByteOrder: OF_BYTE_ORDER_NATIVE];
}

- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder
{
	OFObject *object = [[[OFObject alloc] init] autorelease];
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t length = self.length;
	of_char16_t *ret;
	size_t j;
	bool swap = (byteOrder != OF_BYTE_ORDER_NATIVE);

	/* Allocate memory for the worst case */
	ret = [object allocMemoryWithSize: sizeof(of_char16_t)
				    count: (length + 1) * 2];
2643
2644
2645
2646
2647
2648
2649
2650

2651
2652
2653

2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670

2671
2672
2673
2674
2675
2676
2677
2641
2642
2643
2644
2645
2646
2647

2648
2649
2650

2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667

2668
2669
2670
2671
2672
2673
2674
2675







-
+


-
+
















-
+







	objc_autoreleasePoolPop(pool);

	return ret;
}

- (size_t)UTF16StringLength
{
	const of_unichar_t *characters = [self characters];
	const of_unichar_t *characters = self.characters;
	size_t length, UTF16StringLength;

	length = UTF16StringLength = [self length];
	length = UTF16StringLength = self.length;

	for (size_t i = 0; i < length; i++)
		if (characters[i] > 0xFFFF)
			UTF16StringLength++;

	return UTF16StringLength;
}

- (const of_char32_t *)UTF32String
{
	return [self UTF32StringWithByteOrder: OF_BYTE_ORDER_NATIVE];
}

- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
{
	OFObject *object = [[[OFObject alloc] init] autorelease];
	size_t length = [self length];
	size_t length = self.length;
	of_char32_t *ret;

	ret = [object allocMemoryWithSize: sizeof(of_char32_t)
				    count: length + 1];
	[self getCharacters: ret
		    inRange: of_range(0, length)];
	ret[length] = 0;
2757
2758
2759
2760
2761
2762
2763
2764
2765


2766
2767
2768
2769
2770
2771
2772
2755
2756
2757
2758
2759
2760
2761


2762
2763
2764
2765
2766
2767
2768
2769
2770







-
-
+
+







	objc_autoreleasePoolPop(pool);
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t i, last = 0, length = [self length];
	const of_unichar_t *characters = self.characters;
	size_t i, last = 0, length = self.length;
	bool stop = false, lastCarriageReturn = false;

	for (i = 0; i < length && !stop; i++) {
		if (lastCarriageReturn && characters[i] == '\n') {
			lastCarriageReturn = false;
			last++;

Modified src/OFString_UTF8.m from [0962ed33d1] to [b5bfc583a1].

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







-
+







-
+


-
+







- (instancetype)initWithString: (OFString *)string
{
	self = [super init];

	@try {
		_s = &_storage;

		_s->cStringLength = [string UTF8StringLength];
		_s->cStringLength = string.UTF8StringLength;

		if ([string isKindOfClass: [OFString_UTF8 class]] ||
		    [string isKindOfClass: [OFMutableString_UTF8 class]])
			_s->isUTF8 = ((OFString_UTF8 *)string)->_s->isUTF8;
		else
			_s->isUTF8 = true;

		_s->length = [string length];
		_s->length = string.length;

		_s->cString = [self allocMemoryWithSize: _s->cStringLength + 1];
		memcpy(_s->cString, [string UTF8String], _s->cStringLength + 1);
		memcpy(_s->cString, string.UTF8String, _s->cStringLength + 1);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
676
677
678
679
680
681
682
683

684
685
686
687
688
689
690
676
677
678
679
680
681
682

683
684
685
686
687
688
689
690







-
+







		int cStringLength;

		if (format == nil)
			@throw [OFInvalidArgumentException exception];

		_s = &_storage;

		if ((cStringLength = of_vasprintf(&tmp, [format UTF8String],
		if ((cStringLength = of_vasprintf(&tmp, format.UTF8String,
		    arguments)) == -1)
			@throw [OFInvalidFormatException exception];

		_s->cStringLength = cStringLength;

		@try {
			switch (of_string_utf8_check(tmp, cStringLength,
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
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







-
-
+
+








-
+


















-
+



-
+







		return true;

	if (![object isKindOfClass: [OFString class]])
		return false;

	otherString = object;

	if ([otherString UTF8StringLength] != _s->cStringLength ||
	    [otherString length] != _s->length)
	if (otherString.UTF8StringLength != _s->cStringLength ||
	    otherString.length != _s->length)
		return false;

	if (([otherString isKindOfClass: [OFString_UTF8 class]] ||
	    [otherString isKindOfClass: [OFMutableString_UTF8 class]]) &&
	    _s->hashed && otherString->_s->hashed &&
	    _s->hash != otherString->_s->hash)
		return false;

	if (strcmp(_s->cString, [otherString UTF8String]) != 0)
	if (strcmp(_s->cString, otherString.UTF8String) != 0)
		return false;

	return true;
}

- (of_comparison_result_t)compare: (id <OFComparing>)object
{
	OFString *otherString;
	size_t otherCStringLength, minimumCStringLength;
	int compare;

	if (object == self)
		return OF_ORDERED_SAME;

	if (![(id)object isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];

	otherString = (OFString *)object;
	otherCStringLength = [otherString UTF8StringLength];
	otherCStringLength = otherString.UTF8StringLength;
	minimumCStringLength = (_s->cStringLength > otherCStringLength
	    ? otherCStringLength : _s->cStringLength);

	if ((compare = memcmp(_s->cString, [otherString UTF8String],
	if ((compare = memcmp(_s->cString, otherString.UTF8String,
	    minimumCStringLength)) == 0) {
		if (_s->cStringLength > otherCStringLength)
			return OF_ORDERED_DESCENDING;
		if (_s->cStringLength < otherCStringLength)
			return OF_ORDERED_ASCENDING;
		return OF_ORDERED_SAME;
	}
852
853
854
855
856
857
858
859
860


861
862
863
864
865
866
867
852
853
854
855
856
857
858


859
860
861
862
863
864
865
866
867







-
-
+
+








	if (otherString == self)
		return OF_ORDERED_SAME;

	if (![otherString isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];

	otherCString = [otherString UTF8String];
	otherCStringLength = [otherString UTF8StringLength];
	otherCString = otherString.UTF8String;
	otherCStringLength = otherString.UTF8StringLength;

#ifdef OF_HAVE_UNICODE_TABLES
	if (!_s->isUTF8) {
#endif
		minimumCStringLength = (_s->cStringLength > otherCStringLength
		    ? otherCStringLength : _s->cStringLength);

943
944
945
946
947
948
949
950
951


952
953
954
955
956
957
958
943
944
945
946
947
948
949


950
951
952
953
954
955
956
957
958







-
-
+
+







		ssize_t length;

		if ((length = of_string_utf8_decode(_s->cString + i,
		    _s->cStringLength - i, &c)) <= 0)
			@throw [OFInvalidEncodingException exception];

		OF_HASH_ADD(hash, (c & 0xFF0000) >> 16);
		OF_HASH_ADD(hash, (c & 0x00FF00) >>  8);
		OF_HASH_ADD(hash,  c & 0x0000FF);
		OF_HASH_ADD(hash, (c & 0x00FF00) >> 8);
		OF_HASH_ADD(hash, c & 0x0000FF);

		i += length - 1;
	}

	OF_HASH_FINALIZE(hash);

	_s->hash = hash;
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
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







-
+















-
-
+
+







}

- (void)getCharacters: (of_unichar_t *)buffer
	      inRange: (of_range_t)range
{
	/* TODO: Could be slightly optimized */
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	const of_unichar_t *characters = self.characters;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _s->length)
		@throw [OFOutOfRangeException exception];

	memcpy(buffer, characters + range.location,
	    range.length * sizeof(of_unichar_t));

	objc_autoreleasePoolPop(pool);
}

- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
		      range: (of_range_t)range
{
	const char *cString = [string UTF8String];
	size_t cStringLength = [string UTF8StringLength];
	const char *cString = string.UTF8String;
	size_t cStringLength = string.UTF8StringLength;
	size_t rangeLocation, rangeLength;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _s->length)
		@throw [OFOutOfRangeException exception];

	if (_s->isUTF8) {
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


1064
1065
1066
1067
1068
1069
1070
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
1064
1065
1066
1067
1068
1069
1070







-
+














-
+











-
-
+
+








	if (options & OF_STRING_SEARCH_BACKWARDS) {
		for (size_t i = rangeLength - cStringLength;; i--) {
			if (memcmp(_s->cString + rangeLocation + i, cString,
			    cStringLength) == 0) {
				range.location += of_string_utf8_get_index(
				    _s->cString + rangeLocation, i);
				range.length = [string length];
				range.length = string.length;

				return range;
			}

			/* Did not match and we're at the last char */
			if (i == 0)
				return of_range(OF_NOT_FOUND, 0);
		}
	} else {
		for (size_t i = 0; i <= rangeLength - cStringLength; i++) {
			if (memcmp(_s->cString + rangeLocation + i, cString,
			    cStringLength) == 0) {
				range.location += of_string_utf8_get_index(
				    _s->cString + rangeLocation, i);
				range.length = [string length];
				range.length = string.length;

				return range;
			}
		}
	}

	return of_range(OF_NOT_FOUND, 0);
}

- (bool)containsString: (OFString *)string
{
	const char *cString = [string UTF8String];
	size_t cStringLength = [string UTF8StringLength];
	const char *cString = string.UTF8String;
	size_t cStringLength = string.UTF8StringLength;

	if (cStringLength == 0)
		return true;

	if (cStringLength > _s->cStringLength)
		return false;

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







-
+




-
+




-
+





-
+







-
-
+
+








	return [OFString stringWithUTF8String: _s->cString + start
				       length: end - start];
}

- (bool)hasPrefix: (OFString *)prefix
{
	size_t cStringLength = [prefix UTF8StringLength];
	size_t cStringLength = prefix.UTF8StringLength;

	if (cStringLength > _s->cStringLength)
		return false;

	return (memcmp(_s->cString, [prefix UTF8String], cStringLength) == 0);
	return (memcmp(_s->cString, prefix.UTF8String, cStringLength) == 0);
}

- (bool)hasSuffix: (OFString *)suffix
{
	size_t cStringLength = [suffix UTF8StringLength];
	size_t cStringLength = suffix.UTF8StringLength;

	if (cStringLength > _s->cStringLength)
		return false;

	return (memcmp(_s->cString + (_s->cStringLength - cStringLength),
	    [suffix UTF8String], cStringLength) == 0);
	    suffix.UTF8String, cStringLength) == 0);
}

- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
				 options: (int)options
{
	void *pool;
	OFMutableArray *array;
	const char *cString = [delimiter UTF8String];
	size_t cStringLength = [delimiter UTF8StringLength];
	const char *cString = delimiter.UTF8String;
	size_t cStringLength = delimiter.UTF8StringLength;
	bool skipEmpty = (options & OF_STRING_SKIP_EMPTY);
	size_t last;
	OFString *component;

	array = [OFMutableArray array];
	pool = objc_autoreleasePoolPush();

1139
1140
1141
1142
1143
1144
1145
1146

1147
1148
1149
1150
1151
1152
1153

1154
1155
1156
1157
1158
1159
1160
1139
1140
1141
1142
1143
1144
1145

1146
1147
1148
1149
1150
1151
1152

1153
1154
1155
1156
1157
1158
1159
1160







-
+






-
+







	last = 0;
	for (size_t i = 0; i <= _s->cStringLength - cStringLength; i++) {
		if (memcmp(_s->cString + i, cString, cStringLength) != 0)
			continue;

		component = [OFString stringWithUTF8String: _s->cString + last
						    length: i - last];
		if (!skipEmpty || [component length] > 0)
		if (!skipEmpty || component.length > 0)
			[array addObject: component];

		i += cStringLength - 1;
		last = i + 1;
	}
	component = [OFString stringWithUTF8String: _s->cString + last];
	if (!skipEmpty || [component length] > 0)
	if (!skipEmpty || component.length > 0)
		[array addObject: component];

	[array makeImmutable];

	objc_autoreleasePoolPop(pool);

	return array;

Modified src/OFSystemInfo.m from [ee4e3a6986] to [a2974f4317].

145
146
147
148
149
150
151
152
153



154
155

156
157
158
159
160
161
162
145
146
147
148
149
150
151


152
153
154
155

156
157
158
159
160
161
162
163







-
-
+
+
+

-
+







initOperatingSystemVersion(void)
{
#if defined(OF_IOS) || defined(OF_MACOS)
# ifdef OF_HAVE_FILES
	void *pool = objc_autoreleasePoolPush();

	@try {
		OFString *propertyList = [OFString stringWithContentsOfFile:
		    @"/System/Library/CoreServices/SystemVersion.plist"];
		OFDictionary *propertyList = [OFString stringWithContentsOfFile:
		    @"/System/Library/CoreServices/SystemVersion.plist"]
		    .propertyListValue;

		operatingSystemVersion = [[[propertyList propertyListValue]
		operatingSystemVersion = [[propertyList
		    objectForKey: @"ProductVersion"] copy];
	} @finally {
		objc_autoreleasePoolPop(pool);
	}
# endif
#elif defined(OF_WINDOWS)
# ifdef OF_HAVE_FILES
173
174
175
176
177
178
179
180
181


182
183
184
185
186
187
188
174
175
176
177
178
179
180


181
182
183
184
185
186
187
188
189







-
-
+
+







		systemDirLen = GetSystemDirectoryW(systemDir, PATH_MAX);
		if (systemDirLen == 0)
			return;

		systemDirString = [OFString
		    stringWithUTF16String: systemDir
				   length: systemDirLen];
		path = [[systemDirString stringByAppendingPathComponent:
		    @"kernel32.dll"] UTF16String];
		path = [systemDirString stringByAppendingPathComponent:
		    @"kernel32.dll"].UTF16String;

		if ((bufferLen = GetFileVersionInfoSizeW(path, NULL)) == 0)
			return;
		if ((buffer = malloc(bufferLen)) == 0)
			return;

		@try {
433
434
435
436
437
438
439
440

441
442
443
444
445
446
447
434
435
436
437
438
439
440

441
442
443
444
445
446
447
448







-
+







	return @"PROGDIR:";
# else
	OFDictionary *env = [OFApplication environment];
	OFString *var;
	void *pool;

	if ((var = [env objectForKey: @"XDG_DATA_HOME"]) != nil &&
	    [var length] > 0)
	    var.length > 0)
		return var;

	if ((var = [env objectForKey: @"HOME"]) == nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	pool = objc_autoreleasePoolPush();
526
527
528
529
530
531
532
533

534
535
536
537
538
539
540
527
528
529
530
531
532
533

534
535
536
537
538
539
540
541







-
+







# elif defined(OF_AMIGAOS)
	return @"PROGDIR:";
# else
	OFDictionary *env = [OFApplication environment];
	OFString *var;

	if ((var = [env objectForKey: @"XDG_CONFIG_HOME"]) != nil &&
	    [var length] > 0)
	    var.length > 0)
		return var;

	if ((var = [env objectForKey: @"HOME"]) == nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	return [var stringByAppendingPathComponent: @".config"];

Modified src/OFTCPSocket.h from [7fc0a58cc9] to [0da62ee227].

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







-
-
+
+











-
+
-
-
+


















-
+













-
-
+
+







/*!
 * @brief A block which is called when the socket connected.
 *
 * @param socket The socket which connected
 * @param exception An exception which occurred while connecting the socket or
 *		    `nil` on success
 */
typedef void (^of_tcp_socket_async_connect_block_t)(
    OF_KINDOF(OFTCPSocket *) socket, id _Nullable exception);
typedef void (^of_tcp_socket_async_connect_block_t)(OFTCPSocket *socket,
    id _Nullable exception);

/*!
 * @brief A block which is called when the socket accepted a connection.
 *
 * @param socket The socket which accepted the connection
 * @param acceptedSocket The socket which has been accepted
 * @param exception An exception which occurred while accepting the socket or
 *		    `nil` on success
 * @return A bool whether the same block should be used for the next incoming
 *	   connection
 */
typedef bool (^of_tcp_socket_async_accept_block_t)(
typedef bool (^of_tcp_socket_async_accept_block_t)(OFTCPSocket *socket,
    OF_KINDOF(OFTCPSocket *) socket, OF_KINDOF(OFTCPSocket *) acceptedSocket,
    id _Nullable exception);
    OFTCPSocket *acceptedSocket, id _Nullable exception);
#endif

/*!
 * @protocol OFTCPSocketDelegate OFTCPSocket.h ObjFW/OFTCPSocket.h
 *
 * A delegate for OFTCPSocket.
 */
@protocol OFTCPSocketDelegate <OFStreamDelegate>
@optional
/*!
 * @brief A method which is called when a socket connected.
 *
 * @param socket The socket which connected
 * @param host The host connected to
 * @param port The port on the host connected to
 * @param exception An exception that occurred while connecting, or nil on
 *		    success
 */
-     (void)socket: (OF_KINDOF(OFTCPSocket *))socket
-     (void)socket: (OFTCPSocket *)socket
  didConnectToHost: (OFString *)host
	      port: (uint16_t)port
	 exception: (nullable id)exception;

/*!
 * @brief A method which is called when a socket accepted a connection.
 *
 * @param socket The socket which accepted the connection
 * @param acceptedSocket The socket which has been accepted
 * @param exception An exception that occurred while accepting, or nil on
 *		    success
 * @return A bool whether to accept the next incoming connection
 */
-    (bool)socket: (OF_KINDOF(OFTCPSocket *))socket
  didAcceptSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket
-    (bool)socket: (OFTCPSocket *)socket
  didAcceptSocket: (OFTCPSocket *)acceptedSocket
	exception: (nullable id)exception;
@end

/*!
 * @class OFTCPSocket OFTCPSocket.h ObjFW/OFTCPSocket.h
 *
 * @brief A class which provides methods to create and use TCP sockets.

Modified src/OFTCPSocket.m from [909cd558d8] to [e57d0397dd].

134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148







-
+







		_socket = [sock retain];
		_host = [host copy];
		_port = port;
		_SOCKS5Host = [SOCKS5Host copy];
		_SOCKS5Port = SOCKS5Port;
		_delegate = [delegate retain];

		[_socket setDelegate: self];
		_socket.delegate = self;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
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
213
214
215
216
217
218
219
220
221

222
223
224
225

226
227
228
229
230

231
232
233
234
235
236
237
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
213
214
215
216
217
218
219
220

221
222
223
224

225
226
227
228
229

230
231
232
233
234
235
236
237







-
+

-
-
+
+


















-
+






-
+












-
+



-
+




-
+







	return self;
}
#endif

- (void)dealloc
{
#ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
	if (_block == NULL)
#endif
		if ([_socket delegate] == self)
			[_socket setDelegate: _delegate];
		if (_socket.delegate == self)
			_socket.delegate = _delegate;

	[_socket release];
	[_host release];
	[_SOCKS5Host release];
	[_delegate release];
#ifdef OF_HAVE_BLOCKS
	[_block release];
#endif
	[_exception release];
	[_socketAddresses release];
	[_request release];

	[super dealloc];
}

- (void)didConnect
{
	if (_exception == nil)
		[_socket setBlocking: true];
		_socket.blocking = true;

#ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		_block(_socket, _exception);
	else {
#endif
		[_socket setDelegate: _delegate];
		_socket.delegate = _delegate;

		if ([_delegate respondsToSelector:
		    @selector(socket:didConnectToHost:port:exception:)])
			[_delegate    socket: _socket
			    didConnectToHost: _host
					port: _port
				   exception: _exception];
#ifdef OF_HAVE_BLOCKS
	}
#endif
}

- (void)of_socketDidConnect: (OF_KINDOF(OFTCPSocket *))sock
- (void)of_socketDidConnect: (OFTCPSocket *)sock
		  exception: (id)exception
{
	if (exception != nil) {
		if (_socketAddressesIndex >= [_socketAddresses count]) {
		if (_socketAddressesIndex >= _socketAddresses.count) {
			_exception = [exception retain];
			[self didConnect];
		} else {
			[self tryNextAddressWithRunLoopMode:
			    [[OFRunLoop currentRunLoop] currentMode]];
			    [OFRunLoop currentRunLoop].currentMode];
		}

		return;
	}

	if (_SOCKS5Host != nil)
		[self sendSOCKS5Request];
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262
248
249
250
251
252
253
254

255
256
257
258
259
260
261
262







-
+







	if (_SOCKS5Host != nil)
		of_socket_address_set_port(&address, _SOCKS5Port);
	else
		of_socket_address_set_port(&address, _port);

	if (![_socket of_createSocketForAddress: &address
					  errNo: &errNo]) {
		if (_socketAddressesIndex >= [_socketAddresses count]) {
		if (_socketAddressesIndex >= _socketAddresses.count) {
			_exception = [[OFConnectionFailedException alloc]
			    initWithHost: _host
				    port: _port
				  socket: _socket
				   errNo: errNo];
			[self didConnect];
			return;
273
274
275
276
277
278
279
280

281
282

283
284
285
286
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
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
273
274
275
276
277
278
279

280
281

282
283
284
285
286
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
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







-
+

-
+














-
+

















-
+



















-
+








-
+







	 * Additionally, on Wii, there is no getsockopt(), so it would not be
	 * possible to get the error (or success) after connecting anyway.
	 *
	 * So for now, connecting is blocking on Wii and 3DS.
	 *
	 * FIXME: Use a different thread as a work around.
	 */
	[_socket setBlocking: true];
	_socket.blocking = true;
#else
	[_socket setBlocking: false];
	_socket.blocking = false;
#endif

	if (![_socket of_connectSocketToAddress: &address
					  errNo: &errNo]) {
#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII)
		if (errNo == EINPROGRESS) {
			[OFRunLoop of_addAsyncConnectForTCPSocket: _socket
							     mode: runLoopMode
							 delegate: self];
			return;
		} else {
#endif
			[_socket of_closeSocket];

			if (_socketAddressesIndex >= [_socketAddresses count]) {
			if (_socketAddressesIndex >= _socketAddresses.count) {
				_exception = [[OFConnectionFailedException
				    alloc] initWithHost: _host
						   port: _port
						 socket: _socket
						  errNo: errNo];
				[self didConnect];
				return;
			}

			[self tryNextAddressWithRunLoopMode: runLoopMode];
			return;
#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII)
		}
#endif
	}

#if defined(OF_NINTENDO_3DS) || defined(OF_WII)
	[_socket setBlocking: false];
	_socket.blocking = false;
#endif

	[self didConnect];
}

-	(void)resolver: (OFDNSResolver *)resolver
  didResolveDomainName: (OFString *)domainName
       socketAddresses: (OFData *)socketAddresses
	     exception: (id)exception
{
	if (exception != nil) {
		_exception = [exception retain];
		[self didConnect];
		return;
	}

	_socketAddresses = [socketAddresses copy];

	[self tryNextAddressWithRunLoopMode:
	    [[OFRunLoop currentRunLoop] currentMode]];
	    [OFRunLoop currentRunLoop].currentMode];
}

- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
{
	OFString *host;
	uint16_t port;

	if (_SOCKS5Host != nil) {
		if ([_host UTF8StringLength] > 255)
		if (_host.UTF8StringLength > 255)
			@throw [OFOutOfRangeException exception];

		host = _SOCKS5Host;
		port = _SOCKS5Port;
	} else {
		host = _host;
		port = _port;
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
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







-
+


-
+
















-
+







- (void)sendSOCKS5Request
{
	OFData *data = [OFData dataWithItems: "\x05\x01\x00"
				       count: 3];

	_SOCKS5State = SOCKS5_STATE_SEND_AUTHENTICATION;
	[_socket asyncWriteData: data
		    runLoopMode: [[OFRunLoop currentRunLoop] currentMode]];
		    runLoopMode: [OFRunLoop currentRunLoop].currentMode];
}

-      (bool)stream: (OF_KINDOF(OFStream *))sock
-      (bool)stream: (OFStream *)sock
  didReadIntoBuffer: (void *)buffer
	     length: (size_t)length
	  exception: (id)exception
{
	of_run_loop_mode_t runLoopMode;
	unsigned char *SOCKSVersion;
	uint8_t hostLength;
	unsigned char port[2];
	unsigned char *response, *addressLength;

	if (exception != nil) {
		_exception = [exception retain];
		[self didConnect];
		return false;
	}

	runLoopMode = [[OFRunLoop currentRunLoop] currentMode];
	runLoopMode = [OFRunLoop currentRunLoop].currentMode;

	switch (_SOCKS5State) {
	case SOCKS5_STATE_READ_VERSION:
		SOCKSVersion = buffer;

		if (SOCKSVersion[0] != 5 || SOCKSVersion[1] != 0) {
			_exception = [[OFConnectionFailedException alloc]
417
418
419
420
421
422
423
424

425
426

427
428
429
430
431
432

433
434
435
436
437
438
439
417
418
419
420
421
422
423

424
425

426
427
428
429
430
431

432
433
434
435
436
437
438
439







-
+

-
+





-
+








		[_request release];
		_request = [[OFMutableData alloc] init];

		[_request addItems: "\x05\x01\x00\x03"
			     count: 4];

		hostLength = (uint8_t)[_host UTF8StringLength];
		hostLength = (uint8_t)_host.UTF8StringLength;
		[_request addItem: &hostLength];
		[_request addItems: [_host UTF8String]
		[_request addItems: _host.UTF8String
			     count: hostLength];

		port[0] = _port >> 8;
		port[1] = _port & 0xFF;
		[_request addItems: port
			    count: 2];
			     count: 2];

		_SOCKS5State = SOCKS5_STATE_SEND_REQUEST;
		[_socket asyncWriteData: _request
			    runLoopMode: runLoopMode];
		return false;
	case SOCKS5_STATE_READ_RESPONSE:
		response = buffer;
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
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







-
+












-
+







		return false;
	default:
		assert(0);
		return false;
	}
}

- (OFData *)stream: (OF_KINDOF(OFStream *))sock
- (OFData *)stream: (OFStream *)sock
      didWriteData: (OFData *)data
      bytesWritten: (size_t)bytesWritten
	 exception: (id)exception
{
	of_run_loop_mode_t runLoopMode;

	if (exception != nil) {
		_exception = [exception retain];
		[self didConnect];
		return nil;
	}

	runLoopMode = [[OFRunLoop currentRunLoop] currentMode];
	runLoopMode = [OFRunLoop currentRunLoop].currentMode;

	switch (_SOCKS5State) {
	case SOCKS5_STATE_SEND_AUTHENTICATION:
		_SOCKS5State = SOCKS5_STATE_READ_VERSION;
		[_socket asyncReadIntoBuffer: _buffer
				 exactLength: 2
				 runLoopMode: runLoopMode];
577
578
579
580
581
582
583
584

585
586
587
588
589
590
591
577
578
579
580
581
582
583

584
585
586
587
588
589
590
591







-
+







- (void)dealloc
{
	[_exception release];

	[super dealloc];
}

-     (void)socket: (OF_KINDOF(OFTCPSocket *))sock
-     (void)socket: (OFTCPSocket *)sock
  didConnectToHost: (OFString *)host
	      port: (uint16_t)port
	 exception: (id)exception
{
	_done = true;
	_exception = [exception retain];
}
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
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







-
+















-
+







{
	void *pool = objc_autoreleasePoolPush();
	id <OFTCPSocketDelegate> delegate = [_delegate retain];
	OFTCPSocket_ConnectDelegate *connectDelegate =
	    [[[OFTCPSocket_ConnectDelegate alloc] init] autorelease];
	OFRunLoop *runLoop = [OFRunLoop currentRunLoop];

	[self setDelegate: connectDelegate];
	self.delegate = connectDelegate;
	[self asyncConnectToHost: host
			    port: port
		     runLoopMode: connectRunLoopMode];

	while (!connectDelegate->_done)
		[runLoop runMode: connectRunLoopMode
		      beforeDate: nil];

	/* Cleanup */
	[runLoop runMode: connectRunLoopMode
	      beforeDate: [OFDate date]];

	if (connectDelegate->_exception != nil)
		@throw connectDelegate->_exception;

	[self setDelegate: delegate];
	self.delegate = delegate;

	objc_autoreleasePoolPop(pool);
}

- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
{

Modified src/OFTarArchive.h from [12a3337977] to [c1cedd4497].

27
28
29
30
31
32
33
34

35
36
37
38
39
40
41

42
43
44
45
46
47
48
27
28
29
30
31
32
33

34
35
36
37
38
39
40

41
42
43
44
45
46
47
48







-
+






-
+







/*!
 * @class OFTarArchive OFTarArchive.h ObjFW/OFTarArchive.h
 *
 * @brief A class for accessing and manipulating tar archives.
 */
@interface OFTarArchive: OFObject
{
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	enum {
		OF_TAR_ARCHIVE_MODE_READ,
		OF_TAR_ARCHIVE_MODE_WRITE,
		OF_TAR_ARCHIVE_MODE_APPEND
	} _mode;
	of_string_encoding_t _encoding;
	OF_KINDOF(OFStream *) _Nullable _lastReturnedStream;
	OFStream *_Nullable _lastReturnedStream;
}

/*!
 * @brief The encoding to use for the archive. Defaults to UTF-8.
 */
@property (nonatomic) of_string_encoding_t encoding;

63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77







-
+







 * @param stream A stream from which the tar archive will be read.
 *		 For append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the tar file. Valid modes are "r" for reading,
 *	       "w" for creating a new file and "a" for appending to an existing
 *	       archive.
 * @return A new, autoreleased OFTarArchive
 */
+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)archiveWithStream: (OFStream *)stream
			     mode: (OFString *)mode;

#ifdef OF_HAVE_FILES
/*!
 * @brief Creates a new OFTarArchive object with the specified file.
 *
 * @param path The path to the tar archive
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107







-
+







 * @param stream A stream from which the tar archive will be read.
 *		 For append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the tar file. Valid modes are "r" for reading,
 *	       "w" for creating a new file and "a" for appending to an existing
 *	       archive.
 * @return An initialized OFTarArchive
 */
- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode OF_DESIGNATED_INITIALIZER;

#ifdef OF_HAVE_FILES
/*!
 * @brief Initializes an already allocated OFTarArchive object with the
 *	  specified file.
 *

Modified src/OFTarArchive.m from [cfc88dc079] to [c1512afd3b].

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







-
+

-
+














-
+












-
+



-
+






-
+




















-
+







 */

#include "config.h"

#import "OFTarArchive.h"
#import "OFTarArchiveEntry.h"
#import "OFTarArchiveEntry+Private.h"
#import "OFStream.h"
#import "OFDate.h"
#import "OFSeekableStream.h"
#import "OFDate.h"
#import "OFStream.h"
#ifdef OF_HAVE_FILES
# import "OFFile.h"
#endif

#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFNotOpenException.h"
#import "OFOutOfRangeException.h"
#import "OFTruncatedDataException.h"
#import "OFWriteFailedException.h"

@interface OFTarArchive_FileReadStream: OFStream <OFReadyForReadingObserving>
{
	OFTarArchiveEntry *_entry;
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	uint64_t _toRead;
	bool _atEndOfStream, _skipped;
}

- (instancetype)of_initWithStream: (OFStream *)stream
			    entry: (OFTarArchiveEntry *)entry;
- (void)of_skip;
@end

@interface OFTarArchive_FileWriteStream: OFStream <OFReadyForWritingObserving>
{
	OFTarArchiveEntry *_entry;
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	uint64_t _toWrite;
}

- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFStream *)stream
			    entry: (OFTarArchiveEntry *)entry;
@end

@implementation OFTarArchive: OFObject
@synthesize encoding = _encoding;

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)archiveWithStream: (OFStream *)stream
			     mode: (OFString *)mode
{
	return [[[self alloc] initWithStream: stream
					mode: mode] autorelease];
}

#ifdef OF_HAVE_FILES
+ (instancetype)archiveWithPath: (OFString *)path
			   mode: (OFString *)mode
{
	return [[[self alloc] initWithPath: path
				      mode: mode] autorelease];
}
#endif

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode
{
	self = [super init];

	@try {
		_stream = [stream retain];

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







-
-
-
+
+
+









-
-
+
+







				uint32_t u32[1024 / sizeof(uint32_t)];
			} buffer;
			bool empty = true;

			if (![_stream isKindOfClass: [OFSeekableStream class]])
				@throw [OFInvalidArgumentException exception];

			[_stream seekToOffset: -1024
				       whence: SEEK_END];
			[_stream readIntoBuffer: buffer.c
			[(OFSeekableStream *)stream seekToOffset: -1024
							  whence: SEEK_END];
			[stream readIntoBuffer: buffer.c
				    exactLength: 1024];

			for (size_t i = 0; i < 1024 / sizeof(uint32_t); i++)
				if (buffer.u32[i] != 0)
					empty = false;

			if (!empty)
				@throw [OFInvalidFormatException exception];

			[_stream seekToOffset: -1024
				       whence: SEEK_END];
			[(OFSeekableStream *)stream seekToOffset: -1024
							  whence: SEEK_END];
		}

		_encoding = OF_STRING_ENCODING_UTF_8;
	} @catch (id e) {
		[self release];
		@throw e;
	}
173
174
175
176
177
178
179
180

181
182
183
184
185

186
187
188
189
190
191
192
173
174
175
176
177
178
179

180
181
182
183
184

185
186
187
188
189
190
191
192







-
+




-
+







		uint32_t u32[512 / sizeof(uint32_t)];
	} buffer;
	bool empty = true;

	if (_mode != OF_TAR_ARCHIVE_MODE_READ)
		@throw [OFInvalidArgumentException exception];

	[_lastReturnedStream of_skip];
	[(OFTarArchive_FileReadStream *)_lastReturnedStream of_skip];
	[_lastReturnedStream close];
	[_lastReturnedStream release];
	_lastReturnedStream = nil;

	if ([_stream isAtEndOfStream])
	if (_stream.atEndOfStream)
		return nil;

	[_stream readIntoBuffer: buffer.c
		    exactLength: 512];

	for (size_t i = 0; i < 512 / sizeof(uint32_t); i++)
		if (buffer.u32[i] != 0)
218
219
220
221
222
223
224

225

226
227
228
229
230
231
232
218
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233







+
-
+







{
	if (_mode != OF_TAR_ARCHIVE_MODE_READ)
		@throw [OFInvalidArgumentException exception];

	if (_lastReturnedStream == nil)
		@throw [OFInvalidArgumentException exception];

	return [[(OFTarArchive_FileReadStream *)_lastReturnedStream
	return [[_lastReturnedStream retain] autorelease];
	    retain] autorelease];
}

- (OFStream <OFReadyForWritingObserving> *)
    streamForWritingEntry: (OFTarArchiveEntry *)entry
{
	void *pool;

245
246
247
248
249
250
251

252

253
254
255
256
257
258
259
246
247
248
249
250
251
252
253

254
255
256
257
258
259
260
261







+
-
+








	_lastReturnedStream = [[OFTarArchive_FileWriteStream alloc]
	    of_initWithStream: _stream
			entry: entry];

	objc_autoreleasePoolPop(pool);

	return [[(OFTarArchive_FileWriteStream *)_lastReturnedStream
	return [[_lastReturnedStream retain] autorelease];
	    retain] autorelease];
}

- (void)close
{
	if (_stream == nil)
		return;

279
280
281
282
283
284
285
286

287
288
289
290
291
292
293
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295







-
+







			    entry: (OFTarArchiveEntry *)entry
{
	self = [super init];

	@try {
		_entry = [entry copy];
		_stream = [stream retain];
		_toRead = [entry size];
		_toRead = entry.size;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
337
338
339
340
341
342
343
344

345
346
347
348

349

350
351
352
353
354
355
356
339
340
341
342
343
344
345

346
347
348
349
350
351

352
353
354
355
356
357
358
359







-
+




+
-
+







		@throw [OFNotOpenException exceptionWithObject: self];

	return _atEndOfStream;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]);
	return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer);
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_stream)
	return [_stream fileDescriptorForReading];
	    .fileDescriptorForReading;
}

- (void)close
{
	[self of_skip];

	[_stream release];
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
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







-
-
+
+



-
+


+
-
-
+
+
















-
+











-
+







-
+







	if (_stream == nil || _skipped)
		return;

	if ([_stream isKindOfClass: [OFSeekableStream class]] &&
	    _toRead <= INT64_MAX && (of_offset_t)_toRead == (int64_t)_toRead) {
		uint64_t size;

		[_stream seekToOffset: (of_offset_t)_toRead
			       whence: SEEK_CUR];
		[(OFSeekableStream *)_stream seekToOffset: (of_offset_t)_toRead
						   whence: SEEK_CUR];

		_toRead = 0;

		size = [_entry size];
		size = _entry.size;

		if (size % 512 != 0)
			[(OFSeekableStream *)_stream
			[_stream seekToOffset: 512 - (size % 512)
				       whence: SEEK_CUR];
			    seekToOffset: 512 - (size % 512)
				  whence: SEEK_CUR];
	} else {
		char buffer[512];
		uint64_t size;

		while (_toRead >= 512) {
			[_stream readIntoBuffer: buffer
				    exactLength: 512];
			_toRead -= 512;
		}

		if (_toRead > 0) {
			[_stream readIntoBuffer: buffer
				    exactLength: (size_t)_toRead];
			_toRead = 0;
		}

		size = [_entry size];
		size = _entry.size;

		if (size % 512 != 0)
			[_stream readIntoBuffer: buffer
				    exactLength: (size_t)(512 - (size % 512))];
	}

	_skipped = true;
}
@end

@implementation OFTarArchive_FileWriteStream
- (instancetype)of_initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)of_initWithStream: (OFStream *)stream
			    entry: (OFTarArchiveEntry *)entry
{
	self = [super init];

	@try {
		_entry = [entry copy];
		_stream = [stream retain];
		_toWrite = [entry size];
		_toWrite = entry.size;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
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
485
486
487
488
489
490
491

492
493
494
495
496
497
498
499
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
495

496
497
498
499
500
501
502
503
504







-
+


















+
-
+







-
+





-
+







-
+








	if ((uint64_t)length > _toWrite)
		@throw [OFOutOfRangeException exception];

	@try {
		bytesWritten = [_stream writeBuffer: buffer
					     length: length];
	} @catch (OFWriteFailedException *e) {
		_toWrite -= [e bytesWritten];
		_toWrite -= e.bytesWritten;
		@throw e;
	}

	_toWrite -= bytesWritten;

	return bytesWritten;
}

- (bool)lowlevelIsAtEndOfStream
{
	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	return (_toWrite == 0);
}

- (int)fileDescriptorForWriting
{
	return ((id <OFReadyForWritingObserving>)_stream)
	return [_stream fileDescriptorForWriting];
	    .fileDescriptorForWriting;
}

- (void)close
{
	if (_stream == nil)
		return;

	uint64_t remainder = 512 - [_entry size] % 512;
	uint64_t remainder = 512 - _entry.size % 512;

	if (_toWrite > 0)
		@throw [OFTruncatedDataException exception];

	if (remainder != 512) {
		bool wasWriteBuffered = [_stream isWriteBuffered];
		bool wasWriteBuffered = _stream.writeBuffered;

		[_stream setWriteBuffered: true];

		while (remainder--)
			[_stream writeInt8: 0];

		[_stream flushWriteBuffer];
		[_stream setWriteBuffered: wasWriteBuffered];
		_stream.writeBuffered = wasWriteBuffered;
	}

	[_stream release];
	_stream = nil;

	[super close];
}
@end

Modified src/OFTarArchiveEntry.m from [f5aca25b8d] to [cfb25a345f].

61
62
63
64
65
66
67
68
69


70
71
72
73
74
75
76
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75
76







-
-
+
+







	if (length == 0)
		return 0;

	if (buffer[0] == 0x80) {
		for (size_t i = 1; i < length; i++)
			value = (value << 8) | buffer[i];
	} else
		value = [stringFromBuffer(buffer, length,
		    OF_STRING_ENCODING_ASCII) octalValue];
		value = stringFromBuffer(buffer, length,
		    OF_STRING_ENCODING_ASCII).octalValue;

	if (value > max)
		@throw [OFOutOfRangeException exception];

	return value;
}

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







-
+



















-
+







		_modificationDate = [[OFDate alloc]
		    initWithTimeIntervalSince1970:
		    (of_time_interval_t)octalValueFromBuffer(
		    header + 136, 12, UINTMAX_MAX)];
		_type = header[156];

		targetFileName = stringFromBuffer(header + 157, 100, encoding);
		if ([targetFileName length] > 0)
		if (targetFileName.length > 0)
			_targetFileName = [targetFileName copy];

		if (_type == '\0')
			_type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE;

		if (memcmp(header + 257, "ustar\0" "00", 8) == 0) {
			OFString *prefix;

			_owner = [stringFromBuffer(header + 265, 32, encoding)
			    copy];
			_group = [stringFromBuffer(header + 297, 32, encoding)
			    copy];

			_deviceMajor = (uint32_t)octalValueFromBuffer(
			    header + 329, 8, UINT32_MAX);
			_deviceMinor = (uint32_t)octalValueFromBuffer(
			    header + 337, 8, UINT32_MAX);

			prefix = stringFromBuffer(header + 345, 155, encoding);
			if ([prefix length] > 0) {
			if (prefix.length > 0) {
				OFString *fileName = [OFString
				    stringWithFormat: @"%@/%@",
						      prefix, _fileName];
				[_fileName release];
				_fileName = [fileName copy];
			}
		}
276
277
278
279
280
281
282
283
284


285
286
287
288
289
290
291
292
276
277
278
279
280
281
282


283
284

285
286
287
288
289
290
291







-
-
+
+
-







	     @"\tType = %u\n"
	     @"\tTarget file name = %@\n"
	     @"\tOwner = %@\n"
	     @"\tGroup = %@\n"
	     @"\tDevice major = %" PRIu32 @"\n"
	     @"\tDevice minor = %" PRIu32 @"\n"
	     @">",
	    [self class], _fileName, _mode, _UID, _GID, _size,
	    _modificationDate, _type, _targetFileName, _owner, _group,
	    self.class, _fileName, _mode, _UID, _GID, _size, _modificationDate,
	    _type, _targetFileName, _owner, _group, _deviceMajor, _deviceMinor];
	    _deviceMajor, _deviceMinor];

	[ret retain];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}
307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
306
307
308
309
310
311
312

313
314
315
316
317
318
319
320







-
+







	    OF_STRING_ENCODING_ASCII);
	stringToBuffer(buffer + 116,
	    [OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8,
	    OF_STRING_ENCODING_ASCII);
	stringToBuffer(buffer + 124,
	    [OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12,
	    OF_STRING_ENCODING_ASCII);
	modificationDate = [_modificationDate timeIntervalSince1970];
	modificationDate = _modificationDate.timeIntervalSince1970;
	stringToBuffer(buffer + 136,
	    [OFString stringWithFormat: @"%011" PRIo64 " ", modificationDate],
	    12, OF_STRING_ENCODING_ASCII);

	/*
	 * During checksumming, the checksum field is expected to be set to 8
	 * spaces.

Modified src/OFThread.m from [8c84f260e2] to [5653a804be].

118
119
120
121
122
123
124
125

126
127
128
129

130
131
132
133
134
135
136
118
119
120
121
122
123
124

125
126
127
128

129
130
131
132
133
134
135
136







-
+



-
+







callMain(id object)
{
	OFThread *thread = (OFThread *)object;
	OFString *name;

	if (!of_tlskey_set(threadSelfKey, thread))
		@throw [OFInitializationFailedException
		    exceptionWithClass: [thread class]];
		    exceptionWithClass: thread.class];

	thread->_pool = objc_autoreleasePoolPush();

	name = [thread name];
	name = thread.name;
	if (name != nil)
		of_thread_set_name(
		    [name cStringWithEncoding: [OFLocale encoding]]);
	else
		of_thread_set_name(object_getClassName(thread));

	/*
294
295
296
297
298
299
300
301

302
303
304
305
306
307
308
294
295
296
297
298
299
300

301
302
303
304
305
306
307
308







-
+







	usleep((unsigned int)lrint(
	    (timeInterval - trunc(timeInterval)) * 1000000));
#endif
}

+ (void)sleepUntilDate: (OFDate *)date
{
	[self sleepForTimeInterval: [date timeIntervalSinceNow]];
	[self sleepForTimeInterval: date.timeIntervalSinceNow];
}

+ (void)yield
{
#ifdef OF_HAVE_SCHED_YIELD
	sched_yield();
#else
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
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







-
+





-
+




-
+



















-
+







	[thread release];

	of_thread_exit();
}

+ (void)setName: (OFString *)name
{
	[[OFThread currentThread] setName: name];
	[OFThread currentThread].name = name;

	if (name != nil)
		of_thread_set_name(
		    [name cStringWithEncoding: [OFLocale encoding]]);
	else
		of_thread_set_name(class_getName([self class]));
		of_thread_set_name(class_getName(self.class));
}

+ (OFString *)name
{
	return [[OFThread currentThread] name];
	return [OFThread currentThread].name;
}

+ (void)of_createMainThread
{
	mainThread = [[OFThread alloc] init];
	mainThread->_thread = of_thread_current();

	if (!of_tlskey_set(threadSelfKey, mainThread))
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}

- (instancetype)init
{
	self = [super init];

	@try {
		if (!of_thread_attr_init(&_attr))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

Modified src/OFThreadPool.m from [751d46c26d] to [ff320a5fa0].

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







-
+









-
+







			of_list_object_t *listObject;

			if (_terminate) {
				objc_autoreleasePoolPop(pool);
				return nil;
			}

			listObject = [_queue firstListObject];
			listObject = _queue.firstListObject;

			while (listObject == NULL) {
				[_queueCondition wait];

				if (_terminate) {
					objc_autoreleasePoolPop(pool);
					return nil;
				}

				listObject = [_queue firstListObject];
				listObject = _queue.firstListObject;
			}

			job = [[listObject->object retain] autorelease];
			[_queue removeListObject: listObject];
		} @finally {
			[_queueCondition unlock];
		}

Modified src/OFTimer.m from [b2973aea61] to [3990e4e136].

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







-
+







-
+








-
+







	id object3 = [[_object3 retain] autorelease];
	id object4 = [[_object4 retain] autorelease];

	OF_ENSURE(_arguments <= 4);

	if (_repeats && _valid) {
		int64_t missedIntervals =
		    -[_fireDate timeIntervalSinceNow] / _interval;
		    -_fireDate.timeIntervalSinceNow / _interval;
		of_time_interval_t newFireDate;
		OFRunLoop *runLoop;

		/* In case the clock was changed backwards */
		if (missedIntervals < 0)
			missedIntervals = 0;

		newFireDate = [_fireDate timeIntervalSince1970] +
		newFireDate = _fireDate.timeIntervalSince1970 +
		    (missedIntervals + 1) * _interval;

		[_fireDate release];
		_fireDate = [[OFDate alloc]
		    initWithTimeIntervalSince1970: newFireDate];

		runLoop = [OFRunLoop currentRunLoop];
		[runLoop addTimer: self
			  forMode: [runLoop currentMode]];
			  forMode: runLoop.currentMode];
	} else
		[self invalidate];

#ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		_block(self);
	else {

Modified src/OFUDPSocket.h from [3a88d52639] to [55c0fec4d8].

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







-
+














-
+







 * @param buffer The buffer the packet has been written to
 * @param length The length of the packet
 * @param sender The address of the sender of the packet
 * @param exception An exception that occurred while receiving, or nil on
 *		    success
 * @return A bool whether the same block should be used for the next receive
 */
-	  (bool)socket: (OF_KINDOF(OFUDPSocket *))socket
-	  (bool)socket: (OFUDPSocket *)socket
  didReceiveIntoBuffer: (void *)buffer
		length: (size_t)length
		sender: (const of_socket_address_t *_Nonnull)sender
	     exception: (nullable id)exception;

/*!
 * @brief This which is called when a packet has been sent.
 *
 * @param socket The UDP socket which sent a packet
 * @param data The data which was sent
 * @param receiver The receiver for the UDP packet
 * @param exception An exception that occurred while sending, or nil on success
 * @return The data to repeat the send with or nil if it should not repeat
 */
- (nullable OFData *)socket: (OF_KINDOF(OFUDPSocket *))socket
- (nullable OFData *)socket: (OFUDPSocket *)socket
		didSendData: (OFData *)data
		   receiver: (const of_socket_address_t *_Nonnull)receiver
		  exception: (nullable id)exception;
@end

/*!
 * @class OFUDPSocket OFUDPSocket.h ObjFW/OFUDPSocket.h

Modified src/OFURL.m from [614bfb9897] to [3539c64da7].

68
69
70
71
72
73
74
75

76
77
78
79

80
81
82
83
84
85
86
68
69
70
71
72
73
74

75
76
77
78

79
80
81
82
83
84
85
86







-
+



-
+







# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	path = [path stringByReplacingOccurrencesOfString: @"\\"
					       withString: @"/"];
	path = [path stringByPrependingString: @"/"];

	return path;
# elif defined(OF_AMIGAOS)
	OFArray OF_GENERIC(OFString *) *components = [path pathComponents];
	OFArray OF_GENERIC(OFString *) *components = path.pathComponents;
	OFMutableString *ret = [OFMutableString string];

	for (OFString *component in components) {
		if ([component length] == 0)
		if (component.length == 0)
			continue;

		if ([component isEqual: @"/"])
			[ret appendString: @"/.."];
		else {
			[ret appendString: @"/"];
			[ret appendString: component];
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
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







-
+








-
+


-
+



















-
+







# endif
}

static OFString *
URLPathToPath(OFString *path)
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	path = [path substringWithRange: of_range(1, [path length] - 1)];
	path = [path substringWithRange: of_range(1, path.length - 1)];
	path = [path stringByReplacingOccurrencesOfString: @"/"
					       withString: @"\\"];

	return path;
# elif defined(OF_AMIGAOS)
	OFMutableArray OF_GENERIC(OFString *) *components;
	size_t count;

	path = [path substringWithRange: of_range(1, [path length] - 1)];
	path = [path substringWithRange: of_range(1, path.length - 1)];
	components = [[[path
	    componentsSeparatedByString: @"/"] mutableCopy] autorelease];
	count = [components count];
	count = components.count;

	for (size_t i = 0; i < count; i++) {
		OFString *component = [components objectAtIndex: i];

		if ([component isEqual: @"."]) {
			[components removeObjectAtIndex: i];
			count--;

			i--;
			continue;
		}

		if ([component isEqual: @".."])
			[components replaceObjectAtIndex: i
					      withObject: @"/"];
	}

	return [OFString pathWithComponents: components];
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII)
	return [path substringWithRange: of_range(1, [path length] - 1)];
	return [path substringWithRange: of_range(1, path.length - 1)];
# else
	return path;
# endif
}
#endif

@interface OFCharacterSet_invertedSetWithPercent: OFCharacterSet
469
470
471
472
473
474
475
476

477
478
479

480
481
482
483
484
485
486
469
470
471
472
473
474
475

476
477
478

479
480
481
482
483
484
485
486







-
+


-
+








	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		char *tmp, *tmp2;

		if ((UTF8String2 = of_strdup([string UTF8String])) == NULL)
		if ((UTF8String2 = of_strdup(string.UTF8String)) == NULL)
			@throw [OFOutOfMemoryException
			     exceptionWithRequestedSize:
			     [string UTF8StringLength]];
			     string.UTF8StringLength];

		UTF8String = UTF8String2;

		if ((tmp = strchr(UTF8String, ':')) == NULL)
			@throw [OFInvalidFormatException exception];

		if (strncmp(tmp, "://", 3) != 0)
538
539
540
541
542
543
544
545

546
547
548
549

550
551
552
553
554
555
556
538
539
540
541
542
543
544

545
546
547
548

549
550
551
552
553
554
555
556







-
+



-
+







			tmp2++;

			_URLEncodedHost = [[OFString alloc]
			    initWithUTF8String: UTF8String];

			portString = [OFString stringWithUTF8String: tmp2];

			if ([portString decimalValue] > 65535)
			if (portString.decimalValue > 65535)
				@throw [OFInvalidFormatException exception];

			_port = [[OFNumber alloc] initWithUInt16:
			    (uint16_t)[portString decimalValue]];
			    (uint16_t)portString.decimalValue];
		} else
			_URLEncodedHost = [[OFString alloc]
			    initWithUTF8String: UTF8String];

		of_url_verify_escaped(_URLEncodedHost,
		    [OFCharacterSet URLHostAllowedCharacterSet]);

614
615
616
617
618
619
620
621

622
623
624

625
626
627
628
629
630
631
614
615
616
617
618
619
620

621
622
623

624
625
626
627
628
629
630
631







-
+


-
+








		_URLEncodedScheme = [URL->_URLEncodedScheme copy];
		_URLEncodedHost = [URL->_URLEncodedHost copy];
		_port = [URL->_port copy];
		_URLEncodedUser = [URL->_URLEncodedUser copy];
		_URLEncodedPassword = [URL->_URLEncodedPassword copy];

		if ((UTF8String2 = of_strdup([string UTF8String])) == NULL)
		if ((UTF8String2 = of_strdup(string.UTF8String)) == NULL)
			@throw [OFOutOfMemoryException
			     exceptionWithRequestedSize:
			     [string UTF8StringLength]];
			     string.UTF8StringLength];

		UTF8String = UTF8String2;

		if ((tmp = strchr(UTF8String, '#')) != NULL) {
			*tmp = '\0';
			_URLEncodedFragment = [[OFString alloc]
			    initWithUTF8String: tmp + 1];
665
666
667
668
669
670
671
672

673
674
675
676
677
678
679
665
666
667
668
669
670
671

672
673
674
675
676
677
678
679







-
+







					  options: OF_STRING_SEARCH_BACKWARDS];

				if (range.location == OF_NOT_FOUND)
					@throw [OFInvalidFormatException
					    exception];

				range.location++;
				range.length = [path length] - range.location;
				range.length = path.length - range.location;

				[path replaceCharactersInRange: range
						    withString: relativePath];
				[path makeImmutable];

				_URLEncodedPath = [path copy];
			}
730
731
732
733
734
735
736
737
738
739



740
741
742
743

744
745
746
747
748
749
750
730
731
732
733
734
735
736



737
738
739
740
741
742

743
744
745
746
747
748
749
750







-
-
-
+
+
+



-
+







			isDirectory: (bool)isDirectory
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![path isAbsolutePath]) {
			OFString *currentDirectoryPath = [[OFFileManager
			    defaultManager] currentDirectoryPath];
		if (!path.absolutePath) {
			OFString *currentDirectoryPath = [OFFileManager
			    defaultManager].currentDirectoryPath;

			path = [currentDirectoryPath
			    stringByAppendingPathComponent: path];
			path = [path stringByStandardizingPath];
			path = path.stringByStandardizingPath;
		}

		path = pathToURLPath(path);

		if (isDirectory && ![path hasSuffix: @"/"])
			path = [path stringByAppendingString: @"/"];

765
766
767
768
769
770
771
772
773


774
775
776

777
778
779
780
781
782
783
765
766
767
768
769
770
771


772
773
774
775

776
777
778
779
780
781
782
783







-
-
+
+


-
+








- (instancetype)initWithSerialization: (OFXMLElement *)element
{
	void *pool = objc_autoreleasePoolPush();
	OFString *stringValue;

	@try {
		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		stringValue = [element stringValue];
		stringValue = element.stringValue;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	self = [self initWithString: stringValue];

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







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








-
+









-
+














-
+









-
+









-
+









-
+





-
+

















-
+
-

-
-
+
+



















-
+









-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_URLEncodedScheme hash]);
	OF_HASH_ADD_HASH(hash, [_URLEncodedHost hash]);
	OF_HASH_ADD_HASH(hash, [_port hash]);
	OF_HASH_ADD_HASH(hash, [_URLEncodedUser hash]);
	OF_HASH_ADD_HASH(hash, [_URLEncodedPassword hash]);
	OF_HASH_ADD_HASH(hash, [_URLEncodedPath hash]);
	OF_HASH_ADD_HASH(hash, [_URLEncodedQuery hash]);
	OF_HASH_ADD_HASH(hash, [_URLEncodedFragment hash]);
	OF_HASH_ADD_HASH(hash, _URLEncodedScheme.hash);
	OF_HASH_ADD_HASH(hash, _URLEncodedHost.hash);
	OF_HASH_ADD_HASH(hash, _port.hash);
	OF_HASH_ADD_HASH(hash, _URLEncodedUser.hash);
	OF_HASH_ADD_HASH(hash, _URLEncodedPassword.hash);
	OF_HASH_ADD_HASH(hash, _URLEncodedPath.hash);
	OF_HASH_ADD_HASH(hash, _URLEncodedQuery.hash);
	OF_HASH_ADD_HASH(hash, _URLEncodedFragment.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)scheme
{
	return [_URLEncodedScheme stringByURLDecoding];
	return _URLEncodedScheme.stringByURLDecoding;
}

- (OFString *)URLEncodedScheme
{
	return _URLEncodedScheme;
}

- (OFString *)host
{
	return [_URLEncodedHost stringByURLDecoding];
	return _URLEncodedHost.stringByURLDecoding;
}

- (OFString *)URLEncodedHost
{
	return _URLEncodedHost;
}

- (OFNumber *)port
{
	return _port;
}

- (OFString *)user
{
	return [_URLEncodedUser stringByURLDecoding];
	return _URLEncodedUser.stringByURLDecoding;
}

- (OFString *)URLEncodedUser
{
	return _URLEncodedUser;
}

- (OFString *)password
{
	return [_URLEncodedPassword stringByURLDecoding];
	return _URLEncodedPassword.stringByURLDecoding;
}

- (OFString *)URLEncodedPassword
{
	return _URLEncodedPassword;
}

- (OFString *)path
{
	return [_URLEncodedPath stringByURLDecoding];
	return _URLEncodedPath.stringByURLDecoding;
}

- (OFString *)URLEncodedPath
{
	return _URLEncodedPath;
}

- (OFArray *)pathComponents
{
	return [[self path] componentsSeparatedByString: @"/"];
	return [self.path componentsSeparatedByString: @"/"];
}

- (OFString *)lastPathComponent
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = [self path];
	OFString *path = self.path;
	const char *UTF8String, *lastComponent;
	size_t length;
	OFString *ret;

	if (path == nil) {
		objc_autoreleasePoolPop(pool);

		return nil;
	}

	if ([path isEqual: @"/"]) {
		objc_autoreleasePoolPop(pool);

		return @"";
	}

	if ([path hasSuffix: @"/"])
		path = [path substringWithRange:
		path = [path substringWithRange: of_range(0, path.length - 1)];
		    of_range(0, [path length] - 1)];

	UTF8String = lastComponent = [path UTF8String];
	length = [path UTF8StringLength];
	UTF8String = lastComponent = path.UTF8String;
	length = path.UTF8StringLength;

	for (size_t i = 1; i <= length; i++) {
		if (UTF8String[length - i] == '/') {
			lastComponent = UTF8String + (length - i) + 1;
			break;
		}
	}

	ret = [[OFString alloc]
	    initWithUTF8String: lastComponent
			length: length - (lastComponent - UTF8String)];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}

- (OFString *)query
{
	return [_URLEncodedQuery stringByURLDecoding];
	return _URLEncodedQuery.stringByURLDecoding;
}

- (OFString *)URLEncodedQuery
{
	return _URLEncodedQuery;
}

- (OFString *)fragment
{
	return [_URLEncodedFragment stringByURLDecoding];
	return _URLEncodedFragment.stringByURLDecoding;
}

- (OFString *)URLEncodedFragment
{
	return _URLEncodedFragment;
}

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







-
+


-
+
-


















-
+




-
+








-
+











-
+



-
-
+
+


















-
-
+
+








	if (![_URLEncodedScheme isEqual: @"file"])
		@throw [OFInvalidArgumentException exception];

	if (![_URLEncodedPath hasPrefix: @"/"])
		@throw [OFInvalidFormatException exception];

	path = [self path];
	path = self.path;

	if ([path hasSuffix: @"/"])
		path = [path substringWithRange:
		path = [path substringWithRange: of_range(0, path.length - 1)];
		    of_range(0, [path length] - 1)];

	path = URLPathToPath(path);

	[path retain];

	objc_autoreleasePoolPop(pool);

	return [path autorelease];
}
#endif

- (OFMutableURL *)of_URLByAppendingPathComponent: (OFString *)component
{
	OFMutableURL *ret = [[self mutableCopy] autorelease];
	void *pool;
	OFMutableString *URLEncodedPath;

	if ([component hasPrefix: @"/"]) {
		[ret setPath: component];
		ret.path = component;
		return ret;
	}

	pool = objc_autoreleasePoolPush();
	URLEncodedPath = [[[self URLEncodedPath] mutableCopy] autorelease];
	URLEncodedPath = [[self.URLEncodedPath mutableCopy] autorelease];

	if (![URLEncodedPath hasSuffix: @"/"])
		[URLEncodedPath appendString: @"/"];

	[URLEncodedPath appendString:
	    [component stringByURLEncodingWithAllowedCharacters:
	    [OFCharacterSet URLPathAllowedCharacterSet]]];

	[ret setURLEncodedPath: URLEncodedPath];
	ret.URLEncodedPath = URLEncodedPath;

	objc_autoreleasePoolPop(pool);

	return ret;
}

- (OFURL *)URLByAppendingPathComponent: (OFString *)component
{
	OFMutableURL *ret = [self of_URLByAppendingPathComponent: component];

#ifdef OF_HAVE_FILES
	if ([[ret scheme] isEqual: @"file"]) {
	if ([ret.scheme isEqual: @"file"]) {
		void *pool = objc_autoreleasePoolPush();

		if ([[OFFileManager defaultManager] directoryExistsAtURL: ret])
			[ret setURLEncodedPath: [[ret URLEncodedPath]
			    stringByAppendingString: @"/"]];
			ret.URLEncodedPath =
			    [ret.URLEncodedPath stringByAppendingString: @"/"];

		objc_autoreleasePoolPop(pool);
	}
#endif

	[ret makeImmutable];

	return ret;
}

- (OFURL *)URLByAppendingPathComponent: (OFString *)component
			   isDirectory: (bool)isDirectory
{
	OFMutableURL *ret = [self of_URLByAppendingPathComponent: component];

	if (isDirectory) {
		void *pool = objc_autoreleasePoolPush();

		[ret setURLEncodedPath:
		    [[ret URLEncodedPath] stringByAppendingString: @"/"]];
		ret.URLEncodedPath =
		    [ret.URLEncodedPath stringByAppendingString: @"/"];

		objc_autoreleasePoolPop(pool);
	}

	[ret makeImmutable];

	return ret;
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
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







-
+







-
+

-
+









	return URL;
}

- (OFString *)description
{
	return [OFString stringWithFormat: @"<%@: %@>",
					   [self class], [self string]];
					   self.class, self.string];
}

- (OFXMLElement *)XMLElementBySerializing
{
	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *element;

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

	[element retain];

	objc_autoreleasePoolPop(pool);

	return [element autorelease];
}
@end

Modified src/OFURLHandler.m from [e9b99833f4] to [097dcd213e].

139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153







-
+








+ (OF_KINDOF(OFURLHandler *))handlerForURL: (OFURL *)URL
{
#ifdef OF_HAVE_THREADS
	[mutex lock];
	@try {
#endif
		return [handlers objectForKey: [URL scheme]];
		return [handlers objectForKey: URL.scheme];
#ifdef OF_HAVE_THREADS
	} @finally {
		[mutex unlock];
	}
#endif
}

Modified src/OFURLHandler_file.m from [111f6cb51f] to [701f79185c].

134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148







-
+







}
#endif

static int
of_stat(OFString *path, of_stat_t *buffer)
{
#if defined(OF_WINDOWS)
	return _wstat64([path UTF16String], buffer);
	return _wstat64(path.UTF16String, buffer);
#elif defined(OF_AMIGAOS)
	BPTR lock;
# ifdef OF_AMIGAOS4
	struct ExamineData *ed;
# else
	struct FileInfoBlock fib;
# endif
340
341
342
343
344
345
346
347

348
349
350
351
352
353
354
340
341
342
343
344
345
346

347
348
349
350
351
352
353
354







-
+







}

static void
setSymbolicLinkDestinationAttribute(of_mutable_file_attributes_t attributes,
    of_stat_t *s, OFURL *URL)
{
#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS
	OFString *path = [URL fileSystemRepresentation];
	OFString *path = URL.fileSystemRepresentation;

# ifndef OF_WINDOWS
	if (S_ISLNK(s->st_mode)) {
		of_string_encoding_t encoding = [OFLocale encoding];
		char destinationC[PATH_MAX];
		ssize_t length;
		OFString *destination;
370
371
372
373
374
375
376
377

378
379
380
381
382
383

384
385
386
387
388
389
390
370
371
372
373
374
375
376

377
378
379
380
381
382

383
384
385
386
387
388
389
390







-
+





-
+







		[attributes setObject: destination
			       forKey: key];
	}
# else
	WIN32_FIND_DATAW data;

	if (func_CreateSymbolicLinkW != NULL &&
	    FindFirstFileW([path UTF16String], &data) &&
	    FindFirstFileW(path.UTF16String, &data) &&
	    (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
	    data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
		HANDLE handle;
		OFString *destination;

		if ((handle = CreateFileW([path UTF16String], 0,
		if ((handle = CreateFileW(path.UTF16String, 0,
		    (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING,
		    FILE_FLAG_OPEN_REPARSE_POINT, NULL)) ==
		    INVALID_HANDLE_VALUE)
			@throw [OFRetrieveItemAttributesFailedException
			    exceptionWithURL: URL
				       errNo: 0];

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







-
+




















-
+







}

- (OFStream *)openItemAtURL: (OFURL *)URL
		       mode: (OFString *)mode
{
	void *pool = objc_autoreleasePoolPush();
	OFFile *file = [[OFFile alloc]
	    initWithPath: [URL fileSystemRepresentation]
	    initWithPath: URL.fileSystemRepresentation
		    mode: mode];

	objc_autoreleasePoolPop(pool);

	return [file autorelease];
}

- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL
{
	of_mutable_file_attributes_t ret = [OFMutableDictionary dictionary];
	void *pool = objc_autoreleasePoolPush();
	OFString *path;
	of_stat_t s;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	path = [URL fileSystemRepresentation];
	path = URL.fileSystemRepresentation;

	if (of_lstat(path, &s) == -1)
		@throw [OFRetrieveItemAttributesFailedException
		    exceptionWithURL: URL
			       errNo: errno];

	if (s.st_size < 0)
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
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







-
-
+
+




-
+


















-
+







}

- (void)of_setPOSIXPermissions: (OFNumber *)permissions
		   ofItemAtURL: (OFURL *)URL
		    attributes: (of_file_attributes_t)attributes
{
#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
	uint16_t mode = [permissions uInt16Value] & 0777;
	OFString *path = [URL fileSystemRepresentation];
	uint16_t mode = permissions.uInt16Value & 0777;
	OFString *path = URL.fileSystemRepresentation;

# ifndef OF_WINDOWS
	if (chmod([path cStringWithEncoding: [OFLocale encoding]], mode) != 0)
# else
	if (_wchmod([path UTF16String], mode) != 0)
	if (_wchmod(path.UTF16String, mode) != 0)
# endif
		@throw [OFSetItemAttributesFailedException
		    exceptionWithURL: URL
			  attributes: attributes
		     failedAttribute: of_file_attribute_key_posix_permissions
			       errNo: errno];
#else
	OF_UNRECOGNIZED_SELECTOR
#endif
}

- (void)of_setOwner: (OFString *)owner
	   andGroup: (OFString *)group
	ofItemAtURL: (OFURL *)URL
       attributeKey: (of_file_attribute_key_t)attributeKey
	 attributes: (of_file_attributes_t)attributes
{
#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER
	OFString *path = [URL fileSystemRepresentation];
	OFString *path = URL.fileSystemRepresentation;
	uid_t uid = -1;
	gid_t gid = -1;
	of_string_encoding_t encoding;

	if (owner == nil && group == nil)
		@throw [OFInvalidArgumentException exception];

642
643
644
645
646
647
648
649

650
651
652
653
654
655
656
642
643
644
645
646
647
648

649
650
651
652
653
654
655
656







-
+







	OFEnumerator *objectEnumerator;
	of_file_attribute_key_t key;
	id object;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	keyEnumerator = [attributes keyEnumerator];
	objectEnumerator = [attributes objectEnumerator];

	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
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
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







-
+


-
+


















-
+


-
+

















-
+


-
+


-
+







	void *pool = objc_autoreleasePoolPush();
	of_stat_t s;
	bool ret;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	if (of_stat([URL fileSystemRepresentation], &s) == -1)
	if (of_stat(URL.fileSystemRepresentation, &s) == -1)
		return false;

	ret = S_ISREG(s.st_mode);

	objc_autoreleasePoolPop(pool);

	return ret;
}

- (bool)directoryExistsAtURL: (OFURL *)URL
{
	void *pool = objc_autoreleasePoolPush();
	of_stat_t s;
	bool ret;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	if (of_stat([URL fileSystemRepresentation], &s) == -1)
	if (of_stat(URL.fileSystemRepresentation, &s) == -1)
		return false;

	ret = S_ISDIR(s.st_mode);

	objc_autoreleasePoolPop(pool);

	return ret;
}

- (void)createDirectoryAtURL: (OFURL *)URL
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	path = [URL fileSystemRepresentation];
	path = URL.fileSystemRepresentation;

#if defined(OF_WINDOWS)
	if (_wmkdir([path UTF16String]) != 0)
	if (_wmkdir(path.UTF16String) != 0)
		@throw [OFCreateDirectoryFailedException
		    exceptionWithURL: URL
			       errNo: errno];
#elif defined(OF_AMIGAOS)
	BPTR lock;

	if ((lock = CreateDir(
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
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







-
+


-
+







-
+







	OFMutableArray *files = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	OFString *path;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	path = [URL fileSystemRepresentation];
	path = URL.fileSystemRepresentation;

#if defined(OF_WINDOWS)
	HANDLE handle;
	WIN32_FIND_DATAW fd;

	path = [path stringByAppendingString: @"\\*"];

	if ((handle = FindFirstFileW([path UTF16String],
	if ((handle = FindFirstFileW(path.UTF16String,
	    &fd)) == INVALID_HANDLE_VALUE) {
		int errNo = 0;

		if (GetLastError() == ERROR_FILE_NOT_FOUND)
			errNo = ENOENT;

		@throw [OFOpenItemFailedException exceptionWithURL: URL
1004
1005
1006
1007
1008
1009
1010
1011

1012
1013
1014

1015
1016
1017
1018
1019
1020
1021
1004
1005
1006
1007
1008
1009
1010

1011
1012
1013

1014
1015
1016
1017
1018
1019
1020
1021







-
+


-
+







	void *pool = objc_autoreleasePoolPush();
	OFString *path;
	of_stat_t s;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	path = [URL fileSystemRepresentation];
	path = URL.fileSystemRepresentation;

	if (of_lstat(path, &s) != 0)
		@throw [OFRemoveItemFailedException exceptionWithURL: URL
							       errNo: errno];

	if (S_ISDIR(s.st_mode)) {
		OFArray *contents;
1047
1048
1049
1050
1051
1052
1053
1054

1055
1056
1057
1058
1059
1060
1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
1047
1048
1049
1050
1051
1052
1053

1054
1055
1056
1057
1058
1059
1060
1061
1062
1063

1064
1065
1066
1067
1068
1069
1070
1071







-
+









-
+







			objc_autoreleasePoolPop(pool2);
		}

#ifndef OF_AMIGAOS
# ifndef OF_WINDOWS
		if (rmdir([path cStringWithEncoding: [OFLocale encoding]]) != 0)
# else
		if (_wrmdir([path UTF16String]) != 0)
		if (_wrmdir(path.UTF16String) != 0)
# endif
			@throw [OFRemoveItemFailedException
				exceptionWithURL: URL
					   errNo: errno];
	} else {
# ifndef OF_WINDOWS
		if (unlink([path cStringWithEncoding:
		    [OFLocale encoding]]) != 0)
# else
		if (_wunlink([path UTF16String]) != 0)
		if (_wunlink(path.UTF16String) != 0)
# endif
			@throw [OFRemoveItemFailedException
			    exceptionWithURL: URL
				       errNo: errno];
#endif
	}

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
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189


1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202


1203
1204
1205
1206
1207
1208
1209
1210

1211
1212

1213
1214
1215
1216
1217
1218
1219
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
1178
1179
1180
1181
1182
1183
1184
1185
1186


1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199


1200
1201
1202
1203
1204
1205
1206
1207
1208

1209
1210

1211
1212
1213
1214
1215
1216
1217
1218







-
-
+
+


-
-
+
+











-
-
+
+




















-
+


-
+















-
+
-















-
-
+
+











-
-
+
+







-
+

-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFString *sourcePath, *destinationPath;

	if (source == nil || destination == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[source scheme] isEqual: _scheme] ||
	    ![[destination scheme] isEqual: _scheme])
	if (![source.scheme isEqual: _scheme] ||
	    ![destination.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	sourcePath = [source fileSystemRepresentation];
	destinationPath = [destination fileSystemRepresentation];
	sourcePath = source.fileSystemRepresentation;
	destinationPath = destination.fileSystemRepresentation;

# ifndef OF_WINDOWS
	of_string_encoding_t encoding = [OFLocale encoding];

	if (link([sourcePath cStringWithEncoding: encoding],
	    [destinationPath cStringWithEncoding: encoding]) != 0)
		@throw [OFLinkFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: errno];
# else
	if (!CreateHardLinkW([destinationPath UTF16String],
	    [sourcePath UTF16String], NULL))
	if (!CreateHardLinkW(destinationPath.UTF16String,
	    sourcePath.UTF16String, NULL))
		@throw [OFLinkFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: 0];
# endif

	objc_autoreleasePoolPop(pool);
}
#endif

#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS
- (void)createSymbolicLinkAtURL: (OFURL *)URL
	    withDestinationPath: (OFString *)target
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path;

	if (URL == nil || target == nil)
		@throw [OFInvalidArgumentException exception];

	if (![[URL scheme] isEqual: _scheme])
	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	path = [URL fileSystemRepresentation];
	path = URL.fileSystemRepresentation;

# ifndef OF_WINDOWS
	of_string_encoding_t encoding = [OFLocale encoding];

	if (symlink([target cStringWithEncoding: encoding],
	    [path cStringWithEncoding: encoding]) != 0)
		@throw [OFCreateSymbolicLinkFailedException
		    exceptionWithURL: URL
			      target: target
			       errNo: errno];
# else
	if (func_CreateSymbolicLinkW == NULL)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	if (!func_CreateSymbolicLinkW([path UTF16String],
	if (!func_CreateSymbolicLinkW(path.UTF16String, target.UTF16String, 0))
	    [target UTF16String], 0))
		@throw [OFCreateSymbolicLinkFailedException
		    exceptionWithURL: URL
			      target: target
			       errNo: 0];
# endif

	objc_autoreleasePoolPop(pool);
}
#endif

- (bool)moveItemAtURL: (OFURL *)source
		toURL: (OFURL *)destination
{
	void *pool;

	if (![[source scheme] isEqual: _scheme] ||
	    ![[destination scheme] isEqual: _scheme])
	if (![source.scheme isEqual: _scheme] ||
	    ![destination.scheme isEqual: _scheme])
		return false;

	if ([self fileExistsAtURL: destination])
		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: EEXIST];

	pool = objc_autoreleasePoolPush();

#if defined(OF_WINDOWS)
	if (_wrename([[source fileSystemRepresentation] UTF16String],
	    [[destination fileSystemRepresentation] UTF16String]) != 0)
	if (_wrename(source.fileSystemRepresentation.UTF16String,
	    destination.fileSystemRepresentation.UTF16String) != 0)
		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: errno];
#elif defined(OF_AMIGAOS)
	of_string_encoding_t encoding = [OFLocale encoding];

	if (!Rename([[source fileSystemRepresentation]
	if (!Rename([source.fileSystemRepresentation
	    cStringWithEncoding: encoding],
	    [[destination fileSystemRepresentation]
	    [destination.fileSystemRepresentation
	    cStringWithEncoding: encoding])) {
		int errNo;

		switch (IoErr()) {
		case ERROR_RENAME_ACROSS_DEVICES:
			errNo = EXDEV;
			break;
1239
1240
1241
1242
1243
1244
1245
1246

1247
1248

1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1238
1239
1240
1241
1242
1243
1244

1245
1246

1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259







-
+

-
+












		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: errNo];
	}
#else
	of_string_encoding_t encoding = [OFLocale encoding];

	if (rename([[source fileSystemRepresentation]
	if (rename([source.fileSystemRepresentation
	    cStringWithEncoding: encoding],
	    [[destination fileSystemRepresentation]
	    [destination.fileSystemRepresentation
	    cStringWithEncoding: encoding]) != 0)
		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: errno];
#endif

	objc_autoreleasePoolPop(pool);

	return true;
}
@end

Modified src/OFValue.m from [3dfa97e178] to [a898bac105].

168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
168
169
170
171
172
173
174

175
176
177
178
179
180
181
182







-
+







	const char *objCType;
	size_t size;
	void *value, *otherValue;

	if (![object isKindOfClass: [OFValue class]])
		return false;

	objCType = [self objCType];
	objCType = self.objCType;

	if (strcmp([object objCType], objCType) != 0)
		return false;

	size = of_sizeof_type_encoding(objCType);

	if ((value = malloc(size)) == NULL)
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
200
201
202
203
204
205
206

207
208
209
210
211
212
213
214







-
+







		free(value);
		free(otherValue);
	}
}

- (uint32_t)hash
{
	size_t size = of_sizeof_type_encoding([self objCType]);
	size_t size = of_sizeof_type_encoding(self.objCType);
	unsigned char *value;
	uint32_t hash;

	if ((value = malloc(size)) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: size];

305
306
307
308
309
310
311
312

313
314
315
316
317
318
319
305
306
307
308
309
310
311

312
313
314
315
316
317
318
319







-
+







	return ret;
}

- (OFString *)description
{
	OFMutableString *ret =
	    [OFMutableString stringWithString: @"<OFValue: "];
	size_t size = of_sizeof_type_encoding([self objCType]);
	size_t size = of_sizeof_type_encoding(self.objCType);
	unsigned char *value;

	if ((value = malloc(size)) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: size];

	@try {

Modified src/OFWindowsRegistryKey.m from [393e6cb19f] to [e2b1c254bf].

103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
103
104
105
106
107
108
109

110
111
112
113
114
115
116
117







-
+







				   options: (DWORD)options
		   securityAndAccessRights: (REGSAM)securityAndAccessRights
{
	void *pool = objc_autoreleasePoolPush();
	LSTATUS status;
	HKEY subKey;

	if ((status = RegOpenKeyExW(_hKey, [path UTF16String], options,
	if ((status = RegOpenKeyExW(_hKey, path.UTF16String, options,
	    securityAndAccessRights, &subKey)) != ERROR_SUCCESS) {
		if (status == ERROR_FILE_NOT_FOUND) {
			objc_autoreleasePoolPop(pool);
			return nil;
		}

		@throw [OFOpenWindowsRegistryKeyFailedException
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160







-
+







	 securityAttributes: (LPSECURITY_ATTRIBUTES)securityAttributes
		disposition: (LPDWORD)disposition
{
	void *pool = objc_autoreleasePoolPush();
	LSTATUS status;
	HKEY subKey;

	if ((status = RegCreateKeyExW(_hKey, [path UTF16String], 0,
	if ((status = RegCreateKeyExW(_hKey, path.UTF16String, 0,
	    NULL, options, securityAndAccessRights, securityAttributes,
	    &subKey, NULL)) != ERROR_SUCCESS)
		@throw [OFCreateWindowsRegistryKeyFailedException
		    exceptionWithRegistryKey: self
					path: path
				     options: options
		     securityAndAccessRights: securityAndAccessRights
176
177
178
179
180
181
182
183
184


185
186
187
188
189
190
191
176
177
178
179
180
181
182


183
184
185
186
187
188
189
190
191







-
-
+
+







	void *pool = objc_autoreleasePoolPush();
	char stackBuffer[256], *buffer = stackBuffer;
	DWORD length = sizeof(stackBuffer);
	OFMutableData *ret = nil;
	LSTATUS status;

	for (;;) {
		status = RegGetValueW(_hKey, [subkeyPath UTF16String],
		    [value UTF16String], flags, type, buffer, &length);
		status = RegGetValueW(_hKey, subkeyPath.UTF16String,
		    value.UTF16String, flags, type, buffer, &length);

		switch (status) {
		case ERROR_SUCCESS:
			if (buffer == stackBuffer) {
				objc_autoreleasePoolPop(pool);

				return [OFData dataWithItems: buffer
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234
235
236


237
238
239
240
241
242
243
204
205
206
207
208
209
210

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

229
230
231
232
233
234


235
236
237
238
239
240
241
242
243







-
+

















-
+





-
-
+
+







			return nil;
		case ERROR_MORE_DATA:
			objc_autoreleasePoolPop(pool);
			pool = objc_autoreleasePoolPush();

			ret = [OFMutableData dataWithCapacity: length];
			[ret increaseCountBy: length];
			buffer = [ret items];
			buffer = ret.items;

			continue;
		default:
			@throw [OFGetWindowsRegistryValueFailedException
			    exceptionWithRegistryKey: self
					       value: value
					  subkeyPath: subkeyPath
					       flags: flags
					      status: status];
		}
	}
}

- (void)setData: (OFData *)data
       forValue: (OFString *)value
	   type: (DWORD)type
{
	size_t length = [data count] * [data itemSize];
	size_t length = data.count * data.itemSize;
	LSTATUS status;

	if (length > UINT32_MAX)
		@throw [OFOutOfRangeException exception];

	if ((status = RegSetValueExW(_hKey, [value UTF16String], 0, type,
	    [data items], (DWORD)length)) != ERROR_SUCCESS)
	if ((status = RegSetValueExW(_hKey, value.UTF16String, 0, type,
	    data.items, (DWORD)length)) != ERROR_SUCCESS)
		@throw [OFSetWindowsRegistryValueFailedException
		    exceptionWithRegistryKey: self
				       value: value
					data: data
					type: type
				      status: status];
}
264
265
266
267
268
269
270
271
272


273
274

275
276
277
278
279
280
281
264
265
266
267
268
269
270


271
272
273

274
275
276
277
278
279
280
281







-
-
+
+

-
+







	const of_char16_t *UTF16String;
	size_t length;
	OFString *ret;

	if (data == nil)
		return nil;

	UTF16String = [data items];
	length = [data count];
	UTF16String = data.items;
	length = data.count;

	if ([data itemSize] != 1 || length % 2 == 1)
	if (data.itemSize != 1 || length % 2 == 1)
		@throw [OFInvalidFormatException exception];

	length /= 2;

	/*
	 * REG_SZ and REG_EXPAND_SZ contain a \0, but can contain data after it
	 * that should be ignored.
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
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







-
+

-
+












-
+














-
+









- (void)setString: (OFString *)string
	 forValue: (OFString *)value
	     type: (DWORD)type
{
	void *pool = objc_autoreleasePoolPush();
	OFData *data;

	data = [OFData dataWithItems: [string UTF16String]
	data = [OFData dataWithItems: string.UTF16String
			    itemSize: sizeof(of_char16_t)
			       count: [string UTF16StringLength] + 1];
			       count: string.UTF16StringLength + 1];
	[self setData: data
	     forValue: value
		 type: type];

	objc_autoreleasePoolPop(pool);
}

- (void)deleteValue: (OFString *)value
{
	void *pool = objc_autoreleasePoolPush();
	LSTATUS status;

	if ((status = RegDeleteValueW(_hKey, [value UTF16String])) !=
	if ((status = RegDeleteValueW(_hKey, value.UTF16String)) !=
	    ERROR_SUCCESS)
		@throw [OFDeleteWindowsRegistryValueFailedException
		    exceptionWithRegistryKey: self
				       value: value
				      status: status];

	objc_autoreleasePoolPop(pool);
}

- (void)deleteSubkeyAtPath: (OFString *)subkeyPath
{
	void *pool = objc_autoreleasePoolPush();
	LSTATUS status;

	if ((status = RegDeleteKeyW(_hKey, [subkeyPath UTF16String])) !=
	if ((status = RegDeleteKeyW(_hKey, subkeyPath.UTF16String)) !=
	    ERROR_SUCCESS)
		@throw [OFDeleteWindowsRegistryKeyFailedException
		    exceptionWithRegistryKey: self
				  subkeyPath: subkeyPath
				      status: status];

	objc_autoreleasePoolPop(pool);
}
@end

Modified src/OFXMLAttribute.m from [bc86f5c2b5] to [87a544a7c5].

73
74
75
76
77
78
79
80
81


82
83
84

85
86
87
88
89




90
91
92
93
94
95
96
73
74
75
76
77
78
79


80
81
82
83

84





85
86
87
88
89
90
91
92
93
94
95







-
-
+
+


-
+
-
-
-
-
-
+
+
+
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		_name = [[[element attributeForName: @"name"]
		_name = [[element attributeForName: @"name"].stringValue copy];
		    stringValue] copy];
		_namespace = [[[element attributeForName: @"namespace"]
		    stringValue] copy];
		_stringValue = [[[element attributeForName: @"stringValue"]
		    stringValue] copy];
		_namespace = [[element attributeForName: @"namespace"]
		    .stringValue copy];
		_stringValue = [[element attributeForName: @"stringValue"]
		    .stringValue copy];

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

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







-
-
-
+
+
+











-
+








- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, [_namespace hash]);
	OF_HASH_ADD_HASH(hash, [_stringValue hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD_HASH(hash, _namespace.hash);
	OF_HASH_ADD_HASH(hash, _stringValue.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFXMLElement *)XMLElementBySerializing
{
	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *element;

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

	[element addAttributeWithName: @"name"
			  stringValue: _name];

	if (_namespace != nil)
		[element addAttributeWithName: @"namespace"

Modified src/OFXMLCDATA.m from [daf8eb8593] to [37fee43ed7].

47
48
49
50
51
52
53
54
55


56
57
58

59
60
61
62
63
64
65
47
48
49
50
51
52
53


54
55
56
57

58
59
60
61
62
63
64
65







-
-
+
+


-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		_CDATA = [[element stringValue] copy];
		_CDATA = [element.stringValue copy];

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

86
87
88
89
90
91
92
93

94
95
96
97
98
99
100
86
87
88
89
90
91
92

93
94
95
96
97
98
99
100







-
+







	CDATA = object;

	return ([CDATA->_CDATA isEqual: _CDATA]);
}

- (uint32_t)hash
{
	return [_CDATA hash];
	return _CDATA.hash;
}

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

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







-
+





-
+




-
+





-
+






	[ret retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

- (OFString *)XMLStringWithIndentation: (unsigned int)indentation
{
	return [self XMLString];
	return self.XMLString;
}

- (OFString *)XMLStringWithIndentation: (unsigned int)indentation
				level: (unsigned int)level
{
	return [self XMLString];
	return self.XMLString;
}

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

- (OFXMLElement *)XMLElementBySerializing
{
	OFXMLElement *element =
	    [OFXMLElement elementWithName: [self className]
	    [OFXMLElement elementWithName: self.className
				namespace: OF_SERIALIZATION_NS];
	[element addChild: self];

	return element;
}
@end

Modified src/OFXMLCharacters.m from [7f78add46a] to [0b6f50536f].

47
48
49
50
51
52
53
54
55


56
57
58

59
60
61
62
63
64
65
47
48
49
50
51
52
53


54
55
56
57

58
59
60
61
62
63
64
65







-
-
+
+


-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		_characters = [[element stringValue] copy];
		_characters = [element.stringValue copy];

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

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







-
+
















-
+




-
+





-
+




-
+




-
+




	characters = object;

	return ([characters->_characters isEqual: _characters]);
}

- (uint32_t)hash
{
	return [_characters hash];
	return _characters.hash;
}

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

- (void)setStringValue: (OFString *)stringValue
{
	OFString *old = _characters;
	_characters = [stringValue copy];
	[old release];
}

- (OFString *)XMLString
{
	return [_characters stringByXMLEscaping];
	return _characters.stringByXMLEscaping;
}

- (OFString *)XMLStringWithIndentation: (unsigned int)indentation
{
	return [_characters stringByXMLEscaping];
	return _characters.stringByXMLEscaping;
}

- (OFString *)XMLStringWithIndentation: (unsigned int)indentation
				 level: (unsigned int)level
{
	return [_characters stringByXMLEscaping];
	return _characters.stringByXMLEscaping;
}

- (OFString *)description
{
	return [_characters stringByXMLEscaping];
	return _characters.stringByXMLEscaping;
}

- (OFXMLElement *)XMLElementBySerializing
{
	return [OFXMLElement elementWithName: [self className]
	return [OFXMLElement elementWithName: self.className
				   namespace: OF_SERIALIZATION_NS
				 stringValue: _characters];
}
@end

Modified src/OFXMLComment.m from [cfcfb31543] to [7cb96fc45d].

49
50
51
52
53
54
55
56
57


58
59
60

61
62
63
64
65
66
67
49
50
51
52
53
54
55


56
57
58
59

60
61
62
63
64
65
66
67







-
-
+
+


-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		_comment = [[element stringValue] copy];
		_comment = [element.stringValue copy];

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

88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
88
89
90
91
92
93
94

95
96
97
98
99
100
101
102







-
+







	comment = object;

	return ([comment->_comment isEqual: _comment]);
}

- (uint32_t)hash
{
	return [_comment hash];
	return _comment.hash;
}

- (OFString *)stringValue
{
	return @"";
}

137
138
139
140
141
142
143
144

145
146
147
148
137
138
139
140
141
142
143

144
145
146
147
148







-
+




- (OFString *)description
{
	return [OFString stringWithFormat: @"<!--%@-->", _comment];
}

- (OFXMLElement *)XMLElementBySerializing
{
	return [OFXMLElement elementWithName: [self className]
	return [OFXMLElement elementWithName: self.className
				   namespace: OF_SERIALIZATION_NS
				 stringValue: _comment];
}
@end

Modified src/OFXMLElement.m from [7faef87abe] to [5fc577399d].

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







-
+


-
+



-
+



-
+







		    stringValue: (OFString *)stringValue
{
	return [[[self alloc] initWithName: name
			       stringValue: stringValue] autorelease];
}

+ (instancetype)elementWithName: (OFString *)name
		      namespace: (OFString *)ns
		      namespace: (OFString *)namespace
{
	return [[[self alloc] initWithName: name
				 namespace: ns] autorelease];
				 namespace: namespace] autorelease];
}

+ (instancetype)elementWithName: (OFString *)name
		      namespace: (OFString *)ns
		      namespace: (OFString *)namespace
		    stringValue: (OFString *)stringValue
{
	return [[[self alloc] initWithName: name
				 namespace: ns
				 namespace: namespace
			       stringValue: stringValue] autorelease];
}

+ (instancetype)elementWithElement: (OFXMLElement *)element
{
	return [[[self alloc] initWithElement: element] autorelease];
}
175
176
177
178
179
180
181
182

183
184
185
186
187
188
189
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189







-
+








		_namespaces = [[OFMutableDictionary alloc]
		    initWithKeysAndObjects:
		    @"http://www.w3.org/XML/1998/namespace", @"xml",
		    @"http://www.w3.org/2000/xmlns/", @"xmlns", nil];

		if (stringValue != nil)
			[self setStringValue: stringValue];
			self.stringValue = stringValue;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
226
227
228
229
230
231
232
233
234


235
236
237
238

239
240
241
242
243
244
245
226
227
228
229
230
231
232


233
234
235
236
237

238
239
240
241
242
243
244
245







-
-
+
+



-
+







	pool = objc_autoreleasePoolPush();

	parser = [OFXMLParser parser];
	builder = [OFXMLElementBuilder elementBuilder];
	delegate = [[[OFXMLElement_OFXMLElementBuilderDelegate alloc] init]
	    autorelease];

	[parser setDelegate: builder];
	[builder setDelegate: delegate];
	parser.delegate = builder;
	builder.delegate = delegate;

	[parser parseString: string];

	if (![parser hasFinishedParsing])
	if (!parser.hasFinishedParsing)
		@throw [OFMalformedXMLException exceptionWithParser: parser];

	self = [delegate->_element retain];

	objc_autoreleasePoolPop(pool);

	return self;
258
259
260
261
262
263
264
265
266


267
268
269
270

271
272
273
274
275
276
277
258
259
260
261
262
263
264


265
266
267
268
269

270
271
272
273
274
275
276
277







-
-
+
+



-
+







	pool = objc_autoreleasePoolPush();

	parser = [OFXMLParser parser];
	builder = [OFXMLElementBuilder elementBuilder];
	delegate = [[[OFXMLElement_OFXMLElementBuilderDelegate alloc] init]
	    autorelease];

	[parser setDelegate: builder];
	[builder setDelegate: delegate];
	parser.delegate = builder;
	builder.delegate = delegate;

	[parser parseFile: path];

	if (![parser hasFinishedParsing])
	if (!parser.hasFinishedParsing)
		@throw [OFMalformedXMLException exceptionWithParser: parser];

	self = [delegate->_element retain];

	objc_autoreleasePoolPop(pool);

	return self;
285
286
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
327
285
286
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







-
-
+
+


-
+
-
-
-
-
-
+
+
+
+

-
+


-
-
+
+


-
-
+
+


-
+

-
+

-
+

-
+







	@try {
		void *pool = objc_autoreleasePoolPush();
		OFXMLElement *attributesElement, *namespacesElement;
		OFXMLElement *childrenElement;
		OFEnumerator *keyEnumerator, *objectEnumerator;
		OFString *key, *object;

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		_name = [[[element attributeForName: @"name"]
		_name = [[element attributeForName: @"name"].stringValue copy];
		    stringValue] copy];
		_namespace = [[[element attributeForName: @"namespace"]
		    stringValue] copy];
		_defaultNamespace = [[[element attributeForName:
		    @"defaultNamespace"] stringValue] copy];
		_namespace = [[element attributeForName: @"namespace"]
		    .stringValue copy];
		_defaultNamespace = [[element attributeForName:
		    @"defaultNamespace"].stringValue copy];

		attributesElement = [[[element
		attributesElement = [[element
		    elementForName: @"attributes"
			 namespace: OF_SERIALIZATION_NS] elementsForNamespace:
		    OF_SERIALIZATION_NS] firstObject];
		namespacesElement = [[[element
		    OF_SERIALIZATION_NS].firstObject;
		namespacesElement = [[element
		    elementForName: @"namespaces"
			 namespace: OF_SERIALIZATION_NS] elementsForNamespace:
		    OF_SERIALIZATION_NS] firstObject];
		childrenElement = [[[element
		    OF_SERIALIZATION_NS].firstObject;
		childrenElement = [[element
		    elementForName: @"children"
			 namespace: OF_SERIALIZATION_NS] elementsForNamespace:
		    OF_SERIALIZATION_NS] firstObject];
		    OF_SERIALIZATION_NS].firstObject;

		_attributes = [[attributesElement objectByDeserializing]
		_attributes = [attributesElement.objectByDeserializing
		    mutableCopy];
		_namespaces = [[namespacesElement objectByDeserializing]
		_namespaces = [namespacesElement.objectByDeserializing
		    mutableCopy];
		_children = [[childrenElement objectByDeserializing]
		_children = [childrenElement.objectByDeserializing
		    mutableCopy];

		/* Sanity checks */
		if ((_attributes != nil && ![_attributes isKindOfClass:
		    [OFMutableArray class]]) || (_namespaces != nil &&
		    ![_namespaces isKindOfClass:
		    [OFMutableDictionary class]]) || (_children != nil &&
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
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







-
-
+
+








-
+







-
+







	return [[_children copy] autorelease];
}

- (void)setStringValue: (OFString *)stringValue
{
	void *pool = objc_autoreleasePoolPush();

	[self setChildren: [OFArray arrayWithObject:
	    [OFXMLCharacters charactersWithString: stringValue]]];
	self.children = [OFArray arrayWithObject:
	    [OFXMLCharacters charactersWithString: stringValue]];

	objc_autoreleasePoolPop(pool);
}

- (OFString *)stringValue
{
	OFMutableString *ret;

	if ([_children count] == 0)
	if (_children.count == 0)
		return @"";

	ret = [OFMutableString string];

	for (OFXMLNode *child in _children) {
		void *pool = objc_autoreleasePoolPush();

		[ret appendString: [child stringValue]];
		[ret appendString: child.stringValue];

		objc_autoreleasePoolPop(pool);
	}

	[ret makeImmutable];

	return ret;
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
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
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
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







-
+









-
+








-
-
+
+
-



-
-
+
+





-
+










-
-
-
+
+
+






-
+
-
-
+
-

-
+











-
-
+
+











-
-
-
+
+
+






-
-
+
+







		defaultNS = parent->_namespace;
	else if (parent != nil && parent->_defaultNamespace != nil)
		defaultNS = parent->_defaultNamespace;
	else
		defaultNS = _defaultNamespace;

	i = 0;
	length = [_name UTF8StringLength] + 3 + (level * indentation);
	length = _name.UTF8StringLength + 3 + (level * indentation);
	cString = [self allocMemoryWithSize: length];

	memset(cString + i, ' ', level * indentation);
	i += level * indentation;

	/* Start of tag */
	cString[i++] = '<';

	if (prefix != nil && ![_namespace isEqual: defaultNS]) {
		length += [prefix UTF8StringLength] + 1;
		length += prefix.UTF8StringLength + 1;
		@try {
			cString = [self resizeMemory: cString
						size: length];
		} @catch (id e) {
			[self freeMemory: cString];
			@throw e;
		}

		memcpy(cString + i, [prefix UTF8String],
		    [prefix UTF8StringLength]);
		memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength);
		i += prefix.UTF8StringLength;
		i += [prefix UTF8StringLength];
		cString[i++] = ':';
	}

	memcpy(cString + i, [_name UTF8String], [_name UTF8StringLength]);
	i += [_name UTF8StringLength];
	memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength);
	i += _name.UTF8StringLength;

	/* xmlns if necessary */
	if (prefix == nil && ((_namespace != nil &&
	    ![_namespace isEqual: defaultNS]) ||
	    (_namespace == nil && defaultNS != nil))) {
		length += [_namespace UTF8StringLength] + 9;
		length += _namespace.UTF8StringLength + 9;
		@try {
			cString = [self resizeMemory: cString
						size: length];
		} @catch (id e) {
			[self freeMemory: cString];
			@throw e;
		}

		memcpy(cString + i, " xmlns='", 8);
		i += 8;
		memcpy(cString + i, [_namespace UTF8String],
		    [_namespace UTF8StringLength]);
		i += [_namespace UTF8StringLength];
		memcpy(cString + i, _namespace.UTF8String,
		    _namespace.UTF8StringLength);
		i += _namespace.UTF8StringLength;
		cString[i++] = '\'';
	}

	/* Attributes */
	for (OFXMLAttribute *attribute in _attributes) {
		void *pool2 = objc_autoreleasePoolPush();
		const char *attributeNameCString =
		const char *attributeNameCString = attribute->_name.UTF8String;
		    [attribute->_name UTF8String];
		size_t attributeNameLength =
		size_t attributeNameLength = attribute->_name.UTF8StringLength;
		    [attribute->_name UTF8StringLength];
		OFString *attributePrefix = nil;
		OFString *tmp = [[attribute stringValue] stringByXMLEscaping];
		OFString *tmp = attribute.stringValue.stringByXMLEscaping;
		char delimiter = (attribute->_useDoubleQuotes ? '"' : '\'');

		if (attribute->_namespace != nil &&
		    (attributePrefix = [allNamespaces objectForKey:
		    attribute->_namespace]) == nil)
			@throw [OFUnboundNamespaceException
			    exceptionWithNamespace: [attribute namespace]
					   element: self];

		length += attributeNameLength +
		    (attributePrefix != nil ?
		    [attributePrefix UTF8StringLength] + 1 : 0) +
		    [tmp UTF8StringLength] + 4;
		    attributePrefix.UTF8StringLength + 1 : 0) +
		    tmp.UTF8StringLength + 4;

		@try {
			cString = [self resizeMemory: cString
						size: length];
		} @catch (id e) {
			[self freeMemory: cString];
			@throw e;
		}

		cString[i++] = ' ';
		if (attributePrefix != nil) {
			memcpy(cString + i, [attributePrefix UTF8String],
			    [attributePrefix UTF8StringLength]);
			i += [attributePrefix UTF8StringLength];
			memcpy(cString + i, attributePrefix.UTF8String,
			    attributePrefix.UTF8StringLength);
			i += attributePrefix.UTF8StringLength;
			cString[i++] = ':';
		}
		memcpy(cString + i, attributeNameCString, attributeNameLength);
		i += attributeNameLength;
		cString[i++] = '=';
		cString[i++] = delimiter;
		memcpy(cString + i, [tmp UTF8String], [tmp UTF8StringLength]);
		i += [tmp UTF8StringLength];
		memcpy(cString + i, tmp.UTF8String, tmp.UTF8StringLength);
		i += tmp.UTF8StringLength;
		cString[i++] = delimiter;

		objc_autoreleasePoolPop(pool2);
	}

	/* Children */
	if (_children != nil) {
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
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







-
-
+
+





-
+











-
-
+
+









-
+








-
-
-
+
+
+


-
-
+
+
-







					       indentation: ind
						     level: level + 1];
			else
				childString = [child
				    XMLStringWithIndentation: ind
						       level: level + 1];

			[tmp addItems: [childString UTF8String]
				count: [childString UTF8StringLength]];
			[tmp addItems: childString.UTF8String
				count: childString.UTF8StringLength];
		}

		if (indent)
			[tmp addItem: "\n"];

		length += [tmp count] + [_name UTF8StringLength] + 2 +
		length += tmp.count + _name.UTF8StringLength + 2 +
		    (indent ? level * indentation : 0);
		@try {
			cString = [self resizeMemory: cString
						size: length];
		} @catch (id e) {
			[self freeMemory: cString];
			@throw e;
		}

		cString[i++] = '>';

		memcpy(cString + i, [tmp items], [tmp count]);
		i += [tmp count];
		memcpy(cString + i, tmp.items, tmp.count);
		i += tmp.count;

		if (indent) {
			memset(cString + i, ' ', level * indentation);
			i += level * indentation;
		}

		cString[i++] = '<';
		cString[i++] = '/';
		if (prefix != nil) {
			length += [prefix UTF8StringLength] + 1;
			length += prefix.UTF8StringLength + 1;
			@try {
				cString = [self resizeMemory: cString
							size: length];
			} @catch (id e) {
				[self freeMemory: cString];
				@throw e;
			}

			memcpy(cString + i, [prefix UTF8String],
			    [prefix UTF8StringLength]);
			i += [prefix UTF8StringLength];
			memcpy(cString + i, prefix.UTF8String,
			    prefix.UTF8StringLength);
			i += prefix.UTF8StringLength;
			cString[i++] = ':';
		}
		memcpy(cString + i, [_name UTF8String],
		    [_name UTF8StringLength]);
		memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength);
		i += _name.UTF8StringLength;
		i += [_name UTF8StringLength];
	} else
		cString[i++] = '/';

	cString[i++] = '>';
	assert(i == length);

	objc_autoreleasePoolPop(pool);
697
698
699
700
701
702
703
704

705
706
707
708
709
710
711
692
693
694
695
696
697
698

699
700
701
702
703
704
705
706







-
+







}

- (OFXMLElement *)XMLElementBySerializing
{
	void *pool = objc_autoreleasePoolPush();
	OFXMLElement *element;

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

	if (_name != nil)
		[element addAttributeWithName: @"name"
				  stringValue: _name];

	if (_namespace != nil)
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
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







-
+













-
+




-
+










-
+







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

		attributesElement =
		    [OFXMLElement elementWithName: @"attributes"
					namespace: OF_SERIALIZATION_NS];
		[attributesElement addChild:
		    [_attributes XMLElementBySerializing]];
		    _attributes.XMLElementBySerializing];
		[element addChild: attributesElement];
	}

	if (_namespaces != nil) {
		OFXMLElement *namespacesElement;
		OFMutableDictionary *namespacesCopy =
		    [[_namespaces mutableCopy] autorelease];

		[namespacesCopy removeObjectForKey:
		    @"http://www.w3.org/XML/1998/namespace"];
		[namespacesCopy removeObjectForKey:
		    @"http://www.w3.org/2000/xmlns/"];

		if ([namespacesCopy count] > 0) {
		if (namespacesCopy.count > 0) {
			namespacesElement =
			    [OFXMLElement elementWithName: @"namespaces"
						namespace: OF_SERIALIZATION_NS];
			[namespacesElement addChild:
			    [namespacesCopy XMLElementBySerializing]];
			    namespacesCopy.XMLElementBySerializing];
			[element addChild: namespacesElement];
		}
	}

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

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

	[element retain];

	objc_autoreleasePoolPop(pool);

820
821
822
823
824
825
826
827
828


829
830
831
832
833
834
835
815
816
817
818
819
820
821


822
823
824
825
826
827
828
829
830







-
-
+
+







			return attribute;

	return nil;
}

- (void)removeAttributeForName: (OFString *)attributeName
{
	OFXMLAttribute *const *objects = [_attributes objects];
	size_t count = [_attributes count];
	OFXMLAttribute *const *objects = _attributes.objects;
	size_t count = _attributes.count;

	for (size_t i = 0; i < count; i++) {
		if (objects[i]->_namespace == nil &&
		    [objects[i]->_name isEqual: attributeName]) {
			[_attributes removeObjectAtIndex: i];

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







-
-
+
+













-
+







	size_t count;

	if (attributeNS == nil) {
		[self removeAttributeForName: attributeName];
		return;
	}

	objects = [_attributes objects];
	count = [_attributes count];
	objects = _attributes.objects;
	count = _attributes.count;

	for (size_t i = 0; i < count; i++) {
		if ([objects[i]->_namespace isEqual: attributeNS] &&
		    [objects[i]->_name isEqual: attributeName]) {
			[_attributes removeObjectAtIndex: i];
				return;
		}
	}
}

- (void)setPrefix: (OFString *)prefix
     forNamespace: (OFString *)namespace
{
	if ([prefix length] == 0)
	if (prefix.length == 0)
		@throw [OFInvalidArgumentException exception];
	if (namespace == nil)
		namespace = @"";

	[_namespaces setObject: prefix
			forKey: namespace];
}
949
950
951
952
953
954
955
956

957
958
959
960
961
962
963


964
965
966
967
968
969
970
944
945
946
947
948
949
950

951
952
953
954
955
956


957
958
959
960
961
962
963
964
965







-
+





-
-
+
+








	[_children replaceObjectAtIndex: idx
			     withObject: node];
}

- (OFXMLElement *)elementForName: (OFString *)elementName
{
	return [[self elementsForName: elementName] firstObject];
	return [self elementsForName: elementName].firstObject;
}

- (OFXMLElement *)elementForName: (OFString *)elementName
		       namespace: (OFString *)elementNS
{
	return [[self elementsForName: elementName
			    namespace: elementNS] firstObject];
	return [self elementsForName: elementName
			   namespace: elementNS].firstObject;
}

- (OFArray *)elements
{
	OFMutableArray OF_GENERIC(OFXMLElement *) *ret = [OFMutableArray array];

	for (OFXMLNode *child in _children)
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086






1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1069
1070
1071
1072
1073
1074
1075






1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092







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












- (uint32_t)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_name hash]);
	OF_HASH_ADD_HASH(hash, [_namespace hash]);
	OF_HASH_ADD_HASH(hash, [_defaultNamespace hash]);
	OF_HASH_ADD_HASH(hash, [_attributes hash]);
	OF_HASH_ADD_HASH(hash, [_namespaces hash]);
	OF_HASH_ADD_HASH(hash, [_children hash]);
	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD_HASH(hash, _namespace.hash);
	OF_HASH_ADD_HASH(hash, _defaultNamespace.hash);
	OF_HASH_ADD_HASH(hash, _attributes.hash);
	OF_HASH_ADD_HASH(hash, _namespaces.hash);
	OF_HASH_ADD_HASH(hash, _children.hash);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (id)copy
{
	return [[[self class] alloc] initWithElement: self];
}
@end

Modified src/OFXMLElementBuilder.m from [525456c691] to [40db47b479].

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







-
+



















-
-
+
+


-
-
-
-
+
+
+
+




-
+








-
+













-
+













-
+













-
+













-
+







}

-		 (void)parser: (OFXMLParser *)parser
  foundProcessingInstructions: (OFString *)pi
{
	OFXMLProcessingInstructions *node = [OFXMLProcessingInstructions
	    processingInstructionsWithString: pi];
	OFXMLElement *parent = [_stack lastObject];
	OFXMLElement *parent = _stack.lastObject;

	if (parent != nil)
		[parent addChild: node];
	else if ([_delegate respondsToSelector:
	    @selector(elementBuilder:didBuildParentlessNode:)])
		[_delegate elementBuilder: self
		   didBuildParentlessNode: node];
}

-    (void)parser: (OFXMLParser *)parser
  didStartElement: (OFString *)name
	   prefix: (OFString *)prefix
	namespace: (OFString *)namespace
       attributes: (OFArray *)attributes
{
	OFXMLElement *element = [OFXMLElement elementWithName: name
						    namespace: namespace];

	for (OFXMLAttribute *attribute in attributes) {
		if ([attribute namespace] == nil &&
		    [[attribute name] isEqual: @"xmlns"])
		if (attribute.namespace == nil &&
		    [attribute.name isEqual: @"xmlns"])
			continue;

		if ([[attribute namespace]
		    isEqual: @"http://www.w3.org/2000/xmlns/"])
			[element setPrefix: [attribute name]
			      forNamespace: [attribute stringValue]];
		if ([attribute.namespace isEqual:
		    @"http://www.w3.org/2000/xmlns/"])
			[element setPrefix: attribute.name
			      forNamespace: attribute.stringValue];

		[element addAttribute: attribute];
	}

	[[_stack lastObject] addChild: element];
	[_stack.lastObject addChild: element];
	[_stack addObject: element];
}

-  (void)parser: (OFXMLParser *)parser
  didEndElement: (OFString *)name
	 prefix: (OFString *)prefix
      namespace: (OFString *)namespace
{
	switch ([_stack count]) {
	switch (_stack.count) {
	case 0:
		if ([_delegate respondsToSelector: @selector(elementBuilder:
		    didNotExpectCloseTag:prefix:namespace:)])
			[_delegate elementBuilder: self
			     didNotExpectCloseTag: name
					   prefix: prefix
					namespace: namespace];
		else
			@throw [OFMalformedXMLException exception];

		return;
	case 1:
		[_delegate elementBuilder: self
			  didBuildElement: [_stack firstObject]];
			  didBuildElement: _stack.firstObject];
		break;
	}

	[_stack removeLastObject];
}

-    (void)parser: (OFXMLParser *)parser
  foundCharacters: (OFString *)characters
{
	OFXMLCharacters *node;
	OFXMLElement *parent;

	node = [OFXMLCharacters charactersWithString: characters];
	parent = [_stack lastObject];
	parent = _stack.lastObject;

	if (parent != nil)
		[parent addChild: node];
	else if ([_delegate respondsToSelector:
	    @selector(elementBuilder:didBuildParentlessNode:)])
		[_delegate  elementBuilder: self
		    didBuildParentlessNode: node];
}

- (void)parser: (OFXMLParser *)parser
    foundCDATA: (OFString *)CDATA
{
	OFXMLCDATA *node = [OFXMLCDATA CDATAWithString: CDATA];
	OFXMLElement *parent = [_stack lastObject];
	OFXMLElement *parent = _stack.lastObject;

	if (parent != nil)
		[parent addChild: node];
	else if ([_delegate respondsToSelector:
	    @selector(elementBuilder:didBuildParentlessNode:)])
		[_delegate elementBuilder: self
		   didBuildParentlessNode: node];
}

- (void)parser: (OFXMLParser *)parser
  foundComment: (OFString *)comment
{
	OFXMLComment *node = [OFXMLComment commentWithString: comment];
	OFXMLElement *parent = [_stack lastObject];
	OFXMLElement *parent = _stack.lastObject;

	if (parent != nil)
		[parent addChild: node];
	else if ([_delegate respondsToSelector:
	    @selector(elementBuilder:didBuildParentlessNode:)])
		[_delegate elementBuilder: self
		   didBuildParentlessNode: node];

Modified src/OFXMLNode.m from [badc6f5c55] to [ed42a019d1].

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







-
+




-
+




-
+




-
+







- (void)setStringValue: (OFString *)stringValue
{
	OF_UNRECOGNIZED_SELECTOR
}

- (intmax_t)decimalValue
{
	return [[self stringValue] decimalValue];
	return self.stringValue.decimalValue;
}

- (uintmax_t)hexadecimalValue
{
	return [[self stringValue] hexadecimalValue];
	return self.stringValue.hexadecimalValue;
}

- (float)floatValue
{
	return [[self stringValue] floatValue];
	return self.stringValue.floatValue;
}

- (double)doubleValue
{
	return [[self stringValue] doubleValue];
	return self.stringValue.doubleValue;
}

- (OFString *)XMLString
{
	return [self XMLStringWithIndentation: 0
					level: 0];
}

Modified src/OFXMLParser.m from [f6e5cef596] to [e97aaf5fcc].

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







-
-
+
+








-
-
+
+







-
+







		[buffer addItems: string
			   count: length];
	else {
		void *pool = objc_autoreleasePoolPush();
		OFString *tmp = [OFString stringWithCString: string
						   encoding: encoding
						     length: length];
		[buffer addItems: [tmp UTF8String]
			   count: [tmp UTF8StringLength]];
		[buffer addItems: tmp.UTF8String
			   count: tmp.UTF8StringLength];
		objc_autoreleasePoolPop(pool);
	}
}

static OFString *
transformString(OFXMLParser *parser, OFMutableData *buffer, size_t cut,
    bool unescape)
{
	char *items = [buffer items];
	size_t length = [buffer count] - cut;
	char *items = buffer.mutableItems;
	size_t length = buffer.count - cut;
	bool hasEntities = false;
	OFString *ret;

	for (size_t i = 0; i < length; i++) {
		if (items[i] == '\r') {
			if (i + 1 < length && items[i + 1] == '\n') {
				[buffer removeItemAtIndex: i];
				items = [buffer items];
				items = buffer.mutableItems;

				i--;
				length--;
			} else
				items[i] = '\n';
		} else if (items[i] == '&')
			hasEntities = true;
121
122
123
124
125
126
127
128
129


130
131
132
133
134
135
136
121
122
123
124
125
126
127


128
129
130
131
132
133
134
135
136







-
-
+
+








	return ret;
}

static OFString *
namespaceForPrefix(OFString *prefix, OFArray *namespaces)
{
	OFDictionary *const *objects = [namespaces objects];
	size_t count = [namespaces count];
	OFDictionary *const *objects = namespaces.objects;
	size_t count = namespaces.count;

	if (prefix == nil)
		prefix = @"";

	while (count > 0) {
		OFString *tmp;

278
279
280
281
282
283
284
285
286


287
288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
278
279
280
281
282
283
284


285
286
287
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302







-
-
+
+








-
+







	if (length - _last > 0 && _state != OF_XMLPARSER_IN_TAG)
		appendToBuffer(_buffer, _data + _last, _encoding,
		    length - _last);
}

- (void)parseString: (OFString *)string
{
	[self parseBuffer: [string UTF8String]
		   length: [string UTF8StringLength]];
	[self parseBuffer: string.UTF8String
		   length: string.UTF8StringLength];
}

- (void)parseStream: (OFStream *)stream
{
	size_t pageSize = [OFSystemInfo pageSize];
	char *buffer = [self allocMemoryWithSize: pageSize];

	@try {
		while (![stream isAtEndOfStream]) {
		while (!stream.atEndOfStream) {
			size_t length = [stream readIntoBuffer: buffer
							length: pageSize];

			[self parseBuffer: buffer
				   length: length];
		}
	} @finally {
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
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







-
+










-
+







}

/* Not in a tag */
- (void)of_outsideTagState
{
	size_t length;

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

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

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

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

		if ([_delegate respondsToSelector:
		    @selector(parser:foundCharacters:)])
			[_delegate parser: self
			  foundCharacters: characters];
394
395
396
397
398
399
400
401

402
403
404
405
406
407
408
394
395
396
397
398
399
400

401
402
403
404
405
406
407
408







-
+







		break;
	case '!':
		_last = _i + 1;
		_state = OF_XMLPARSER_IN_EXCLAMATIONMARK;
		_acceptProlog = false;
		break;
	default:
		if (_depthLimit > 0 && [_previous count] >= _depthLimit)
		if (_depthLimit > 0 && _previous.count >= _depthLimit)
			@throw [OFOutOfRangeException exception];

		_state = OF_XMLPARSER_IN_TAG_NAME;
		_acceptProlog = false;
		_i--;
		break;
	}
420
421
422
423
424
425
426
427
428


429
430
431


432
433
434
435
436
437
438
420
421
422
423
424
425
426


427
428
429


430
431
432
433
434
435
436
437
438







-
-
+
+

-
-
+
+







	bool hasVersion = false;

	if (!_acceptProlog)
		return false;

	_acceptProlog = false;

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

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

	last = 0;
	for (size_t i = 0; i < length; i++) {
		switch (PIState) {
		case 0:
			if (cString[i] == ' ' || cString[i] == '\t' ||
			    cString[i] == '\r' || cString[i] == '\n')
543
544
545
546
547
548
549
550
551


552
553
554
555
556
557
558
543
544
545
546
547
548
549


550
551
552
553
554
555
556
557
558







-
-
+
+







		return;

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

	pool = objc_autoreleasePoolPush();

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

	if ((tmp = memchr(bufferCString, ':', bufferLength)) != NULL) {
		_name = [[OFString alloc]
		    initWithUTF8String: tmp + 1
				length: bufferLength -
587
588
589
590
591
592
593
594

595
596
597
598
599
600
601
587
588
589
590
591
592
593

594
595
596
597
598
599
600
601







-
+







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

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

		[_name release];
		[_prefix release];
		_name = _prefix = nil;
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
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







-
-
+
+
















-
+







		return;

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

	pool = objc_autoreleasePoolPush();

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

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

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

	[_previous removeLastObject];

	[_buffer removeAllItems];

	namespace = namespaceForPrefix(_prefix, _namespaces);
677
678
679
680
681
682
683
684

685
686
687
688
689
690
691
677
678
679
680
681
682
683

684
685
686
687
688
689
690
691







-
+







	_name = _prefix = nil;

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

	if ([_previous count] == 0)
	if (_previous.count == 0)
		_finishedParsing = true;
}

/* Inside a tag, name found */
- (void)of_inTagState
{
	void *pool;
700
701
702
703
704
705
706
707
708


709
710
711
712
713
714
715
700
701
702
703
704
705
706


707
708
709
710
711
712
713
714
715







-
-
+
+







			_state = OF_XMLPARSER_IN_ATTRIBUTE_NAME;
			_i--;
		}

		return;
	}

	attributesObjects = [_attributes objects];
	attributesCount = [_attributes count];
	attributesObjects = _attributes.objects;
	attributesCount = _attributes.count;

	namespace = namespaceForPrefix(_prefix, _namespaces);

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

731
732
733
734
735
736
737
738

739
740
741
742
743
744
745
731
732
733
734
735
736
737

738
739
740
741
742
743
744
745







-
+







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

		if ([_previous count] == 0)
		if (_previous.count == 0)
			_finishedParsing = true;

		[_namespaces removeLastObject];
	} else if (_prefix != nil) {
		OFString *str = [OFString stringWithFormat: @"%@:%@",
							    _prefix, _name];
		[_previous addObject: str];
772
773
774
775
776
777
778
779
780


781
782
783


784
785
786
787
788
789
790
772
773
774
775
776
777
778


779
780
781


782
783
784
785
786
787
788
789
790







-
-
+
+

-
-
+
+







		return;

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

	pool = objc_autoreleasePoolPush();

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

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

	if ((tmp = memchr(bufferCString, ':', bufferLength)) != NULL) {
		_attributeName = [[OFString alloc]
		    initWithUTF8String: tmp + 1
				length: bufferLength -
					(tmp - bufferCString) - 1];
		_attributePrefix = [[OFString alloc]
849
850
851
852
853
854
855
856
857


858
859
860


861
862
863
864
865
866
867
849
850
851
852
853
854
855


856
857
858


859
860
861
862
863
864
865
866
867







-
-
+
+

-
-
+
+







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

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

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

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

Modified src/OFXMLProcessingInstructions.m from [894e02c7e4] to [b4f91e54e3].

49
50
51
52
53
54
55
56
57


58
59
60

61
62
63
64
65
66
67
49
50
51
52
53
54
55


56
57
58
59

60
61
62
63
64
65
66
67







-
-
+
+


-
+







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

	@try {
		void *pool = objc_autoreleasePoolPush();

		if (![[element name] isEqual: [self className]] ||
		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
		if (![element.name isEqual: self.className] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		_processingInstructions = [[element stringValue] copy];
		_processingInstructions = [element.stringValue copy];

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

89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103







-
+








	return ([processingInstructions->_processingInstructions
	    isEqual: _processingInstructions]);
}

- (uint32_t)hash
{
	return [_processingInstructions hash];
	return _processingInstructions.hash;
}

- (OFString *)stringValue
{
	return @"";
}

138
139
140
141
142
143
144
145

146
147
148
149
138
139
140
141
142
143
144

145
146
147
148
149







-
+




- (OFString *)description
{
	return [OFString stringWithFormat: @"<?%@?>", _processingInstructions];
}

- (OFXMLElement *)XMLElementBySerializing
{
	return [OFXMLElement elementWithName: [self className]
	return [OFXMLElement elementWithName: self.className
				   namespace: OF_SERIALIZATION_NS
				 stringValue: _processingInstructions];
}
@end

Modified src/OFZIPArchive.h from [56b243376c] to [4b0bcbe6e5].

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43







-
+







/*!
 * @class OFZIPArchive OFZIPArchive.h ObjFW/OFZIPArchive.h
 *
 * @brief A class for accessing and manipulating ZIP files.
 */
@interface OFZIPArchive: OFObject
{
	OF_KINDOF(OFStream *) _stream;
	OFStream *_stream;
	int64_t _offset;
	enum {
		OF_ZIP_ARCHIVE_MODE_READ,
		OF_ZIP_ARCHIVE_MODE_WRITE,
		OF_ZIP_ARCHIVE_MODE_APPEND
	} _mode;
	uint32_t _diskNumber, _centralDirectoryDisk;
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87







-
+







 * @param stream A stream from which the ZIP archive will be read.
 *		 For read and append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the ZIP file. Valid modes are "r" for reading,
 *	       "w" for creating a new file and "a" for appending to an existing
 *	       archive.
 * @return A new, autoreleased OFZIPArchive
 */
+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)archiveWithStream: (OFStream *)stream
			     mode: (OFString *)mode;

#ifdef OF_HAVE_FILES
/*!
 * @brief Creates a new OFZIPArchive object with the specified file.
 *
 * @param path The path to the ZIP file
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
103
104
105
106
107
108
109

110
111
112
113
114
115
116
117







-
+







 * @param stream A stream from which the ZIP archive will be read.
 *		 For read and append mode, this needs to be an OFSeekableStream.
 * @param mode The mode for the ZIP file. Valid modes are "r" for reading,
 *	       "w" for creating a new file and "a" for appending to an existing
 *	       archive.
 * @return An initialized OFZIPArchive
 */
- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode OF_DESIGNATED_INITIALIZER;

#ifdef OF_HAVE_FILES
/*!
 * @brief Initializes an already allocated OFZIPArchive object with the
 *	  specified file.
 *

Modified src/OFZIPArchive.m from [a406f55747] to [ebb48a8010].

72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
72
73
74
75
76
77
78


79
80
81
82
83
84
85
86
87







-
-
+
+








- (instancetype)initWithStream: (OFStream *)stream;
- (bool)matchesEntry: (OFZIPArchiveEntry *)entry;
@end

@interface OFZIPArchive_FileReadStream: OFStream
{
	OF_KINDOF(OFStream *) _stream;
	OF_KINDOF(OFStream *) _decompressedStream;
	OFStream *_stream;
	OFStream *_decompressedStream;
	OFZIPArchiveEntry *_entry;
	uint64_t _toRead;
	uint32_t _CRC32;
	bool _atEndOfStream;
}

- (instancetype)of_initWithStream: (OFStream *)stream
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
183
184
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
183
184







-
+









-
+




















-
+







seekOrThrowInvalidFormat(OFSeekableStream *stream,
    of_offset_t offset, int whence)
{
	@try {
		[stream seekToOffset: offset
			      whence: whence];
	} @catch (OFSeekFailedException *e) {
		if ([e errNo] == EINVAL)
		if (e.errNo == EINVAL)
			@throw [OFInvalidFormatException exception];

		@throw e;
	}
}

@implementation OFZIPArchive
@synthesize archiveComment = _archiveComment;

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
+ (instancetype)archiveWithStream: (OFStream *)stream
			     mode: (OFString *)mode
{
	return [[[self alloc] initWithStream: stream
					mode: mode] autorelease];
}

#ifdef OF_HAVE_FILES
+ (instancetype)archiveWithPath: (OFString *)path
			   mode: (OFString *)mode
{
	return [[[self alloc] initWithPath: path
				      mode: mode] autorelease];
}
#endif

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode
{
	self = [super init];

	@try {
		if ([mode isEqual: @"r"])
			_mode = OF_ZIP_ARCHIVE_MODE_READ;
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
200
201
202
203
204
205
206

207
208
209
210
211
212
213
214







-
+








			[self of_readZIPInfo];
			[self of_readEntries];
		}

		if (_mode == OF_ZIP_ARCHIVE_MODE_APPEND) {
			_offset = _centralDirectoryOffset;
			seekOrThrowInvalidFormat(_stream,
			seekOrThrowInvalidFormat((OFSeekableStream *)_stream,
			    (of_offset_t)_offset, SEEK_SET);
		}
	} @catch (id e) {
		/*
		 * If we are in write or append mode, we do not want -[close]
		 * to write anything to it on error - after all, it might not
		 * be a ZIP file which we would destroy otherwise.
264
265
266
267
268
269
270

271

272
273
274
275
276
277
278
264
265
266
267
268
269
270
271

272
273
274
275
276
277
278
279







+
-
+







{
	void *pool = objc_autoreleasePoolPush();
	uint16_t commentLength;
	of_offset_t offset = -22;
	bool valid = false;

	do {
		seekOrThrowInvalidFormat((OFSeekableStream *)_stream,
		seekOrThrowInvalidFormat(_stream, offset, SEEK_END);
		    offset, SEEK_END);

		if ([_stream readLittleEndianInt32] == 0x06054B50) {
			valid = true;
			break;
		}
	} while (--offset >= -65557);

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
327
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
327
328
329







+
-
+
















-
+







	    _centralDirectoryEntriesInDisk == 0xFFFF ||
	    _centralDirectoryEntries == 0xFFFF ||
	    _centralDirectorySize == 0xFFFFFFFF ||
	    _centralDirectoryOffset == 0xFFFFFFFF) {
		int64_t offset64;
		uint64_t size;

		seekOrThrowInvalidFormat((OFSeekableStream *)_stream,
		seekOrThrowInvalidFormat(_stream, offset - 20, SEEK_END);
		    offset - 20, SEEK_END);

		if ([_stream readLittleEndianInt32] != 0x07064B50) {
			objc_autoreleasePoolPop(pool);
			return;
		}

		/*
		 * FIXME: Handle number of the disk containing ZIP64 end of
		 * central directory record.
		 */
		[_stream readLittleEndianInt32];
		offset64 = [_stream readLittleEndianInt64];

		if (offset64 < 0 || (of_offset_t)offset64 != offset64)
			@throw [OFOutOfRangeException exception];

		seekOrThrowInvalidFormat(_stream,
		seekOrThrowInvalidFormat((OFSeekableStream *)_stream,
		    (of_offset_t)offset64, SEEK_SET);

		if ([_stream readLittleEndianInt32] != 0x06064B50)
			@throw [OFInvalidFormatException exception];

		size = [_stream readLittleEndianInt64];
		if (size < 44)
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
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







-
+






-
+




-
+




















-
+







{
	void *pool = objc_autoreleasePoolPush();

	if (_centralDirectoryOffset < 0 ||
	    (of_offset_t)_centralDirectoryOffset != _centralDirectoryOffset)
		@throw [OFOutOfRangeException exception];

	seekOrThrowInvalidFormat(_stream,
	seekOrThrowInvalidFormat((OFSeekableStream *)_stream,
	    (of_offset_t)_centralDirectoryOffset, SEEK_SET);

	for (size_t i = 0; i < _centralDirectoryEntries; i++) {
		OFZIPArchiveEntry *entry = [[[OFZIPArchiveEntry alloc]
		    of_initWithStream: _stream] autorelease];

		if ([_pathToEntryMap objectForKey: [entry fileName]] != nil)
		if ([_pathToEntryMap objectForKey: entry.fileName] != nil)
			@throw [OFInvalidFormatException exception];

		[_entries addObject: entry];
		[_pathToEntryMap setObject: entry
				    forKey: [entry fileName]];
				    forKey: entry.fileName];
	}

	objc_autoreleasePoolPop(pool);
}

- (OFArray *)entries
{
	return [[_entries copy] autorelease];
}

- (OFString *)archiveComment
{
	return _archiveComment;
}

- (void)setArchiveComment: (OFString *)comment
{
	void *pool = objc_autoreleasePoolPush();
	OFString *old;

	if ([comment UTF8StringLength] > UINT16_MAX)
	if (comment.UTF8StringLength > UINT16_MAX)
		@throw [OFOutOfRangeException exception];

	old = _archiveComment;
	_archiveComment = [comment copy];
	[old release];

	objc_autoreleasePoolPop(pool);
440
441
442
443
444
445
446
447

448
449
450

451

452
453
454
455
456
457
458
442
443
444
445
446
447
448

449
450
451
452
453

454
455
456
457
458
459
460
461







-
+



+
-
+







	if ((entry = [_pathToEntryMap objectForKey: path]) == nil)
		@throw [OFOpenItemFailedException exceptionWithPath: path
							       mode: @"r"
							      errNo: ENOENT];

	[self of_closeLastReturnedStream];

	offset64 = [entry of_localFileHeaderOffset];
	offset64 = entry.of_localFileHeaderOffset;
	if (offset64 < 0 || (of_offset_t)offset64 != offset64)
		@throw [OFOutOfRangeException exception];

	seekOrThrowInvalidFormat((OFSeekableStream *)_stream,
	seekOrThrowInvalidFormat(_stream, (of_offset_t)offset64, SEEK_SET);
	    (of_offset_t)offset64, SEEK_SET);
	localFileHeader = [[[OFZIPArchive_LocalFileHeader alloc]
	    initWithStream: _stream] autorelease];

	if (![localFileHeader matchesEntry: entry])
		@throw [OFInvalidFormatException exception];

	if ((localFileHeader->_minVersionNeeded & 0xFF) > 45) {
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
516
517
518





519
520
521


522
523
524
525
526
527
528





529
530
531
532
533
534
535
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
516





517
518
519
520
521



522
523
524
525





526
527
528
529
530
531
532
533
534
535
536
537







-
+

-
+



-
+






-
-
-
-
+
+
+
+




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


-
-
-
-
-
+
+
+
+
+







	if (_mode != OF_ZIP_ARCHIVE_MODE_WRITE &&
	    _mode != OF_ZIP_ARCHIVE_MODE_APPEND)
		@throw [OFInvalidArgumentException exception];

	pool = objc_autoreleasePoolPush();
	entry = [[entry_ mutableCopy] autorelease];

	if ([_pathToEntryMap objectForKey: [entry fileName]] != nil)
	if ([_pathToEntryMap objectForKey: entry.fileName] != nil)
		@throw [OFOpenItemFailedException
		    exceptionWithPath: [entry fileName]
		    exceptionWithPath: entry.fileName
				 mode: @"w"
				errNo: EEXIST];

	if ([entry compressionMethod] !=
	if (entry.compressionMethod !=
	    OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	[self of_closeLastReturnedStream];

	fileName = [entry fileName];
	fileNameLength = [fileName UTF8StringLength];
	extraField = [entry extraField];
	extraFieldLength = [extraField count];
	fileName = entry.fileName;
	fileNameLength = fileName.UTF8StringLength;
	extraField = entry.extraField;
	extraFieldLength = extraField.count;

	if (UINT16_MAX - extraFieldLength < 20)
		@throw [OFOutOfRangeException exception];

	[entry setVersionMadeBy: ([entry versionMadeBy] & 0xFF00) | 45];
	[entry setMinVersionNeeded: ([entry minVersionNeeded] & 0xFF00) | 45];
	[entry setCompressedSize: 0];
	[entry setUncompressedSize: 0];
	[entry setCRC32: 0];
	entry.versionMadeBy = (entry.versionMadeBy & 0xFF00) | 45;
	entry.minVersionNeeded = (entry.minVersionNeeded & 0xFF00) | 45;
	entry.compressedSize = 0;
	entry.uncompressedSize = 0;
	entry.CRC32 = 0;
	[entry setGeneralPurposeBitFlag:
	    [entry generalPurposeBitFlag] | (1 << 3) | (1 << 11)];
	[entry of_setLocalFileHeaderOffset: _offset];
	entry.generalPurposeBitFlag |= (1 << 3) | (1 << 11);
	entry.of_localFileHeaderOffset = _offset;

	[_stream writeLittleEndianInt32: 0x04034B50];
	[_stream writeLittleEndianInt16: [entry minVersionNeeded]];
	[_stream writeLittleEndianInt16: [entry generalPurposeBitFlag]];
	[_stream writeLittleEndianInt16: [entry compressionMethod]];
	[_stream writeLittleEndianInt16: [entry of_lastModifiedFileTime]];
	[_stream writeLittleEndianInt16: [entry of_lastModifiedFileDate]];
	[_stream writeLittleEndianInt16: entry.minVersionNeeded];
	[_stream writeLittleEndianInt16: entry.generalPurposeBitFlag];
	[_stream writeLittleEndianInt16: entry.compressionMethod];
	[_stream writeLittleEndianInt16: entry.of_lastModifiedFileTime];
	[_stream writeLittleEndianInt16: entry.of_lastModifiedFileDate];
	/* We use the data descriptor */
	[_stream writeLittleEndianInt32: 0];
	/* We use ZIP64 */
	[_stream writeLittleEndianInt32: 0xFFFFFFFF];
	[_stream writeLittleEndianInt32: 0xFFFFFFFF];
	[_stream writeLittleEndianInt16: fileNameLength];
	[_stream writeLittleEndianInt16: extraFieldLength + 20];
602
603
604
605
606
607
608
609

610
611
612
613
614
615
616
604
605
606
607
608
609
610

611
612
613
614
615
616
617
618







-
+







	[_stream writeLittleEndianInt32: 0x06054B50];
	[_stream writeLittleEndianInt16: 0xFFFF];	/* Disk number */
	[_stream writeLittleEndianInt16: 0xFFFF];	/* CD disk */
	[_stream writeLittleEndianInt16: 0xFFFF];	/* CD entries in disk */
	[_stream writeLittleEndianInt16: 0xFFFF];	/* CD entries */
	[_stream writeLittleEndianInt32: 0xFFFFFFFF];	/* CD size */
	[_stream writeLittleEndianInt32: 0xFFFFFFFF];	/* CD offset */
	[_stream writeLittleEndianInt16: [_archiveComment UTF8StringLength]];
	[_stream writeLittleEndianInt16: _archiveComment.UTF8StringLength];
	if (_archiveComment != nil)
		[_stream writeString: _archiveComment];

	objc_autoreleasePoolPop(pool);
}

- (void)close
683
684
685
686
687
688
689
690

691
692
693
694
695
696
697
685
686
687
688
689
690
691

692
693
694
695
696
697
698
699







-
+








			if (ZIP64Size > 0)
				@throw [OFInvalidFormatException exception];

			[extraField removeItemsInRange: range];
		}

		if ([extraField count] > 0) {
		if (extraField.count > 0) {
			[extraField makeImmutable];
			_extraField = [extraField copy];
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
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
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







-
-
-
+
+
+



-
-
-
+
+
+


-
+















-
+


















-
+







	[_extraField release];

	[super dealloc];
}

- (bool)matchesEntry: (OFZIPArchiveEntry *)entry
{
	if (_compressionMethod != [entry compressionMethod] ||
	    _lastModifiedFileTime != [entry of_lastModifiedFileTime] ||
	    _lastModifiedFileDate != [entry of_lastModifiedFileDate])
	if (_compressionMethod != entry.compressionMethod ||
	    _lastModifiedFileTime != entry.of_lastModifiedFileTime ||
	    _lastModifiedFileDate != entry.of_lastModifiedFileDate)
		return false;

	if (!(_generalPurposeBitFlag & (1 << 3)))
		if (_CRC32 != [entry CRC32] ||
		    _compressedSize != [entry compressedSize] ||
		    _uncompressedSize != [entry uncompressedSize])
		if (_CRC32 != entry.CRC32 ||
		    _compressedSize != entry.compressedSize ||
		    _uncompressedSize != entry.uncompressedSize)
			return false;

	if (![_fileName isEqual: [entry fileName]])
	if (![_fileName isEqual: entry.fileName])
		return false;

	return true;
}
@end

@implementation OFZIPArchive_FileReadStream
- (instancetype)of_initWithStream: (OFStream *)stream
			    entry: (OFZIPArchiveEntry *)entry
{
	self = [super init];

	@try {
		_stream = [stream retain];

		switch ([entry compressionMethod]) {
		switch (entry.compressionMethod) {
		case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE:
			_decompressedStream = [stream retain];
			break;
		case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE:
			_decompressedStream = [[OFInflateStream alloc]
			    initWithStream: stream];
			break;
		case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64:
			_decompressedStream = [[OFInflate64Stream alloc]
			    initWithStream: stream];
			break;
		default:
			@throw [OFNotImplementedException
			    exceptionWithSelector: _cmd
					   object: self];
		}

		_entry = [entry copy];
		_toRead = [entry uncompressedSize];
		_toRead = entry.uncompressedSize;
		_CRC32 = ~0;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
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
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







-
-
+



















-
+



-
+












-
-
+
+




+
-
+








	if (_stream == nil)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (_atEndOfStream)
		return 0;

	if ([_stream isAtEndOfStream] &&
	    ![_decompressedStream hasDataInReadBuffer])
	if (_stream.atEndOfStream && !_decompressedStream.hasDataInReadBuffer)
		@throw [OFTruncatedDataException exception];

#if SIZE_MAX >= UINT64_MAX
	if (length > UINT64_MAX)
		@throw [OFOutOfRangeException exception];
#endif

	if ((uint64_t)length > _toRead)
		length = (size_t)_toRead;

	ret = [_decompressedStream readIntoBuffer: buffer
					   length: length];

	_toRead -= ret;
	_CRC32 = of_crc32(_CRC32, buffer, ret);

	if (_toRead == 0) {
		_atEndOfStream = true;

		if (~_CRC32 != [_entry CRC32]) {
		if (~_CRC32 != _entry.CRC32) {
			OFString *actualChecksum = [OFString stringWithFormat:
			    @"%08" PRIX32, ~_CRC32];
			OFString *expectedChecksum = [OFString stringWithFormat:
			    @"%08" PRIX32, [_entry CRC32]];
			    @"%08" PRIX32, _entry.CRC32];

			@throw [OFChecksumMismatchException
			    exceptionWithActualChecksum: actualChecksum
				       expectedChecksum: expectedChecksum];
		}
	}

	return ret;
}

- (bool)hasDataInReadBuffer
{
	return ([super hasDataInReadBuffer] ||
	    [_decompressedStream hasDataInReadBuffer]);
	return (super.hasDataInReadBuffer ||
	    _decompressedStream.hasDataInReadBuffer);
}

- (int)fileDescriptorForReading
{
	return ((id <OFReadyForReadingObserving>)_decompressedStream)
	return [_decompressedStream fileDescriptorForReading];
	    .fileDescriptorForReading;
}

- (void)close
{
	[_stream release];
	_stream = nil;

910
911
912
913
914
915
916
917
918
919



920
921
922
923
924
912
913
914
915
916
917
918



919
920
921
922
923
924
925
926







-
-
-
+
+
+





	[_stream writeLittleEndianInt32: _CRC32];
	[_stream writeLittleEndianInt64: _bytesWritten];
	[_stream writeLittleEndianInt64: _bytesWritten];

	[_stream release];
	_stream = nil;

	[_entry setCRC32: ~_CRC32];
	[_entry setCompressedSize: _bytesWritten];
	[_entry setUncompressedSize: _bytesWritten];
	_entry.CRC32 = ~_CRC32;
	_entry.compressedSize = _bytesWritten;
	_entry.uncompressedSize = _bytesWritten;
	[_entry makeImmutable];

	_bytesWritten += (2 * 4 + 2 * 8);
}
@end

Modified src/OFZIPArchiveEntry.m from [ef9c9a9140] to [d12805fb90].

144
145
146
147
148
149
150
151
152


153
154
155
156
157
158
159
144
145
146
147
148
149
150


151
152
153
154
155
156
157
158
159







-
-
+
+







	}
}

size_t
of_zip_archive_entry_extra_field_find(OFData *extraField, uint16_t tag,
    uint16_t *size)
{
	const uint8_t *bytes = [extraField items];
	size_t count = [extraField count];
	const uint8_t *bytes = extraField.items;
	size_t count = extraField.count;

	for (size_t i = 0; i < count;) {
		uint16_t currentTag, currentSize;

		if (i + 3 >= count)
			@throw [OFInvalidFormatException exception];

189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
189
190
191
192
193
194
195

196
197
198
199
200
201
202
203







-
+







- (instancetype)initWithFileName: (OFString *)fileName
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();

		if ([fileName UTF8StringLength] > UINT16_MAX)
		if (fileName.UTF8StringLength > UINT16_MAX)
			@throw [OFOutOfRangeException exception];

		_fileName = [fileName copy];

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
278
279
280
281
282
283
284
285

286
287
288
289
290
291
292
278
279
280
281
282
283
284

285
286
287
288
289
290
291
292







-
+








			if (ZIP64Size > 0 || _localFileHeaderOffset < 0)
				@throw [OFInvalidFormatException exception];

			[extraField removeItemsInRange: range];
		}

		if ([extraField count] > 0) {
		if (extraField.count > 0) {
			[extraField makeImmutable];
			_extraField = [extraField copy];
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
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

495
496
497
498
499
500
501
502
503
504
505
506

507
508
509
510

511
512
513
514
515
516
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
495
496
497
498
499
500
501
502
503
504
505

506
507
508
509

510
511
512
513
514
515
516







-
+

-
+













-
+












-
-
+
+

-
+







-
+











-
+



-
+






	    @"\tCompressed size = %" @PRIu64 "\n"
	    @"\tUncompressed size = %" @PRIu64 "\n"
	    @"\tCompression method = %@\n"
	    @"\tModification date = %@\n"
	    @"\tCRC32 = %08" @PRIX32 @"\n"
	    @"\tExtra field = %@\n"
	    @">",
	    [self class], _fileName, _fileComment, _generalPurposeBitFlag,
	    self.class, _fileName, _fileComment, _generalPurposeBitFlag,
	    _compressedSize, _uncompressedSize, compressionMethod,
	    [self modificationDate], _CRC32, _extraField];
	    self.modificationDate, _CRC32, _extraField];

	[ret retain];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}

- (uint64_t)of_writeToStream: (OFStream *)stream
{
	void *pool = objc_autoreleasePoolPush();
	uint64_t size = 0;

	if (UINT16_MAX - [_extraField count] < 32)
	if (UINT16_MAX - _extraField.count < 32)
		@throw [OFOutOfRangeException exception];

	[stream writeLittleEndianInt32: 0x02014B50];
	[stream writeLittleEndianInt16: _versionMadeBy];
	[stream writeLittleEndianInt16: _minVersionNeeded];
	[stream writeLittleEndianInt16: _generalPurposeBitFlag];
	[stream writeLittleEndianInt16: _compressionMethod];
	[stream writeLittleEndianInt16: _lastModifiedFileTime];
	[stream writeLittleEndianInt16: _lastModifiedFileDate];
	[stream writeLittleEndianInt32: _CRC32];
	[stream writeLittleEndianInt32: 0xFFFFFFFF];
	[stream writeLittleEndianInt32: 0xFFFFFFFF];
	[stream writeLittleEndianInt16: (uint16_t)[_fileName UTF8StringLength]];
	[stream writeLittleEndianInt16: (uint16_t)[_extraField count] + 32];
	[stream writeLittleEndianInt16: (uint16_t)_fileName.UTF8StringLength];
	[stream writeLittleEndianInt16: (uint16_t)_extraField.count + 32];
	[stream writeLittleEndianInt16:
	    (uint16_t)[_fileComment UTF8StringLength]];
	    (uint16_t)_fileComment.UTF8StringLength];
	[stream writeLittleEndianInt16: 0xFFFF];
	[stream writeLittleEndianInt16: _internalAttributes];
	[stream writeLittleEndianInt32: _versionSpecificAttributes];
	[stream writeLittleEndianInt32: 0xFFFFFFFF];
	size += (4 + (6 * 2) + (3 * 4) + (5 * 2) + (2 * 4));

	[stream writeString: _fileName];
	size += (uint64_t)[_fileName UTF8StringLength];
	size += (uint64_t)_fileName.UTF8StringLength;

	[stream writeLittleEndianInt16: OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64];
	[stream writeLittleEndianInt16: 28];
	[stream writeLittleEndianInt64: _uncompressedSize];
	[stream writeLittleEndianInt64: _compressedSize];
	[stream writeLittleEndianInt64: _localFileHeaderOffset];
	[stream writeLittleEndianInt32: _startDiskNumber];
	size += (2 * 2) + (3 * 8) + 4;

	if (_extraField != nil)
		[stream writeData: _extraField];
	size += (uint64_t)[_extraField count];
	size += (uint64_t)_extraField.count;

	if (_fileComment != nil)
		[stream writeString: _fileComment];
	size += (uint64_t)[_fileComment UTF8StringLength];
	size += (uint64_t)_fileComment.UTF8StringLength;

	objc_autoreleasePoolPop(pool);

	return size;
}
@end

Modified src/base64.m from [8870eb10c8] to [5c79c97e1a].

101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115







-
+







{
	const uint8_t *buffer = (const uint8_t *)string;
	size_t i;

	if ((length & 3) != 0)
		return false;

	if ([data itemSize] != 1)
	if (data.itemSize != 1)
		return false;

	for (i = 0; i < length; i += 4) {
		uint32_t sb = 0;
		uint8_t count = 3;
		char db[3];
		int8_t tmp;

Modified src/bridge/NSArray_OFArray.m from [b2b37f6565] to [48bc1264c2].

43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57







-
+







		return [object NSObject];

	return object;
}

- (NSUInteger)count
{
	size_t count = [_array count];
	size_t count = _array.count;

	if (count > NSUIntegerMax)
		@throw [OFOutOfRangeException exception];

	return (NSUInteger)count;
}
@end

Modified src/bridge/NSBridging.h from [da42c5052c] to [1b3ca80d51].

38
39
40
41
42
43
44
45

46
47
48
38
39
40
41
42
43
44

45
46
47
48







-
+



 * @brief Returns an instance of an ObjFW object corresponding to the receiver.
 *
 * If possible, the original object is wrapped. If this is not possible, an
 * autoreleased copy is created.
 *
 * @return The receiver as an ObjFW object
 */
- (id)OFObject;
@property (readonly, nonatomic) id OFObject;
@end

OF_ASSUME_NONNULL_END

Modified src/bridge/NSDictionary_OFDictionary.m from [a3c8b1ddd3] to [d509c1b2b1].

50
51
52
53
54
55
56
57

58
59
60
61
62
63
64
50
51
52
53
54
55
56

57
58
59
60
61
62
63
64







-
+







		return [object NSObject];

	return object;
}

- (NSUInteger)count
{
	size_t count = [_dictionary count];
	size_t count = _dictionary.count;

	if (count > NSUIntegerMax)
		@throw [OFOutOfRangeException exception];

	return (NSUInteger)count;
}
@end

Modified src/bridge/NSString+OFObject.m from [8716e136d6] to [4604799e9f].

19
20
21
22
23
24
25
26

27
28
19
20
21
22
23
24
25

26
27
28







-
+


#import "OFString.h"

int _NSString_OFObject_reference;

@implementation NSString (OFObject)
- (id)OFObject
{
	return [OFString stringWithUTF8String: [self UTF8String]];
	return [OFString stringWithUTF8String: self.UTF8String];
}
@end

Modified src/bridge/OFArray_NSArray.m from [74dc53d6fa] to [48af716058].

27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41







-
+







- (instancetype)initWithNSArray: (NSArray *)array
{
	self = [super init];

	@try {
		if (array == nil)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		_array = [array retain];
	} @catch (id e) {
		[self release];
		@throw e;
	}

55
56
57
58
59
60
61
62

63
64
55
56
57
58
59
60
61

62
63
64







-
+


		return [object OFObject];

	return object;
}

- (size_t)count
{
	return [_array count];
	return _array.count;
}
@end

Modified src/bridge/OFBridging.h from [ddb7c293c6] to [441e4ae6c2].

39
40
41
42
43
44
45
46

47
48
49
39
40
41
42
43
44
45

46
47
48
49







-
+



 *	  receiver.
 *
 * If possible, the original object is wrapped. If this is not possible, an
 * autoreleased copy is created.
 *
 * @return The receiver as Foundation object
 */
- (id)NSObject;
@property (readonly, nonatomic) id NSObject;
@end

OF_ASSUME_NONNULL_END

Modified src/bridge/OFDictionary_NSDictionary.m from [62f35cbb79] to [6f3ba7ec5c].

28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42







-
+







- (instancetype)initWithNSDictionary: (NSDictionary *)dictionary
{
	self = [super init];

	@try {
		if (dictionary == nil)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithClass: self.class];

		_dictionary = [dictionary retain];
	} @catch (id e) {
		[self release];
		@throw e;
	}

56
57
58
59
60
61
62
63

64
65
56
57
58
59
60
61
62

63
64
65







-
+


		return [object OFObject];

	return object;
}

- (size_t)count
{
	return [_dictionary count];
	return _dictionary.count;
}
@end

Modified src/bridge/OFString+NSObject.m from [50b50754ec] to [b02ed78e50].

22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
22
23
24
25
26
27
28

29
30
31
32
33
34
35
36
37







-
+








#import "OFInitializationFailedException.h"

int _OFString_NSObject_reference;

@implementation OFString (NSObject)
- (id)NSObject
{
	NSString *string = [NSString stringWithUTF8String: [self UTF8String]];
	NSString *string = [NSString stringWithUTF8String: self.UTF8String];

	if (string == nil)
		@throw [OFInitializationFailedException
		    exceptionWithClass: [NSString class]];

	return string;
}
@end

Modified src/exceptions/OFConditionBroadcastFailedException.m from [818bacfec1] to [c0d37d74d8].

51
52
53
54
55
56
57
58

59
60
61
62
51
52
53
54
55
56
57

58
59
60
61
62







-
+




}

- (OFString *)description
{
	if (_condition != nil)
		return [OFString stringWithFormat:
		    @"Broadcasting a condition of type %@ failed!",
		    [_condition class]];
		    _condition.class];
	else
		return @"Broadcasting a condition failed!";
}
@end

Modified src/exceptions/OFConditionSignalFailedException.m from [7cf102178e] to [a0b8d7c91b].

51
52
53
54
55
56
57
58

59
60
61
62
51
52
53
54
55
56
57

58
59
60
61
62







-
+




}

- (OFString *)description
{
	if (_condition != nil)
		return [OFString stringWithFormat:
		    @"Signaling a condition of type %@ failed!",
		    [_condition class]];
		    _condition.class];
	else
		return @"Signaling a condition failed!";
}
@end

Modified src/exceptions/OFConditionStillWaitingException.m from [3fa8245c6c] to [88255bff6f].

52
53
54
55
56
57
58
59

60
61
62
63
64
52
53
54
55
56
57
58

59
60
61
62
63
64







-
+






- (OFString *)description
{
	if (_condition != nil)
		return [OFString stringWithFormat:
		    @"Deallocation of a condition of type %@ was tried, even "
		    "though a thread was still waiting for it!",
		    [_condition class]];
		    _condition.class];
	else
		return @"Deallocation of a condition was tried, even though a "
		    "thread was still waiting for it!";
}
@end

Modified src/exceptions/OFConditionWaitFailedException.m from [ed882483df] to [872efbe506].

51
52
53
54
55
56
57
58

59
60
61
62
51
52
53
54
55
56
57

58
59
60
61
62







-
+




}

- (OFString *)description
{
	if (_condition != nil)
		return [OFString stringWithFormat:
		    @"Waiting for a condition of type %@ failed!",
		    [_condition class]];
		    _condition.class];
	else
		return @"Waiting for a condition failed!";
}
@end

Modified src/exceptions/OFException.m from [168ff4f79b] to [fde76d6a75].

272
273
274
275
276
277
278
279

280
281
282
283
284
285
286
272
273
274
275
276
277
278

279
280
281
282
283
284
285
286







-
+







	return self;
}
#endif

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"An exception of type %@ occurred!", [self class]];
	    @"An exception of type %@ occurred!", self.class];
}

- (OFArray OF_GENERIC(OFString *) *)backtrace
{
#ifdef HAVE__UNWIND_BACKTRACE
	OFMutableArray OF_GENERIC(OFString *) *backtrace =
	    [OFMutableArray array];

Modified src/exceptions/OFGetOptionFailedException.m from [1cc76fa0b0] to [e227c18ccc].

59
60
61
62
63
64
65
66

67
68
59
60
61
62
63
64
65

66
67
68







-
+


	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"Getting an option in a stream of type %@ failed: %@",
	    [_stream class], of_strerror(_errNo)];
	    _stream.class, of_strerror(_errNo)];
}
@end

Modified src/exceptions/OFHTTPRequestFailedException.m from [b33d383c3b] to [c006f7c54d].

59
60
61
62
63
64
65
66

67
68
69
70
71

72
73
59
60
61
62
63
64
65

66

67
68
69

70
71
72







-
+
-



-
+


	[_response release];

	[super dealloc];
}

- (OFString *)description
{
	const char *method =
	const char *method = of_http_request_method_to_string(_request.method);
	    of_http_request_method_to_string([_request method]);

	return [OFString stringWithFormat:
	    @"An HTTP %s request with URL %@ failed with code %d!", method,
	    [_request URL], [_response statusCode]];
	    _request.URL, _response.statusCode];
}
@end

Modified src/exceptions/OFLockFailedException.m from [917c5fce63] to [5ebc5106e3].

49
50
51
52
53
54
55
56

57
58
59
60
49
50
51
52
53
54
55

56
57
58
59
60







-
+




	[super dealloc];
}

- (OFString *)description
{
	if (_lock != nil)
		return [OFString stringWithFormat:
		    @"A lock of type %@ could not be locked!", [_lock class]];
		    @"A lock of type %@ could not be locked!", _lock.class];
	else
		return @"A lock could not be locked!";
}
@end

Modified src/exceptions/OFMalformedXMLException.m from [85b84d379a] to [03c1cd11c5].

51
52
53
54
55
56
57
58

59
60
61
62
51
52
53
54
55
56
57

58
59
60
61
62







-
+




}

- (OFString *)description
{
	if (_parser != nil)
		return [OFString stringWithFormat:
		    @"An XML parser of type %@ encountered malformed XML in "
		    @"line %zu!", [_parser class], [_parser lineNumber]];
		    @"line %zu!", _parser.class, _parser.lineNumber];
	else
		return @"An XML parser encountered malformed XML!";
}
@end

Modified src/exceptions/OFObserveFailedException.m from [790e9c0e69] to [6c8df61c71].

64
65
66
67
68
69
70
71

72
73
64
65
66
67
68
69
70

71
72
73







-
+


	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"An observer of class %@ failed to observe: %@",
	    [_observer className], of_strerror(_errNo)];
	    _observer.class, of_strerror(_errNo)];
}
@end

Modified src/exceptions/OFSeekFailedException.m from [58dd984cfb] to [2e85de50c3].

68
69
70
71
72
73
74
75

76
77
68
69
70
71
72
73
74

75
76
77







-
+


	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"Seeking failed in stream of type %@: %@",
	    [_stream class], of_strerror(_errNo)];
	    _stream.class, of_strerror(_errNo)];
}
@end

Modified src/exceptions/OFStillLockedException.m from [abb4e51f4a] to [bee06f8528].

50
51
52
53
54
55
56
57

58
59
60
61
62
50
51
52
53
54
55
56

57
58
59
60
61
62







-
+





}

- (OFString *)description
{
	if (_lock != nil)
		return [OFString stringWithFormat:
		    @"Deallocation of a lock of type %@ even though it was "
		    @"still locked!", [_lock class]];
		    @"still locked!", _lock.class];
	else
		return @"Deallocation of a lock even though it was still "
		    @"locked!";
}
@end

Modified src/exceptions/OFThreadJoinFailedException.m from [7b4e9d8e39] to [8453050bf7].

52
53
54
55
56
57
58
59

60
61
62
63
64
52
53
54
55
56
57
58

59
60
61
62
63
64







-
+






- (OFString *)description
{
	if (_thread != nil)
		return [OFString stringWithFormat:
		    @"Joining a thread of type %@ failed! Most likely, another "
		    @"thread already waits for the thread to join.",
		    [_thread class]];
		    _thread.class];
	else
		return @"Joining a thread failed! Most likely, another thread "
		    @"already waits for the thread to join.";
}
@end

Modified src/exceptions/OFThreadStartFailedException.m from [c9a1338f9d] to [0346f15b9f].

50
51
52
53
54
55
56
57

58
59
60
61
50
51
52
53
54
55
56

57
58
59
60
61







-
+




	[super dealloc];
}

- (OFString *)description
{
	if (_thread != nil)
		return [OFString stringWithFormat:
		    @"Starting a thread of type %@ failed!", [_thread class]];
		    @"Starting a thread of type %@ failed!", _thread.class];
	else
		return @"Starting a thread failed!";
}
@end

Modified src/exceptions/OFThreadStillRunningException.m from [6701777632] to [0f17a0cae3].

52
53
54
55
56
57
58
59

60
61
62
63
64
52
53
54
55
56
57
58

59
60
61
62
63
64







-
+






- (OFString *)description
{
	if (_thread)
		return [OFString stringWithFormat:
		    @"Deallocation of a thread of type %@ was tried, even "
		    @"though it was still running!",
		    [_thread class]];
		    _thread.class];
	else
		return @"Deallocation of a thread was tried, even though it "
		    @"was still running!";
}
@end

Modified src/exceptions/OFUnboundNamespaceException.m from [c9f5da877a] to [010c318107].

65
66
67
68
69
70
71
72

73
74
65
66
67
68
69
70
71

72
73
74







-
+


	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"The namespace %@ is not bound in an element of type %@!",
	    _namespace, [_element class]];
	    _namespace, _element.class];
}
@end

Modified src/exceptions/OFUnboundPrefixException.m from [3f6fe5c924] to [c97c6c3e6a].

65
66
67
68
69
70
71
72

73
74
65
66
67
68
69
70
71

72
73
74







-
+


	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"An XML parser of type %@ encountered the unbound prefix %@ in "
	    @"line %zu!", [_parser class], _prefix, [_parser lineNumber]];
	    @"line %zu!", _parser.class, _prefix, _parser.lineNumber];
}
@end

Modified src/exceptions/OFUnlockFailedException.m from [f5eb2bdfd8] to [cdcb8469af].

49
50
51
52
53
54
55
56

57
58
59
60
49
50
51
52
53
54
55

56
57
58
59
60







-
+




	[super dealloc];
}

- (OFString *)description
{
	if (_lock != nil)
		return [OFString stringWithFormat:
		    @"A lock of type %@ could not be unlocked!", [_lock class]];
		    @"A lock of type %@ could not be unlocked!", _lock.class];
	else
		return @"A lock could not be unlocked!";
}
@end

Modified src/invocation/invoke-x86_64.m from [47d3793287] to [5df8286fd6].

189
190
191
192
193
194
195
196
197


198
199
200
201
202
203
204
189
190
191
192
193
194
195


196
197
198
199
200
201
202
203
204







-
-
+
+







	*context = newContext;
}
#endif

void
of_invocation_invoke(OFInvocation *invocation)
{
	OFMethodSignature *methodSignature = [invocation methodSignature];
	size_t numberOfArguments = [methodSignature numberOfArguments];
	OFMethodSignature *methodSignature = invocation.methodSignature;
	size_t numberOfArguments = methodSignature.numberOfArguments;
	struct call_context *context;
	const char *typeEncoding;
	uint_fast8_t currentGPR = 0, currentSSE = 0;

	if ((context = calloc(sizeof(*context), 1)) == NULL)
		@throw [OFOutOfMemoryException exception];

306
307
308
309
310
311
312
313

314
315
316
317
318
319
320
306
307
308
309
310
311
312

313
314
315
316
317
318
319
320







-
+







		/* TODO: '(' */
		default:
			free(context);
			@throw [OFInvalidFormatException exception];
		}
	}

	typeEncoding = [methodSignature methodReturnType];
	typeEncoding = methodSignature.methodReturnType;

	if (*typeEncoding == 'r')
		typeEncoding++;

	switch (*typeEncoding) {
	case 'v':
	case 'c':

Modified src/of_asprintf.m from [3f7a200743] to [53badc787e].

368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
368
369
370
371
372
373
374

375
376
377
378
379
380
381
382







-
+







		@try {
			id object;

			if ((object = va_arg(ctx->arguments, id)) != nil) {
				void *pool = objc_autoreleasePoolPush();

				tmpLen = asprintf(&tmp, ctx->subformat,
				    [[object description] UTF8String]);
				    [object description].UTF8String);

				objc_autoreleasePoolPop(pool);
			} else
				tmpLen = asprintf(&tmp, ctx->subformat,
				    "(nil)");
		} @catch (id e) {
			free(ctx->buffer);
562
563
564
565
566
567
568
569

570
571

572
573

574
575
576
577
578
579
580
562
563
564
565
566
567
568

569
570

571
572

573
574
575
576
577
578
579
580







-
+

-
+

-
+







				    stringWithUTF8String: tmp
						  length: tmpLen];
				OFString *point = [OFLocale decimalPoint];
				if (point != nil)
					[tmpStr
					    replaceOccurrencesOfString: point
							    withString: @"."];
				if ([tmpStr UTF8StringLength] > INT_MAX)
				if (tmpStr.UTF8StringLength > INT_MAX)
					return false;
				tmpLen = (int)[tmpStr UTF8StringLength];
				tmpLen = (int)tmpStr.UTF8StringLength;
				tmp2 = malloc(tmpLen);
				memcpy(tmp2, [tmpStr UTF8String], tmpLen);
				memcpy(tmp2, tmpStr.UTF8String, tmpLen);
			} @finally {
				free(tmp);
				objc_autoreleasePoolPop(pool);
			}

			tmp = tmp2;
		}

Modified src/pbkdf2.m from [ba13c01e7e] to [8a2fd39e02].

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







-
+


-
-
+
+















-
+

















-
-
+
+





-
+








void of_pbkdf2(OFHMAC *HMAC, size_t iterations,
    const unsigned char *salt, size_t saltLength,
    const char *password, size_t passwordLength,
    unsigned char *key, size_t keyLength)
{
	void *pool = objc_autoreleasePoolPush();
	size_t blocks, digestSize = [HMAC digestSize];
	size_t blocks, digestSize = HMAC.digestSize;
	OFSecureData *buffer = [OFSecureData dataWithCount: digestSize];
	OFSecureData *digest = [OFSecureData dataWithCount: digestSize];
	unsigned char *bufferItems = [buffer items];
	unsigned char *digestItems = [digest items];
	unsigned char *bufferItems = buffer.mutableItems;
	unsigned char *digestItems = digest.mutableItems;
	OFSecureData *extendedSalt;
	unsigned char *extendedSaltItems;

	if (HMAC == nil || iterations == 0 || salt == NULL ||
	    password == NULL || key == NULL || keyLength == 0)
		@throw [OFInvalidArgumentException exception];

	blocks = keyLength / digestSize;
	if (keyLength % digestSize != 0)
		blocks++;

	if (saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX)
		@throw [OFOutOfRangeException exception];

	extendedSalt = [OFSecureData dataWithCount: saltLength + 4];
	extendedSaltItems = [extendedSalt items];
	extendedSaltItems = extendedSalt.mutableItems;

	@try {
		uint32_t i = OF_BSWAP32_IF_LE(1);

		[HMAC setKey: password
		      length: passwordLength];

		memcpy(extendedSaltItems, salt, saltLength);

		while (keyLength > 0) {
			size_t length;

			memcpy(extendedSaltItems + saltLength, &i, 4);

			[HMAC reset];
			[HMAC updateWithBuffer: extendedSaltItems
					length: saltLength + 4];
			memcpy(bufferItems, [HMAC digest], digestSize);
			memcpy(digestItems, [HMAC digest], digestSize);
			memcpy(bufferItems, HMAC.digest, digestSize);
			memcpy(digestItems, HMAC.digest, digestSize);

			for (size_t j = 1; j < iterations; j++) {
				[HMAC reset];
				[HMAC updateWithBuffer: digestItems
						length: digestSize];
				memcpy(digestItems, [HMAC digest], digestSize);
				memcpy(digestItems, HMAC.digest, digestSize);

				for (size_t k = 0; k < digestSize; k++)
					bufferItems[k] ^= digestItems[k];
			}

			length = digestSize;
			if (length > keyLength)

Modified src/socket.m from [e7074a55dd] to [b2488d7024].

251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266

267
268
269
270
271
272
273

274
275
276
277
278
279
280
251
252
253
254
255
256
257

258
259
260
261
262
263
264
265

266
267
268
269
270
271
272

273
274
275
276
277
278
279
280







-
+







-
+






-
+







	addrIn->sin_port = OF_BSWAP16_IF_LE(port);
#ifdef OF_WII
	addrIn->sin_len = ret.length;
#endif

	components = [IPv4 componentsSeparatedByString: @"."];

	if ([components count] != 4)
	if (components.count != 4)
		@throw [OFInvalidFormatException exception];

	addr = 0;

	for (OFString *component in components) {
		intmax_t number;

		if ([component length] == 0)
		if (component.length == 0)
			@throw [OFInvalidFormatException exception];

		if ([component indexOfCharacterFromSet:
		    whitespaceCharacterSet] != OF_NOT_FOUND)
			@throw [OFInvalidFormatException exception];

		number = [component decimalValue];
		number = component.decimalValue;

		if (number < 0 || number > UINT8_MAX)
			@throw [OFInvalidFormatException exception];

		addr = (addr << 8) | (number & 0xFF);
	}

290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
290
291
292
293
294
295
296

297
298
299
300
301
302
303
304







-
+







{
	uintmax_t number;

	if ([component indexOfCharacterFromSet:
	    [OFCharacterSet whitespaceCharacterSet]] != OF_NOT_FOUND)
		@throw [OFInvalidFormatException exception];

	number = [component hexadecimalValue];
	number = component.hexadecimalValue;

	if (number > UINT16_MAX)
		@throw [OFInvalidFormatException exception];

	return (uint16_t)number;
}

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







-
+










-
+











-
+










-
+






-
+








	doubleColon = [IPv6 rangeOfString: @"::"].location;

	if (doubleColon != OF_NOT_FOUND) {
		OFString *left = [IPv6 substringWithRange:
		    of_range(0, doubleColon)];
		OFString *right = [IPv6 substringWithRange:
		    of_range(doubleColon + 2, [IPv6 length] - doubleColon - 2)];
		    of_range(doubleColon + 2, IPv6.length - doubleColon - 2)];
		OFArray OF_GENERIC(OFString *) *leftComponents;
		OFArray OF_GENERIC(OFString *) *rightComponents;
		size_t i;

		if ([right hasPrefix: @":"] || [right containsString: @"::"])
			@throw [OFInvalidFormatException exception];

		leftComponents = [left componentsSeparatedByString: @":"];
		rightComponents = [right componentsSeparatedByString: @":"];

		if ([leftComponents count] + [rightComponents count] > 7)
		if (leftComponents.count + rightComponents.count > 7)
			@throw [OFInvalidFormatException exception];

		i = 0;
		for (OFString *component in leftComponents) {
			uint16_t number = parseIPv6Component(component);

			addrIn6->sin6_addr.s6_addr[i++] = number >> 8;
			addrIn6->sin6_addr.s6_addr[i++] = number;
		}

		i = 16;
		for (OFString *component in [rightComponents reversedArray]) {
		for (OFString *component in rightComponents.reversedArray) {
			uint16_t number = parseIPv6Component(component);

			addrIn6->sin6_addr.s6_addr[--i] = number >> 8;
			addrIn6->sin6_addr.s6_addr[--i] = number;
		}
	} else {
		OFArray OF_GENERIC(OFString *) *components =
		    [IPv6 componentsSeparatedByString: @":"];
		size_t i;

		if ([components count] != 8)
		if (components.count != 8)
			@throw [OFInvalidFormatException exception];

		i = 0;
		for (OFString *component in components) {
			uint16_t number;

			if ([component length] == 0)
			if (component.length == 0)
				@throw [OFInvalidFormatException exception];

			number = parseIPv6Component(component);

			addrIn6->sin6_addr.s6_addr[i++] = number >> 8;
			addrIn6->sin6_addr.s6_addr[i++] = number;
		}

Modified src/threading_winapi.m from [eef2483c77] to [5c88d5e359].

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43







-
+







}

bool
of_thread_new(of_thread_t *thread, void (*function)(id), id object,
    const of_thread_attr_t *attr)
{
	*thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0),
	    (LPTHREAD_START_ROUTINE)function, (__bridge void *)object, 0, NULL);
	    (LPTHREAD_START_ROUTINE)function, (void *)object, 0, NULL);

	if (thread == NULL)
		return false;

	if (attr != NULL && attr->priority != 0) {
		DWORD priority;

Modified utils/ofhttp/OFHTTP.m from [fe54fd9353] to [1da76a65b7].

512
513
514
515
516
517
518
519

520
521
522
523
524

525
526
527
528
529
530
531
512
513
514
515
516
517
518

519
520
521
522
523

524
525
526
527
528
529
530
531







-
+




-
+







		[_HTTPClient setInsecureRedirectsAllowed: true];

	[self performSelector: @selector(downloadNextURL)
		   afterDelay: 0];
}

-    (void)client: (OFHTTPClient *)client
  didCreateSocket: (OF_KINDOF(OFTCPSocket *))sock
  didCreateSocket: (OFTCPSocket *)sock
	  request: (OFHTTPRequest *)request
{
	if (_insecure && [sock respondsToSelector:
	    @selector(setCertificateVerificationEnabled:)])
		[sock setCertificateVerificationEnabled: false];
		((id <OFTLSSocket>)sock).certificateVerificationEnabled = false;
}

-     (void)client: (OFHTTPClient *)client
  wantsRequestBody: (OFStream *)body
	   request: (OFHTTPRequest *)request
{
	/* TODO: Do asynchronously and print status */
648
649
650
651
652
653
654
655

656
657
658
659
660
661
662
648
649
650
651
652
653
654

655
656
657
658
659
660
661
662







-
+







	} else
		@throw e;

	[self performSelector: @selector(downloadNextURL)
		   afterDelay: 0];
}

-      (bool)stream: (OF_KINDOF(OFStream *))response
-      (bool)stream: (OFStream *)response
  didReadIntoBuffer: (void *)buffer
	     length: (size_t)length
	  exception: (id)exception
{
	if (exception != nil) {
		OFString *URL;