ObjFW  Changes On Branch c45a1085852f19c7

Changes In Branch new-naming-convention Through [c45a108585] Excluding Merge-Ins

This is equivalent to a diff from 27002f2efe to c45a108585

2021-04-25
11:29
Change the naming convention check-in: 2b74ff13b0 user: js tags: trunk
2021-04-17
14:13
Always prefix functions with the type check-in: eb0cfa6ff9 user: js tags: new-naming-convention
14:05
Minor fixes for last commit check-in: c45a108585 user: js tags: new-naming-convention
13:58
of_socket_address_t -> OFSocketAddress check-in: e3c5bb70dd user: js tags: new-naming-convention
00:59
Merge trunk into branch "new-naming-convention" check-in: b57126a21e user: js tags: new-naming-convention
00:57
OFNumber: Remove useless OF_UNAVAILABLE check-in: 27002f2efe user: js tags: trunk
2021-04-13
21:43
Simplify OFValue check-in: e41940c022 user: js tags: trunk

Modified generators/unicode/TableGenerator.h from [75d0d664b0] to [d50b4bdc88].

18
19
20
21
22
23
24
25
26
27
28




29
30
31
32
33
34
35
18
19
20
21
22
23
24




25
26
27
28
29
30
31
32
33
34
35







-
-
-
-
+
+
+
+








@class OFString;

@interface TableGenerator: OFObject <OFApplicationDelegate,
    OFHTTPClientDelegate>
{
	OFHTTPClient *_HTTPClient;
	of_unichar_t _uppercaseTable[0x110000];
	of_unichar_t _lowercaseTable[0x110000];
	of_unichar_t _titlecaseTable[0x110000];
	of_unichar_t _casefoldingTable[0x110000];
	OFUnichar _uppercaseTable[0x110000];
	OFUnichar _lowercaseTable[0x110000];
	OFUnichar _titlecaseTable[0x110000];
	OFUnichar _casefoldingTable[0x110000];
	OFString *_decompositionTable[0x110000];
	OFString *_decompositionCompatTable[0x110000];
	char _uppercaseTableUsed[0x1100];
	char _lowercaseTableUsed[0x1100];
	char _titlecaseTableUsed[0x1100];
	char _casefoldingTableUsed[0x1100];
	char _decompositionTableUsed[0x1100];

Modified generators/unicode/TableGenerator.m from [4d33b76d8d] to [a801b746a9].

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







-
+












-
+





-
+

-
+

-
+










-
+






-
+







	OFHTTPRequest *request;

	[of_stdout writeString: @"Parsing UnicodeData.txt…"];

	while ((line = [response readLine]) != nil) {
		void *pool2;
		OFArray OF_GENERIC(OFString *) *components;
		of_unichar_t codePoint;
		OFUnichar codePoint;

		if (line.length == 0)
			continue;

		pool2 = objc_autoreleasePoolPush();

		components = [line componentsSeparatedByString: @";"];
		if (components.count != 15) {
			of_log(@"Invalid line: %@\n", line);
			[OFApplication terminateWithStatus: 1];
		}

		codePoint = (of_unichar_t)[[components objectAtIndex: 0]
		codePoint = (OFUnichar)[[components objectAtIndex: 0]
		    unsignedLongLongValueWithBase: 16];

		if (codePoint > 0x10FFFF)
			@throw [OFOutOfRangeException exception];

		_uppercaseTable[codePoint] = (of_unichar_t)[[components
		_uppercaseTable[codePoint] = (OFUnichar)[[components
		    objectAtIndex: 12] unsignedLongLongValueWithBase: 16];
		_lowercaseTable[codePoint] = (of_unichar_t)[[components
		_lowercaseTable[codePoint] = (OFUnichar)[[components
		    objectAtIndex: 13] unsignedLongLongValueWithBase: 16];
		_titlecaseTable[codePoint] = (of_unichar_t)[[components
		_titlecaseTable[codePoint] = (OFUnichar)[[components
		    objectAtIndex: 14] unsignedLongLongValueWithBase: 16];

		if ([[components objectAtIndex: 5] length] > 0) {
			OFArray *decomposed = [[components objectAtIndex: 5]
			    componentsSeparatedByString: @" "];
			bool compat = false;
			OFMutableString *string;

			if ([decomposed.firstObject hasPrefix: @"<"]) {
				decomposed = [decomposed objectsInRange:
				    of_range(1, decomposed.count - 1)];
				    OFMakeRange(1, decomposed.count - 1)];
				compat = true;
			}

			string = [OFMutableString string];

			for (OFString *character in decomposed) {
				of_unichar_t unichar = (of_unichar_t)[character
				OFUnichar unichar = (OFUnichar)[character
				    unsignedLongLongValueWithBase: 16];

				[string appendCharacters: &unichar
						  length: 1];
			}

			[string makeImmutable];
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
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







-
+
















-
+





-
+

















-
+

-
+







	OFString *line;

	[of_stdout writeString: @"Parsing CaseFolding.txt…"];

	while ((line = [response readLine]) != nil) {
		void *pool2;
		OFArray OF_GENERIC(OFString *) *components;
		of_unichar_t codePoint;
		OFUnichar codePoint;

		if (line.length == 0 || [line hasPrefix: @"#"])
			continue;

		pool2 = objc_autoreleasePoolPush();

		components = [line componentsSeparatedByString: @"; "];
		if (components.count != 4) {
			of_log(@"Invalid line: %s\n", line);
			[OFApplication terminateWithStatus: 1];
		}

		if (![[components objectAtIndex: 1] isEqual: @"S"] &&
		    ![[components objectAtIndex: 1] isEqual: @"C"])
			continue;

		codePoint = (of_unichar_t)[[components objectAtIndex: 0]
		codePoint = (OFUnichar)[[components objectAtIndex: 0]
		    unsignedLongLongValueWithBase: 16];

		if (codePoint > 0x10FFFF)
			@throw [OFOutOfRangeException exception];

		_casefoldingTable[codePoint] = (of_unichar_t)[[components
		_casefoldingTable[codePoint] = (OFUnichar)[[components
		    objectAtIndex: 2] unsignedLongLongValueWithBase: 16];

		objc_autoreleasePoolPop(pool2);
	}

	[of_stdout writeLine: @" done"];

	[self writeFiles];
}

- (void)applyDecompositionRecursivelyForTable: (OFString *[0x110000])table
{
	bool done;

	do {
		done = true;

		for (of_unichar_t i = 0; i < 0x110000; i++) {
		for (OFUnichar i = 0; i < 0x110000; i++) {
			void *pool;
			const of_unichar_t *characters;
			const OFUnichar *characters;
			size_t length;
			OFMutableString *replacement;
			bool changed = false;

			if (table[i] == nil)
				continue;

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
377
378
379

380
381
382

383
384
385
386

387
388
389
390
391
392
393
394
395
396
397

398
399
400
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420

421
422
423

424
425
426
427

428
429
430
431
432
433
434
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
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
377
378

379
380
381

382
383
384
385

386
387
388
389
390
391
392
393
394
395
396

397
398
399
400

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419

420
421
422

423
424
425
426

427
428
429
430
431
432
433
434
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







-
+




-
+


-
+











-
+



-
+


















-
+


-
+











-
+



-
+


















-
+


-
+



-
+










-
+



-
+


















-
+


-
+



-
+










-
+



-
+


















-
+


-
+
















-
+







	OFFile *file = [OFFile fileWithPath: path
				       mode: @"w"];

	[file writeString: COPYRIGHT
	    @"#include \"config.h\"\n"
	    @"\n"
	    @"#import \"OFString.h\"\n\n"
	    @"static const of_unichar_t emptyPage[0x100] = { 0 };\n"
	    @"static const OFUnichar emptyPage[0x100] = { 0 };\n"
	    @"static const char *emptyDecompositionPage[0x100] = { NULL };\n"
	    @"\n"];

	/* Write uppercasePage%u */
	for (of_unichar_t i = 0; i < 0x110000; i += 0x100) {
	for (OFUnichar i = 0; i < 0x110000; i += 0x100) {
		bool isEmpty = true;

		for (of_unichar_t j = i; j < i + 0x100; j++) {
		for (OFUnichar j = i; j < i + 0x100; j++) {
			if (_uppercaseTable[j] != 0) {
				isEmpty = false;
				_uppercaseTableSize = i >> 8;
				_uppercaseTableUsed[_uppercaseTableSize] = 1;
				break;
			}
		}

		if (!isEmpty) {
			void *pool2 = objc_autoreleasePoolPush();

			[file writeFormat: @"static const of_unichar_t "
			[file writeFormat: @"static const OFUnichar "
					   @"uppercasePage%u[0x100] = {\n",
					   i >> 8];

			for (of_unichar_t j = i; j < i + 0x100; j += 8)
			for (OFUnichar j = i; j < i + 0x100; j += 8)
				[file writeFormat:
				    @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n",
				    _uppercaseTable[j],
				    _uppercaseTable[j + 1],
				    _uppercaseTable[j + 2],
				    _uppercaseTable[j + 3],
				    _uppercaseTable[j + 4],
				    _uppercaseTable[j + 5],
				    _uppercaseTable[j + 6],
				    _uppercaseTable[j + 7]];

			[file writeString: @"};\n\n"];

			objc_autoreleasePoolPop(pool2);
		}
	}

	/* Write lowercasePage%u */
	for (of_unichar_t i = 0; i < 0x110000; i += 0x100) {
	for (OFUnichar i = 0; i < 0x110000; i += 0x100) {
		bool isEmpty = true;

		for (of_unichar_t j = i; j < i + 0x100; j++) {
		for (OFUnichar j = i; j < i + 0x100; j++) {
			if (_lowercaseTable[j] != 0) {
				isEmpty = false;
				_lowercaseTableSize = i >> 8;
				_lowercaseTableUsed[_lowercaseTableSize] = 1;
				break;
			}
		}

		if (!isEmpty) {
			void *pool2 = objc_autoreleasePoolPush();

			[file writeFormat: @"static const of_unichar_t "
			[file writeFormat: @"static const OFUnichar "
					   @"lowercasePage%u[0x100] = {\n",
					   i >> 8];

			for (of_unichar_t j = i; j < i + 0x100; j += 8)
			for (OFUnichar j = i; j < i + 0x100; j += 8)
				[file writeFormat:
				    @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n",
				    _lowercaseTable[j],
				    _lowercaseTable[j + 1],
				    _lowercaseTable[j + 2],
				    _lowercaseTable[j + 3],
				    _lowercaseTable[j + 4],
				    _lowercaseTable[j + 5],
				    _lowercaseTable[j + 6],
				    _lowercaseTable[j + 7]];

			[file writeString: @"};\n\n"];

			objc_autoreleasePoolPop(pool2);
		}
	}

	/* Write titlecasePage%u if it does NOT match uppercasePage%u */
	for (of_unichar_t i = 0; i < 0x110000; i += 0x100) {
	for (OFUnichar i = 0; i < 0x110000; i += 0x100) {
		bool isEmpty = true;

		for (of_unichar_t j = i; j < i + 0x100; j++) {
		for (OFUnichar j = i; j < i + 0x100; j++) {
			if (_titlecaseTable[j] != 0) {
				isEmpty = !memcmp(_uppercaseTable + i,
				    _titlecaseTable + i,
				    256 * sizeof(of_unichar_t));
				    256 * sizeof(OFUnichar));
				_titlecaseTableSize = i >> 8;
				_titlecaseTableUsed[_titlecaseTableSize] =
				    (isEmpty ? 2 : 1);
				break;
			}
		}

		if (!isEmpty) {
			void *pool2 = objc_autoreleasePoolPush();

			[file writeFormat: @"static const of_unichar_t "
			[file writeFormat: @"static const OFUnichar "
					   @"titlecasePage%u[0x100] = {\n",
					   i >> 8];

			for (of_unichar_t j = i; j < i + 0x100; j += 8)
			for (OFUnichar j = i; j < i + 0x100; j += 8)
				[file writeFormat:
				    @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n",
				    _titlecaseTable[j],
				    _titlecaseTable[j + 1],
				    _titlecaseTable[j + 2],
				    _titlecaseTable[j + 3],
				    _titlecaseTable[j + 4],
				    _titlecaseTable[j + 5],
				    _titlecaseTable[j + 6],
				    _titlecaseTable[j + 7]];

			[file writeString: @"};\n\n"];

			objc_autoreleasePoolPop(pool2);
		}
	}

	/* Write casefoldingPage%u if it does NOT match lowercasePage%u */
	for (of_unichar_t i = 0; i < 0x110000; i += 0x100) {
	for (OFUnichar i = 0; i < 0x110000; i += 0x100) {
		bool isEmpty = true;

		for (of_unichar_t j = i; j < i + 0x100; j++) {
		for (OFUnichar j = i; j < i + 0x100; j++) {
			if (_casefoldingTable[j] != 0) {
				isEmpty = !memcmp(_lowercaseTable + i,
				    _casefoldingTable + i,
				    256 * sizeof(of_unichar_t));
				    256 * sizeof(OFUnichar));
				_casefoldingTableSize = i >> 8;
				_casefoldingTableUsed[_casefoldingTableSize] =
				    (isEmpty ? 2 : 1);
				break;
			}
		}

		if (!isEmpty) {
			void *pool2 = objc_autoreleasePoolPush();

			[file writeFormat: @"static const of_unichar_t "
			[file writeFormat: @"static const OFUnichar "
					   @"casefoldingPage%u[0x100] = {\n",
					   i >> 8];

			for (of_unichar_t j = i; j < i + 0x100; j += 8)
			for (OFUnichar j = i; j < i + 0x100; j += 8)
				[file writeFormat:
				    @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n",
				    _casefoldingTable[j],
				    _casefoldingTable[j + 1],
				    _casefoldingTable[j + 2],
				    _casefoldingTable[j + 3],
				    _casefoldingTable[j + 4],
				    _casefoldingTable[j + 5],
				    _casefoldingTable[j + 6],
				    _casefoldingTable[j + 7]];

			[file writeString: @"};\n\n"];

			objc_autoreleasePoolPop(pool2);
		}
	}

	/* Write decompositionPage%u */
	for (of_unichar_t i = 0; i < 0x110000; i += 0x100) {
	for (OFUnichar i = 0; i < 0x110000; i += 0x100) {
		bool isEmpty = true;

		for (of_unichar_t j = i; j < i + 0x100; j++) {
		for (OFUnichar j = i; j < i + 0x100; j++) {
			if (_decompositionTable[j] != nil) {
				isEmpty = false;
				_decompositionTableSize = i >> 8;
				_decompositionTableUsed[
				    _decompositionTableSize] = 1;
				break;
			}
		}

		if (!isEmpty) {
			void *pool2 = objc_autoreleasePoolPush();

			[file writeFormat: @"static const char *const "
					   @"decompositionPage%u[0x100] = {\n",
					   i >> 8];

			for (of_unichar_t j = i; j < i + 0x100; j++) {
			for (OFUnichar j = i; j < i + 0x100; j++) {
				if ((j - i) % 2 == 0)
					[file writeString: @"\t"];
				else
					[file writeString: @" "];

				if (_decompositionTable[j] != nil) {
					const char *UTF8String =
508
509
510
511
512
513
514
515

516
517
518

519
520
521
522
523
524
525
508
509
510
511
512
513
514

515
516
517

518
519
520
521
522
523
524
525







-
+


-
+







			[file writeString: @"};\n\n"];

			objc_autoreleasePoolPop(pool2);
		}
	}

	/* Write decompCompatPage%u if it does NOT match decompositionPage%u */
	for (of_unichar_t i = 0; i < 0x110000; i += 0x100) {
	for (OFUnichar i = 0; i < 0x110000; i += 0x100) {
		bool isEmpty = true;

		for (of_unichar_t j = i; j < i + 0x100; j++) {
		for (OFUnichar j = i; j < i + 0x100; j++) {
			if (_decompositionCompatTable[j] != 0) {
				/*
				 * We bulk-compare pointers via memcmp here.
				 * This is safe, as we always set the same
				 * pointer in both tables if both are the same.
				 */
				isEmpty = !memcmp(_decompositionTable + i,
537
538
539
540
541
542
543
544

545
546
547
548
549
550
551
537
538
539
540
541
542
543

544
545
546
547
548
549
550
551







-
+







		if (!isEmpty) {
			void *pool2 = objc_autoreleasePoolPush();

			[file writeFormat: @"static const char *const "
					   @"decompCompatPage%u[0x100] = {\n",
					   i >> 8];

			for (of_unichar_t j = i; j < i + 0x100; j++) {
			for (OFUnichar j = i; j < i + 0x100; j++) {
				if ((j - i) % 2 == 0)
					[file writeString: @"\t"];
				else
					[file writeString: @" "];

				if (_decompositionCompatTable[j] != nil) {
					const char *UTF8String =
584
585
586
587
588
589
590
591

592
593
594
595

596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612

613
614
615
616

617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633

634
635
636
637

638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656

657
658
659
660

661
662
663
664
665
666
667
584
585
586
587
588
589
590

591
592
593
594

595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611

612
613
614
615

616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632

633
634
635
636

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655

656
657
658
659

660
661
662
663
664
665
666
667







-
+



-
+
















-
+



-
+
















-
+



-
+


















-
+



-
+







	_lowercaseTableSize++;
	_titlecaseTableSize++;
	_casefoldingTableSize++;
	_decompositionTableSize++;
	_decompositionCompatTableSize++;

	/* Write of_unicode_uppercase_table */
	[file writeFormat: @"const of_unichar_t *const "
	[file writeFormat: @"const OFUnichar *const "
			   @"of_unicode_uppercase_table[0x%X] = {\n\t",
			   _uppercaseTableSize];

	for (of_unichar_t i = 0; i < _uppercaseTableSize; i++) {
	for (OFUnichar i = 0; i < _uppercaseTableSize; i++) {
		if (_uppercaseTableUsed[i])
			[file writeFormat: @"uppercasePage%u", i];
		else
			[file writeString: @"emptyPage"];

		if (i + 1 < _uppercaseTableSize) {
			if ((i + 1) % 4 == 0)
				[file writeString: @",\n\t"];
			else
				[file writeString: @", "];
		}
	}

	[file writeString: @"\n};\n\n"];

	/* Write of_unicode_lowercase_table */
	[file writeFormat: @"const of_unichar_t *const "
	[file writeFormat: @"const OFUnichar *const "
			   @"of_unicode_lowercase_table[0x%X] = {\n\t",
			   _lowercaseTableSize];

	for (of_unichar_t i = 0; i < _lowercaseTableSize; i++) {
	for (OFUnichar i = 0; i < _lowercaseTableSize; i++) {
		if (_lowercaseTableUsed[i])
			[file writeFormat: @"lowercasePage%u", i];
		else
			[file writeString: @"emptyPage"];

		if (i + 1 < _lowercaseTableSize) {
			if ((i + 1) % 4 == 0)
				[file writeString: @",\n\t"];
			else
				[file writeString: @", "];
		}
	}

	[file writeString: @"\n};\n\n"];

	/* Write of_unicode_titlecase_table */
	[file writeFormat: @"const of_unichar_t *const "
	[file writeFormat: @"const OFUnichar *const "
			   @"of_unicode_titlecase_table[0x%X] = {\n\t",
			   _titlecaseTableSize];

	for (of_unichar_t i = 0; i < _titlecaseTableSize; i++) {
	for (OFUnichar i = 0; i < _titlecaseTableSize; i++) {
		if (_titlecaseTableUsed[i] == 1)
			[file writeFormat: @"titlecasePage%u", i];
		else if (_titlecaseTableUsed[i] == 2)
			[file writeFormat: @"uppercasePage%u", i];
		else
			[file writeString: @"emptyPage"];

		if (i + 1 < _titlecaseTableSize) {
			if ((i + 1) % 4 == 0)
				[file writeString: @",\n\t"];
			else
				[file writeString: @", "];
		}
	}

	[file writeString: @"\n};\n\n"];

	/* Write of_unicode_casefolding_table */
	[file writeFormat: @"const of_unichar_t *const "
	[file writeFormat: @"const OFUnichar *const "
			   @"of_unicode_casefolding_table[0x%X] = {\n\t",
			   _casefoldingTableSize];

	for (of_unichar_t i = 0; i < _casefoldingTableSize; i++) {
	for (OFUnichar i = 0; i < _casefoldingTableSize; i++) {
		if (_casefoldingTableUsed[i] == 1)
			[file writeFormat: @"casefoldingPage%u", i];
		else if (_casefoldingTableUsed[i] == 2)
			[file writeFormat: @"lowercasePage%u", i];
		else
			[file writeString: @"emptyPage"];

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







-
+







	[file writeString: @"\n};\n\n"];

	/* Write of_unicode_decomposition_table */
	[file writeFormat: @"const char *const "
			   @"*of_unicode_decomposition_table[0x%X] = {\n\t",
			   _decompositionTableSize];

	for (of_unichar_t i = 0; i < _decompositionTableSize; i++) {
	for (OFUnichar i = 0; i < _decompositionTableSize; i++) {
		if (_decompositionTableUsed[i])
			[file writeFormat: @"decompositionPage%u", i];
		else
			[file writeString: @"emptyDecompositionPage"];

		if (i + 1 < _decompositionTableSize) {
			if ((i + 1) % 3 == 0)
698
699
700
701
702
703
704
705

706
707
708
709
710
711
712
698
699
700
701
702
703
704

705
706
707
708
709
710
711
712







-
+








	/* Write of_unicode_decomposition_compat_table */
	[file writeFormat: @"const char *const "
			   @"*of_unicode_decomposition_compat_table[0x%X] = {"
			   @"\n\t",
			   _decompositionCompatTableSize];

	for (of_unichar_t i = 0; i < _decompositionCompatTableSize; i++) {
	for (OFUnichar i = 0; i < _decompositionCompatTableSize; i++) {
		if (_decompositionCompatTableUsed[i] == 1)
			[file writeFormat: @"decompCompatPage%u", i];
		else if (_decompositionCompatTableUsed[i] == 2)
			[file writeFormat: @"decompositionPage%u", i];
		else
			[file writeString: @"emptyDecompositionPage"];

743
744
745
746
747
748
749
750

751
752
753

754
755
756

757
758
759

760
761
762
763
764
765
766
743
744
745
746
747
748
749

750
751
752

753
754
755

756
757
758

759
760
761
762
763
764
765
766







-
+


-
+


-
+


-
+







	    _casefoldingTableSize, _decompositionTableSize,
	    _decompositionCompatTableSize];

	[file writeString:
	    @"#ifdef __cplusplus\n"
	    @"extern \"C\" {\n"
	    @"#endif\n"
	    @"extern const of_unichar_t *const _Nonnull\n"
	    @"extern const OFUnichar *const _Nonnull\n"
	    @"    of_unicode_uppercase_table["
	    @"OF_UNICODE_UPPERCASE_TABLE_SIZE];\n"
	    @"extern const of_unichar_t *const _Nonnull\n"
	    @"extern const OFUnichar *const _Nonnull\n"
	    @"    of_unicode_lowercase_table["
	    @"OF_UNICODE_LOWERCASE_TABLE_SIZE];\n"
	    @"extern const of_unichar_t *const _Nonnull\n"
	    @"extern const OFUnichar *const _Nonnull\n"
	    @"    of_unicode_titlecase_table["
	    @"OF_UNICODE_TITLECASE_TABLE_SIZE];\n"
	    @"extern const of_unichar_t *const _Nonnull\n"
	    @"extern const OFUnichar *const _Nonnull\n"
	    @"    of_unicode_casefolding_table["
	    @"OF_UNICODE_CASEFOLDING_TABLE_SIZE];\n"
	    @"extern const char *const _Nullable *const _Nonnull\n"
	    @"    of_unicode_decomposition_table["
	    @"OF_UNICODE_DECOMPOSITION_TABLE_SIZE];\n"
	    @"extern const char *const _Nullable *const _Nonnull\n"
	    @"    of_unicode_decomposition_compat_table["

Modified src/Makefile from [06838b11b3] to [45115139e9].

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







-













-
+

+







	    ${USE_INCLUDES_ATOMIC}

SRCS += OFAdjacentArray.m		\
	OFAdjacentSubarray.m		\
	OFBitSetCharacterSet.m		\
	OFBytesValue.m			\
	OFCountedMapTableSet.m		\
	OFDimensionValue.m		\
	OFInvertedCharacterSet.m	\
	OFLHADecompressingStream.m	\
	OFMapTableDictionary.m		\
	OFMapTableSet.m			\
	OFMutableAdjacentArray.m	\
	OFMutableMapTableDictionary.m	\
	OFMutableMapTableSet.m		\
	OFMutableUTF8String.m		\
	OFNonretainedObjectValue.m	\
	OFPointValue.m			\
	OFPointerValue.m		\
	OFRangeCharacterSet.m		\
	OFRangeValue.m			\
	OFRectangleValue.m		\
	OFRectValue.m			\
	OFSandbox.m			\
	OFSizeValue.m			\
	OFSubarray.m			\
	OFUTF8String.m			\
	${LIBBASES_M}			\
	${RUNTIME_AUTORELEASE_M}	\
	${RUNTIME_INSTANCE_M}
SRCS_FILES += OFFileURLHandler.m	\
	      OFINIFileSettings.m

Modified src/OFAdjacentArray.m from [0ad6ceaf6f] to [6b135eb930].

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







-
+


















-
+








-
+








-
+








-
+



-
+







}

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

- (void)getObjects: (id *)buffer inRange: (of_range_t)range
- (void)getObjects: (id *)buffer inRange: (OFRange)range
{
	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 const *objects;
	size_t count;

	if (object == nil)
		return OF_NOT_FOUND;
		return OFNotFound;

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

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

	if (object == nil)
		return OF_NOT_FOUND;
		return OFNotFound;

	objects = _array.items;
	count = _array.count;

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

	return OF_NOT_FOUND;
	return OFNotFound;
}


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

	if ([self isKindOfClass: [OFMutableArray class]])
		return [OFArray
312
313
314
315
316
317
318
319

320
321
322
323
324
325
326
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326







-
+







		OF_HASH_ADD_HASH(hash, [objects[i] hash]);

	OF_HASH_FINALIZE(hash);

	return hash;
}

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

	if (count > INT_MAX)
		/*
338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352







-
+







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

	return (int)count;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block
{
	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);

Modified src/OFAdjacentSubarray.m from [738b4fad30] to [188174c31a].

49
50
51
52
53
54
55
56

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

56
57
58
59
60
61
62
63
64
65







-
+









		if (![objects[i] isEqual: otherObjects[i]])
			return false;

	return true;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block
{
	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/OFApplication.m from [19384c303e] to [a312b9ee7c].

219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233







-
+







	@try {
		_environment = [[OFMutableDictionary alloc] init];

		atexit(atexitHandler);

#if defined(OF_WINDOWS)
		if ([OFSystemInfo isWindowsNT]) {
			of_char16_t *env, *env0;
			OFChar16 *env, *env0;
			env = env0 = GetEnvironmentStringsW();

			while (*env != 0) {
				void *pool = objc_autoreleasePoolPush();
				OFString *tmp, *key, *value;
				size_t length, pos;

243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257







-
+







				 */
				if ([tmp hasPrefix: @"="]) {
					objc_autoreleasePoolPop(pool);
					continue;
				}

				pos = [tmp rangeOfString: @"="].location;
				if (pos == OF_NOT_FOUND) {
				if (pos == OFNotFound) {
					fprintf(stderr,
					    "Warning: Invalid environment "
					    "variable: %s\n", tmp.UTF8String);
					continue;
				}

				key = [tmp substringToIndex: pos];
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
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







-
+




















-
+







				 */
				if ([tmp hasPrefix: @"="]) {
					objc_autoreleasePoolPop(pool);
					continue;
				}

				pos = [tmp rangeOfString: @"="].location;
				if (pos == OF_NOT_FOUND) {
				if (pos == OFNotFound) {
					fprintf(stderr,
					    "Warning: Invalid environment "
					    "variable: %s\n", tmp.UTF8String);
					continue;
				}

				key = [tmp substringToIndex: pos];
				value = [tmp substringFromIndex: pos + 1];
				[_environment setObject: value forKey: key];

				objc_autoreleasePoolPop(pool);
			}

			FreeEnvironmentStringsA(env0);
		}
#elif defined(OF_AMIGAOS)
		void *pool = objc_autoreleasePoolPush();
		OFFileManager *fileManager = [OFFileManager defaultManager];
		OFArray *envContents =
		    [fileManager contentsOfDirectoryAtPath: @"ENV:"];
		const of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];
		struct Process *proc;
		struct LocalVar *firstLocalVar;

		for (OFString *name in envContents) {
			void *pool2 = objc_autoreleasePoolPush();
			OFString *path, *value;
			OFFile *file;
372
373
374
375
376
377
378
379
380

381
382
383
384
385
386
387
372
373
374
375
376
377
378


379
380
381
382
383
384
385
386







-
-
+







# ifndef OF_MACOS
		char **env = environ;
# else
		char **env = *_NSGetEnviron();
# endif

		if (env != NULL) {
			const of_string_encoding_t encoding =
			    [OFLocale encoding];
			OFStringEncoding encoding = [OFLocale encoding];

			for (; *env != NULL; env++) {
				void *pool = objc_autoreleasePoolPush();
				OFString *key, *value;
				char *sep;

				if ((sep = strchr(*env, '=')) == NULL) {
464
465
466
467
468
469
470
471

472
473
474
475
476
477
478
463
464
465
466
467
468
469

470
471
472
473
474
475
476
477







-
+







	[super dealloc];
}

- (void)of_setArgumentCount: (int *)argc andArgumentValues: (char ***)argv
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableArray *arguments;
	of_string_encoding_t encoding;
	OFStringEncoding encoding;

	_argc = argc;
	_argv = argv;

	encoding = [OFLocale encoding];

#ifndef OF_NINTENDO_DS
603
604
605
606
607
608
609
610

611
612
613
614
615
616
617
602
603
604
605
606
607
608

609
610
611
612
613
614
615
616







-
+







}

#ifdef OF_HAVE_SANDBOX
- (void)of_activateSandbox: (OFSandbox *)sandbox
{
# ifdef OF_HAVE_PLEDGE
	void *pool = objc_autoreleasePoolPush();
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding 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];

Modified src/OFArray.h from [702817f9c0] to [091ccdd3f4].

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
31
32
33
34
35
36
37
38
39
40
41
42



43
44
45
46
47

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

61

62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95







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










-
+
-








-
+








-
+








-
+








OF_ASSUME_NONNULL_BEGIN

/** @file */

@class OFString;

/**
 * @brief Options for joining the objects of an array.
 *
 * This is a bit mask.
 */
enum {
	OF_ARRAY_SKIP_EMPTY = 1,
	OF_ARRAY_SORT_DESCENDING = 2
typedef enum OFArrayJoinOptions {
	/** Skip empty components */
	OFArraySkipEmptyComponents = 1
} OFArrayJoinOptions;

};
typedef enum OFArraySortOptions {
	OFArraySortDescending = 1
} OFArraySortOptions;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block for enumerating an OFArray.
 *
 * @param object The current object
 * @param index The index of the current object
 * @param stop A pointer to a variable that can be set to true to stop the
 *	       enumeration
 */
typedef void (^of_array_enumeration_block_t)(id object, size_t index,
typedef void (^OFArrayEnumerationBlock)(id object, size_t index, bool *stop);
    bool *stop);

/**
 * @brief A block for filtering an OFArray.
 *
 * @param object The object to inspect
 * @param index The index of the object to inspect
 * @return Whether the object should be in the filtered array
 */
typedef bool (^of_array_filter_block_t)(id object, size_t index);
typedef bool (^OFArrayFilterBlock)(id object, size_t index);

/**
 * @brief A block for mapping objects to objects in an OFArray.
 *
 * @param object The object to map
 * @param index The index of the object to map
 * @return The object to map to
 */
typedef id _Nonnull (^of_array_map_block_t)(id object, size_t index);
typedef id _Nonnull (^OFArrayMapBlock)(id object, size_t index);

/**
 * @brief A block for folding an OFArray.
 *
 * @param left The object to which the object has been folded so far
 * @param right The object that should be added to the left object
 * @return The left and right side folded into one object
 */
typedef id _Nullable (^of_array_fold_block_t)(id _Nullable left, id right);
typedef id _Nullable (^OFArrayFoldBlock)(id _Nullable left, id right);
#endif

/**
 * @class OFArray OFArray.h ObjFW/OFArray.h
 *
 * @brief An abstract class for storing objects in an array.
 *
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
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







-
+



-
+



-
+





-
+



-
+







/**
 * @brief Copies the objects at the specified range to the specified buffer.
 *
 * @param buffer The buffer to copy the objects to
 * @param range The range to copy
 */
- (void)getObjects: (ObjectType __unsafe_unretained _Nonnull *_Nonnull)buffer
	   inRange: (of_range_t)range;
	   inRange: (OFRange)range;

/**
 * @brief Returns the index of the first object that is equivalent to the
 *	  specified object or `OF_NOT_FOUND` if it was not found.
 *	  specified object or `OFNotFound` if it was not found.
 *
 * @param object The object whose index is returned
 * @return The index of the first object equivalent to the specified object
 *	   or `OF_NOT_FOUND` if it was not found
 *	   or `OFNotFound` if it was not found
 */
- (size_t)indexOfObject: (ObjectType)object;

/**
 * @brief Returns the index of the first object that has the same address as the
 *	  specified object or `OF_NOT_FOUND` if it was not found.
 *	  specified object or `OFNotFound` if it was not found.
 *
 * @param object The object whose index is returned
 * @return The index of the first object that has the same address as
 *	   the specified object or `OF_NOT_FOUND` if it was not found
 *	   the specified object or `OFNotFound` if it was not found
 */
- (size_t)indexOfObjectIdenticalTo: (ObjectType)object;

/**
 * @brief Checks whether the array contains an object equal to the specified
 *	  object.
 *
313
314
315
316
317
318
319
320

321
322
323
324
325
326
327
328
329
330
331
332
333
334

335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
369
370

371
372
373
374
375
376
377
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







-
+













-
+
-
-
-
-



-
+


















-
+
-
-
-
-




-
+








/**
 * @brief Returns the objects in the specified range as a new OFArray.
 *
 * @param range The range for the subarray
 * @return The subarray as a new autoreleased OFArray
 */
- (OFArray OF_GENERIC(ObjectType) *)objectsInRange: (of_range_t)range;
- (OFArray OF_GENERIC(ObjectType) *)objectsInRange: (OFRange)range;

/**
 * @brief Creates a string by joining all objects of the array.
 *
 * @param separator The string with which the objects should be joined
 * @return A string containing all objects joined by the separator
 */
- (OFString *)componentsJoinedByString: (OFString *)separator;

/**
 * @brief Creates a string by joining all objects of the array.
 *
 * @param separator The string with which the objects should be joined
 * @param options Options according to which the objects should be joined.@n
 * @param options Options according to which the objects should be joined
 *		  Possible values are:
 *		  Value                 | Description
 *		  ----------------------|----------------------
 * 		  `OF_ARRAY_SKIP_EMPTY` | Skip empty components
 * @return A string containing all objects joined by the separator
 */
- (OFString *)componentsJoinedByString: (OFString *)separator
			       options: (int)options;
			       options: (OFArrayJoinOptions)options;

/**
 * @brief Creates a string by calling the selector on all objects of the array
 *	  and joining the strings returned by calling the selector.
 *
 * @param separator The string with which the objects should be joined
 * @param selector The selector to perform on the objects
 * @return A string containing all objects joined by the separator
 */
- (OFString *)componentsJoinedByString: (OFString *)separator
			 usingSelector: (SEL)selector;

/**
 * @brief Creates a string by calling the selector on all objects of the array
 *	  and joining the strings returned by calling the selector.
 *
 * @param separator The string with which the objects should be joined
 * @param selector The selector to perform on the objects
 * @param options Options according to which the objects should be joined.@n
 * @param options Options according to which the objects should be joined
 *		  Possible values are:
 *		  Value                 | Description
 *		  ----------------------|----------------------
 * 		  `OF_ARRAY_SKIP_EMPTY` | Skip empty components
 * @return A string containing all objects joined by the separator
 */
- (OFString *)componentsJoinedByString: (OFString *)separator
			 usingSelector: (SEL)selector
			       options: (int)options;
			       options: (OFArrayJoinOptions)options;

/**
 * @brief Performs the specified selector on all objects in the array.
 *
 * @param selector The selector to perform on all objects in the array
 */
- (void)makeObjectsPerformSelector: (SEL)selector;
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
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







-
+
-
-
-
-


-
-
+
+
+







-
+
-
-
-
-



-
-
+
+








/**
 * @brief Returns a copy of the array sorted using the specified selector and
 *	  options.
 *
 * @param selector The selector to use to sort the array. It's signature
 *		   should be the same as that of -[compare:].
 * @param options The options to use when sorting the array.@n
 * @param options The options to use when sorting the array
 *		  Possible values are:
 *		  Value                      | Description
 *		  ---------------------------|-------------------------
 *		  `OF_ARRAY_SORT_DESCENDING` | Sort in descending order
 * @return A sorted copy of the array
 */
- (OFArray OF_GENERIC(ObjectType) *)sortedArrayUsingSelector: (SEL)selector
						     options: (int)options;
- (OFArray OF_GENERIC(ObjectType) *)
    sortedArrayUsingSelector: (SEL)selector
		     options: (OFArraySortOptions)options;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Returns a copy of the array sorted using the specified selector and
 *	  options.
 *
 * @param comparator The comparator to use to sort the array
 * @param options The options to use when sorting the array.@n
 * @param options The options to use when sorting the array
 *		  Possible values are:
 *		  Value                      | Description
 *		  ---------------------------|-------------------------
 *		  `OF_ARRAY_SORT_DESCENDING` | Sort in descending order
 * @return A sorted copy of the array
 */
- (OFArray OF_GENERIC(ObjectType) *)
    sortedArrayUsingComparator: (of_comparator_t)comparator
		       options: (int)options;
    sortedArrayUsingComparator: (OFComparator)comparator
		       options: (OFArraySortOptions)options;
#endif

/**
 * @brief Creates a new array with the specified object added.
 *
 * @param object The object to add
 * @return A new array with the specified object added
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
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







-
+







-
+










-
+

















-
+








#ifdef OF_HAVE_BLOCKS
/**
 * @brief Executes a block for each object.
 *
 * @param block The block to execute for each object
 */
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block;
- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block;

/**
 * @brief Creates a new array, mapping each object using the specified block.
 *
 * @param block A block which maps an object for each object
 * @return A new, autoreleased OFArray
 */
- (OFArray *)mappedArrayUsingBlock: (of_array_map_block_t)block;
- (OFArray *)mappedArrayUsingBlock: (OFArrayMapBlock)block;

/**
 * @brief Creates a new array, only containing the objects for which the block
 *	  returns true.
 *
 * @param block A block which determines if the object should be in the new
 *		array
 * @return A new, autoreleased OFArray
 */
- (OFArray OF_GENERIC(ObjectType) *)filteredArrayUsingBlock:
    (of_array_filter_block_t)block;
    (OFArrayFilterBlock)block;

/**
 * @brief Folds the array to a single object using the specified block.
 *
 * If the array is empty, it will return `nil`.
 *
 * If there is only one object in the array, that object will be returned and
 * the block will not be invoked.
 *
 * If there are at least two objects, the block is invoked for each object
 * except the first, where left is always to what the array has already been
 * folded and right what should be added to left.
 *
 * @param block A block which folds two objects into one, which is called for
 *		all objects except the first
 * @return The array folded to a single object
 */
- (nullable id)foldUsingBlock: (of_array_fold_block_t)block;
- (nullable id)foldUsingBlock: (OFArrayFoldBlock)block;
#endif
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef ObjectType
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFArray.m from [f6ae42a2d9] to [6fa2c5536f].

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







-
+











-
+







}

- (size_t)count
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)getObjects: (id *)buffer inRange: (of_range_t)range
- (void)getObjects: (id *)buffer inRange: (OFRange)range
{
	for (size_t i = 0; i < range.length; i++)
		buffer[i] = [self objectAtIndex: range.location + i];
}

- (id const *)objects
{
	size_t count = self.count;
	id *buffer = of_alloc(count, sizeof(id));

	@try {
		[self getObjects: buffer inRange: of_range(0, count)];
		[self getObjects: buffer inRange: OFMakeRange(0, count)];

		return [[OFData dataWithItemsNoCopy: buffer
					      count: count
					   itemSize: sizeof(id)
				       freeWhenDone: true] items];
	} @catch (id e) {
		free(buffer);
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
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







-
+








-
+







-
+








-
+




-
+




-
+




















-
+







}

- (size_t)indexOfObject: (id)object
{
	size_t i = 0;

	if (object == nil)
		return OF_NOT_FOUND;
		return OFNotFound;

	for (id objectIter in self) {
		if ([objectIter isEqual: object])
			return i;

		i++;
	}

	return OF_NOT_FOUND;
	return OFNotFound;
}

- (size_t)indexOfObjectIdenticalTo: (id)object
{
	size_t i = 0;

	if (object == nil)
		return OF_NOT_FOUND;
		return OFNotFound;

	for (id objectIter in self) {
		if (objectIter == object)
			return i;

		i++;
	}

	return OF_NOT_FOUND;
	return OFNotFound;
}

- (bool)containsObject: (id)object
{
	return ([self indexOfObject: object] != OF_NOT_FOUND);
	return ([self indexOfObject: object] != OFNotFound);
}

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

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

	return nil;
}

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

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

	return nil;
}

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

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







-
+
















-
+







{
	return [self componentsJoinedByString: separator
				usingSelector: @selector(description)
				      options: 0];
}

- (OFString *)componentsJoinedByString: (OFString *)separator
			       options: (int)options
			       options: (OFArrayJoinOptions)options
{
	return [self componentsJoinedByString: separator
				usingSelector: @selector(description)
				      options: options];
}

- (OFString *)componentsJoinedByString: (OFString *)separator
			 usingSelector: (SEL)selector
{
	return [self componentsJoinedByString: separator
				usingSelector: selector
				      options: 0];
}

- (OFString *)componentsJoinedByString: (OFString *)separator
			 usingSelector: (SEL)selector
			       options: (int)options
			       options: (OFArrayJoinOptions)options
{
	OFMutableString *ret;

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

	if (self.count == 0)
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
430
431
432
433
434
435
436

437
438
439
440
441
442
443
444







-
+







			@throw [OFInvalidArgumentException exception];

		return component;
	}

	ret = [OFMutableString string];

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

			if (component == nil)
				@throw [OFInvalidArgumentException exception];
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
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







-
+








-
-
+
+
















-
+



-
+







	OFMutableArray *new = [[self mutableCopy] autorelease];
	[new sort];
	[new makeImmutable];
	return new;
}

- (OFArray *)sortedArrayUsingSelector: (SEL)selector
			      options: (int)options
			      options: (OFArraySortOptions)options
{
	OFMutableArray *new = [[self mutableCopy] autorelease];
	[new sortUsingSelector: selector options: options];
	[new makeImmutable];
	return new;
}

#ifdef OF_HAVE_BLOCKS
- (OFArray *)sortedArrayUsingComparator: (of_comparator_t)comparator
				options: (int)options
- (OFArray *)sortedArrayUsingComparator: (OFComparator)comparator
				options: (OFArraySortOptions)options
{
	OFMutableArray *new = [[self mutableCopy] autorelease];
	[new sortUsingComparator: comparator options: options];
	[new makeImmutable];
	return new;
}
#endif

- (OFArray *)reversedArray
{
	OFMutableArray *new = [[self mutableCopy] autorelease];
	[new reverse];
	[new makeImmutable];
	return new;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	of_range_t range = of_range(state->state, count);
	OFRange range = OFMakeRange(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;

768
769
770
771
772
773
774
775

776
777
778
779
780
781
782
768
769
770
771
772
773
774

775
776
777
778
779
780
781
782







-
+







- (OFEnumerator *)objectEnumerator
{
	return [[[OFArrayEnumerator alloc] initWithArray: self
					    mutationsPtr: NULL] autorelease];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block
{
	size_t i = 0;
	bool stop = false;

	for (id object in self) {
		block(object, i++, &stop);

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







-
+



















-
+







	OFMutableArray *ret = [[self mutableCopy] autorelease];
	[ret removeObject: object];
	[ret makeImmutable];
	return ret;
}

#ifdef OF_HAVE_BLOCKS
- (OFArray *)mappedArrayUsingBlock: (of_array_map_block_t)block
- (OFArray *)mappedArrayUsingBlock: (OFArrayMapBlock)block
{
	OFArray *ret;
	size_t count = self.count;
	id *tmp = of_alloc(count, sizeof(id));

	@try {
		[self enumerateObjectsUsingBlock: ^ (id object, size_t idx,
		    bool *stop) {
			tmp[idx] = block(object, idx);
		}];

		ret = [OFArray arrayWithObjects: tmp count: count];
	} @finally {
		free(tmp);
	}

	return ret;
}

- (OFArray *)filteredArrayUsingBlock: (of_array_filter_block_t)block
- (OFArray *)filteredArrayUsingBlock: (OFArrayFilterBlock)block
{
	OFArray *ret;
	size_t count = self.count;
	id *tmp = of_alloc(count, sizeof(id));

	@try {
		__block size_t i = 0;
857
858
859
860
861
862
863
864

865
866
867
868
869
870
871
857
858
859
860
861
862
863

864
865
866
867
868
869
870
871







-
+







	} @finally {
		free(tmp);
	}

	return ret;
}

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

	if (count == 0)
		return nil;
	if (count == 1)

Modified src/OFBitSetCharacterSet.m from [54df15f988] to [7f7124f1b9].

28
29
30
31
32
33
34
35

36
37
38
39

40
41
42
43
44
45
46
28
29
30
31
32
33
34

35
36
37
38

39
40
41
42
43
44
45
46







-
+



-
+








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

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

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

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

				if (UINT32_MAX - c < 1)
					@throw [OFOutOfRangeException
					    exception];
69
70
71
72
73
74
75
76

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

76
77
78
79
80
81
82
83







-
+







- (void)dealloc
{
	free(_bitset);

	[super dealloc];
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character / CHAR_BIT >= _size)
		return false;

	return of_bitset_isset(_bitset, character);
}
@end

Modified src/OFCharacterSet.h from [213677c26a] to [718ebc3831].

52
53
54
55
56
57
58
59

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

59
60
61
62
63
64
65
66







-
+







/**
 * @brief Creates a new character set containing the characters in the specified
 *	  range.
 *
 * @param range The range of characters for the character set
 * @return A new OFCharacterSet
 */
+ (instancetype)characterSetWithRange: (of_range_t)range;
+ (instancetype)characterSetWithRange: (OFRange)range;

/**
 * @brief A character set containing all Unicode characters in the category
 *	  `Zs` plus CHARACTER TABULATION (U+0009).
 */
+ (OFCharacterSet *)whitespaceCharacterSet;

76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93

94
95
96
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90
91
92

93
94
95
96







-
+









-
+



/**
 * @brief Initializes an already allocated character set with the characters in
 *	  the specified range.
 *
 * @param range The range of characters for the character set
 * @return An initialized OFCharacterSet
 */
- (instancetype)initWithRange: (of_range_t)range;
- (instancetype)initWithRange: (OFRange)range;

/**
 * @brief Returns whether the specified character is a member of the character
 *	  set.
 *
 * @param character The character that is checked for being a member of the
 *		    character set
 * @return Whether the specified character is a member of the character set.
 */
- (bool)characterIsMember: (of_unichar_t)character;
- (bool)characterIsMember: (OFUnichar)character;
@end

OF_ASSUME_NONNULL_END

Modified src/OFCharacterSet.m from [e06618edef] to [caa2e9d748].

48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62







-
+








- (instancetype)initWithCharactersInString: (OFString *)characters
{
	return (id)[[OFBitSetCharacterSet alloc]
	    initWithCharactersInString: characters];
}

- (instancetype)initWithRange: (of_range_t)range
- (instancetype)initWithRange: (OFRange)range
{
	return (id)[[OFRangeCharacterSet alloc] initWithRange: range];
}

- (instancetype)retain
{
	return self;
96
97
98
99
100
101
102
103

104
105
106
107
108
109
110
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110







-
+








+ (instancetype)characterSetWithCharactersInString: (OFString *)characters
{
	return [[[self alloc] initWithCharactersInString: characters]
	    autorelease];
}

+ (instancetype)characterSetWithRange: (of_range_t)range
+ (instancetype)characterSetWithRange: (OFRange)range
{
	return [[[self alloc] initWithRange: range] autorelease];
}

+ (OFCharacterSet *)whitespaceCharacterSet
{
	static of_once_t onceControl = OF_ONCE_INIT;
130
131
132
133
134
135
136
137

138
139
140
141
142

143
144
145
146
147
148
149
130
131
132
133
134
135
136

137
138
139
140
141

142
143
144
145
146
147
148
149







-
+




-
+







}

- (instancetype)initWithCharactersInString: (OFString *)characters
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithRange: (of_range_t)range
- (instancetype)initWithRange: (OFRange)range
{
	OF_INVALID_INIT_METHOD
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	OF_UNRECOGNIZED_SELECTOR
}

- (OFCharacterSet *)invertedSet
{
	return [[[OFInvertedCharacterSet alloc]
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







-
+







}

- (unsigned int)retainCount
{
	return OF_RETAIN_COUNT_MAX;
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	switch (character) {
	case 0x0009:
	case 0x0020:
	case 0x00A0:
	case 0x1680:
	case 0x2000:

Modified src/OFCondition.h from [7e6ce2a6b1] to [24d692e490].

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







-
+













-
+







 *
 * @note Waiting might have been interrupted by a signal. It is thus recommended
 *	 to check the condition again after @ref waitForTimeInterval: returned!
 *
 * @param timeInterval The time interval until the timeout is reached
 * @return Whether the condition has been signaled
 */
- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval;
- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval;

#ifdef OF_AMIGAOS
/**
 * @brief Blocks the current thread until another thread calls @ref signal,
 *	  @ref broadcast, the timeout is reached or an Exec Signal is received.
 *
 * @note This is only available on AmigaOS!
 *
 * @param timeInterval The time interval until the timeout is reached
 * @param signalMask A pointer to a signal mask of Exec Signals to receive.
 *		     This is modified and set to the mask of signals received.
 * @return Whether the condition has been signaled or a signal received
 */
- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval
- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval
	       orExecSignal: (ULONG *)signalMask;
#endif

/**
 * @brief Blocks the current thread until another thread calls @ref signal,
 *	  @ref broadcast or the timeout is reached.
 *

Modified src/OFCondition.m from [a2bba1aee6] to [4b58a9908d].

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







-
+















-
+







	if (error != 0)
		@throw [OFConditionWaitFailedException
		    exceptionWithCondition: self
				     errNo: error];
}
#endif

- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval
- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval
{
	int error = of_condition_timed_wait(&_condition, &_mutex, timeInterval);

	if (error == ETIMEDOUT)
		return false;

	if (error != 0)
		@throw [OFConditionWaitFailedException
		    exceptionWithCondition: self
				     errNo: error];

	return true;
}

#ifdef OF_AMIGAOS
- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval
- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval
	       orExecSignal: (ULONG *)signalMask
{
	int error = of_condition_timed_wait_or_signal(&_condition, &_mutex,
	    timeInterval, signalMask);

	if (error == ETIMEDOUT)
		return false;

Modified src/OFConstantString.m from [b52e6a55a7] to [c17936e454].

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







-
+







- (id)mutableCopy
{
	[self finishInitialization];
	return [self mutableCopy];
}

/* From protocol OFComparing,  but overridden in OFString */
- (of_comparison_result_t)compare: (OFString *)string
- (OFComparisonResult)compare: (OFString *)string
{
	[self finishInitialization];
	return [self compare: string];
}

/* From OFObject, but reimplemented in OFString */
- (bool)isEqual: (id)object
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
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
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
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







-
+







-
+

















-
+





-
+





-
+





-
+





-
+





-
+
+





-
-
-
+
+
+












-
+






-
-
+
+







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

- (size_t)getCString: (char *)cString_
	   maxLength: (size_t)maxLength
	    encoding: (of_string_encoding_t)encoding
	    encoding: (OFStringEncoding)encoding
{
	[self finishInitialization];
	return [self getCString: cString_
		      maxLength: maxLength
		       encoding: encoding];
}

- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)cStringWithEncoding: (OFStringEncoding)encoding
{
	[self finishInitialization];
	return [self cStringWithEncoding: encoding];
}

- (size_t)length
{
	[self finishInitialization];
	return self.length;
}

- (size_t)UTF8StringLength
{
	[self finishInitialization];
	return self.UTF8StringLength;
}

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

- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)string
- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string
{
	[self finishInitialization];
	return [self caseInsensitiveCompare: string];
}

- (of_unichar_t)characterAtIndex: (size_t)idx
- (OFUnichar)characterAtIndex: (size_t)idx
{
	[self finishInitialization];
	return [self characterAtIndex: idx];
}

- (void)getCharacters: (of_unichar_t *)buffer inRange: (of_range_t)range
- (void)getCharacters: (OFUnichar *)buffer inRange: (OFRange)range
{
	[self finishInitialization];
	[self getCharacters: buffer inRange: range];
}

- (of_range_t)rangeOfString: (OFString *)string
- (OFRange)rangeOfString: (OFString *)string
{
	[self finishInitialization];
	return [self rangeOfString: string];
}

- (of_range_t)rangeOfString: (OFString *)string options: (int)options
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options
{
	[self finishInitialization];
	return [self rangeOfString: string options: options];
}

- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
		      range: (of_range_t)range
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options
		   range: (OFRange)range
{
	[self finishInitialization];
	return [self rangeOfString: string options: options range: range];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
{
	[self finishInitialization];
	return [self indexOfCharacterFromSet: characterSet];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
			  options: (OFStringSearchOptions)options
{
	[self finishInitialization];
	return [self indexOfCharacterFromSet: characterSet options: options];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
			    range: (of_range_t)range
			  options: (OFStringSearchOptions)options
			    range: (OFRange)range
{
	[self finishInitialization];
	return [self indexOfCharacterFromSet: characterSet
				     options: options
				       range: range];
}

320
321
322
323
324
325
326
327

328
329
330
331
332
333
334
321
322
323
324
325
326
327

328
329
330
331
332
333
334
335







-
+








- (OFString *)substringToIndex: (size_t)idx
{
	[self finishInitialization];
	return [self substringToIndex: idx];
}

- (OFString *)substringWithRange: (of_range_t)range
- (OFString *)substringWithRange: (OFRange)range
{
	[self finishInitialization];
	return [self substringWithRange: range];
}

- (OFString *)stringByAppendingString: (OFString *)string
{
362
363
364
365
366
367
368
369

370
371
372
373
374
375
376
363
364
365
366
367
368
369

370
371
372
373
374
375
376
377







-
+







	return [self stringByReplacingOccurrencesOfString: string
					       withString: replacement];
}

- (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string
					withString: (OFString *)replacement
					   options: (int)options
					     range: (of_range_t)range
					     range: (OFRange)range
{
	[self finishInitialization];
	return [self stringByReplacingOccurrencesOfString: string
					       withString: replacement
						  options: options
						    range: range];
}
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
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







-
+














-
+







- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
{
	[self finishInitialization];
	return [self componentsSeparatedByString: delimiter];
}

- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
				 options: (int)options
				 options: (OFStringSeparationOptions)options
{
	[self finishInitialization];
	return [self componentsSeparatedByString: delimiter options: options];
}

- (OFArray *)
    componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet
{
	[self finishInitialization];
	return [self componentsSeparatedByCharactersInSet: characterSet];
}

- (OFArray *)
    componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet
				 options: (int)options
				 options: (OFStringSeparationOptions)options
{
	[self finishInitialization];
	return [self componentsSeparatedByCharactersInSet: characterSet
						  options: options];
}

- (OFArray *)pathComponents
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
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







-
+





-
+





-
+











-
+





-
+





-
+








- (double)doubleValue
{
	[self finishInitialization];
	return self.doubleValue;
}

- (const of_unichar_t *)characters
- (const OFUnichar *)characters
{
	[self finishInitialization];
	return self.characters;
}

- (const of_char16_t *)UTF16String
- (const OFChar16 *)UTF16String
{
	[self finishInitialization];
	return self.UTF16String;
}

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

- (size_t)UTF16StringLength
{
	[self finishInitialization];
	return self.UTF16StringLength;
}

- (const of_char32_t *)UTF32String
- (const OFChar32 *)UTF32String
{
	[self finishInitialization];
	return self.UTF32String;
}

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

- (OFData *)dataWithEncoding: (of_string_encoding_t)encoding
- (OFData *)dataWithEncoding: (OFStringEncoding)encoding
{
	[self finishInitialization];
	return [self dataWithEncoding: encoding];
}

#ifdef OF_HAVE_UNICODE_TABLES
- (OFString *)decomposedStringWithCanonicalMapping
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
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







-
+












-
+






-
+






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

- (void)writeToFile: (OFString *)path encoding: (of_string_encoding_t)encoding
- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding
{
	[self finishInitialization];
	[self writeToFile: path encoding: encoding];
}
#endif

- (void)writeToURL: (OFURL *)URL
{
	[self finishInitialization];
	[self writeToURL: URL];
}

- (void)writeToURL: (OFURL *)URL encoding: (of_string_encoding_t)encoding
- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding
{
	[self finishInitialization];
	[self writeToURL: URL encoding: encoding];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block
{
	[self finishInitialization];
	[self enumerateLinesUsingBlock: block];
}
#endif
@end

Modified src/OFCountedMapTableSet.m from [1688e99723] to [00546e8e62].

165
166
167
168
169
170
171
172

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

172

173
174
175
176
177
178
179







-
+
-








- (size_t)countForObject: (id)object
{
	return (size_t)(uintptr_t)[_mapTable objectForKey: object];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsAndCountUsingBlock:
- (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block
    (of_counted_set_enumeration_block_t)block
{
	@try {
		[_mapTable enumerateKeysAndObjectsUsingBlock:
		    ^ (void *key, void *object, bool *stop) {
			block(key, (size_t)(uintptr_t)object, stop);
		}];
	} @catch (OFEnumerationMutationException *e) {

Modified src/OFCountedSet.h from [d5fbc7df8a] to [aa07eb172d].

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







-
+







 * @brief A block for enumerating an OFCountedSet.
 *
 * @param object The current object
 * @param count The count of the object
 * @param stop A pointer to a variable that can be set to true to stop the
 *	       enumeration
 */
typedef void (^of_counted_set_enumeration_block_t)(id object, size_t count,
typedef void (^OFCountedSetEnumerationBlock)(id object, size_t count,
    bool *stop);
#endif

/**
 * @class OFCountedSet OFCountedSet.h ObjFW/OFCountedSet.h
 *
 * @brief An abstract class for a mutable unordered set of objects, counting how
55
56
57
58
59
60
61
62

63
64
65
66
67
68
69
70
55
56
57
58
59
60
61

62

63
64
65
66
67
68
69







-
+
-








#ifdef OF_HAVE_BLOCKS
/**
 * @brief Executes a block for each object in the set.
 *
 * @param block The block to execute for each object in the set
 */
- (void)enumerateObjectsAndCountUsingBlock:
- (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block;
    (of_counted_set_enumeration_block_t)block;
#endif
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef ObjectType
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFCountedSet.m from [d6c7218230] to [fe3c7716dc].

210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225
210
211
212
213
214
215
216

217

218
219
220
221
222
223
224







-
+
-








	objc_autoreleasePoolPop(pool);

	return [element autorelease];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsAndCountUsingBlock:
- (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block
    (of_counted_set_enumeration_block_t)block
{
	[self enumerateObjectsUsingBlock: ^ (id object, bool *stop) {
		block(object, [self countForObject: object], stop);
	}];
}
#endif

Modified src/OFDNSResolver.h from [c467730d8f] to [a855f12ad3].

97
98
99
100
101
102
103
104

105
106
107
108
109
110
111
97
98
99
100
101
102
103

104
105
106
107
108
109
110
111







-
+







@protocol OFDNSResolverHostDelegate <OFObject>
/**
 * @brief This method is called when a DNS resolver resolved a host to
 *	  addresses.
 *
 * @param resolver The acting resolver
 * @param host The host the resolver resolved
 * @param addresses OFData containing several of_socket_address_t
 * @param addresses OFData containing several OFSocketAddress
 * @param exception The exception that occurred during resolving, or nil on
 *		    success
 */
- (void)resolver: (OFDNSResolver *)resolver
  didResolveHost: (OFString *)host
       addresses: (nullable OFData *)addresses
       exception: (nullable id)exception;
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175







-
+







 */
@property (copy, nonatomic) OFArray OF_GENERIC(OFString *) *searchDomains;

/**
 * @brief The timeout, in seconds, after which the next name server should be
 *	  tried.
 */
@property (nonatomic) of_time_interval_t timeout;
@property (nonatomic) OFTimeInterval timeout;

/**
 * @brief The number of attempts before giving up to resolve a host.
 *
 * Trying all name servers once is considered a single attempt.
 */
@property (nonatomic) unsigned int maxAttempts;
185
186
187
188
189
190
191
192

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

192
193
194
195
196
197
198
199







-
+







@property (nonatomic) bool usesTCP;

/**
 * @brief The interval in seconds in which the config should be reloaded.
 *
 * Setting this to 0 disables config reloading.
 */
@property (nonatomic) of_time_interval_t configReloadInterval;
@property (nonatomic) OFTimeInterval configReloadInterval;

/**
 * @brief Creates a new, autoreleased OFDNSResolver.
 */
+ (instancetype)resolver;

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







-
+



















-
+











-
-
+
+







-
+


-
+








 * @brief Asynchronously performs the specified query.
 *
 * @param query The query to perform
 * @param runLoopMode The run loop mode in which to resolve
 * @param delegate The delegate to use for callbacks
 */
- (void)asyncPerformQuery: (OFDNSQuery *)query
	      runLoopMode: (of_run_loop_mode_t)runLoopMode
	      runLoopMode: (OFRunLoopMode)runLoopMode
		 delegate: (id <OFDNSResolverQueryDelegate>)delegate;

/**
 * @brief Asynchronously resolves the specified host to socket addresses.
 *
 * @param host The host to resolve
 * @param delegate The delegate to use for callbacks
 */
- (void)asyncResolveAddressesForHost: (OFString *)host
			    delegate: (id <OFDNSResolverHostDelegate>)delegate;

/**
 * @brief Asynchronously resolves the specified host to socket addresses.
 *
 * @param host The host to resolve
 * @param addressFamily The desired socket address family
 * @param delegate The delegate to use for callbacks
 */
- (void)asyncResolveAddressesForHost: (OFString *)host
		       addressFamily: (of_socket_address_family_t)addressFamily
		       addressFamily: (OFSocketAddressFamily)addressFamily
			    delegate: (id <OFDNSResolverHostDelegate>)delegate;

/**
 * @brief Asynchronously resolves the specified host to socket addresses.
 *
 * @param host The host to resolve
 * @param addressFamily The desired socket address family
 * @param runLoopMode The run loop mode in which to resolve
 * @param delegate The delegate to use for callbacks
 */
- (void)asyncResolveAddressesForHost: (OFString *)host
		       addressFamily: (of_socket_address_family_t)addressFamily
			 runLoopMode: (of_run_loop_mode_t)runLoopMode
		       addressFamily: (OFSocketAddressFamily)addressFamily
			 runLoopMode: (OFRunLoopMode)runLoopMode
			    delegate: (id <OFDNSResolverHostDelegate>)delegate;

/**
 * @brief Synchronously resolves the specified host to socket addresses.
 *
 * @param host The host to resolve
 * @param addressFamily The desired socket address family
 * @return OFData containing several of_socket_address_t
 * @return OFData containing several OFSocketAddress
 */
- (OFData *)resolveAddressesForHost: (OFString *)host
		      addressFamily: (of_socket_address_family_t)addressFamily;
		      addressFamily: (OFSocketAddressFamily)addressFamily;

/**
 * @brief Closes all sockets and cancels all ongoing queries.
 */
- (void)close;
@end

OF_ASSUME_NONNULL_END

Modified src/OFDNSResolver.m from [536c83ec11] to [33f15c9fa5].

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







-
+







	OFDNSQuery *_query;
	OFNumber *_ID;
	OFDNSResolverSettings *_settings;
	size_t _nameServersIndex;
	unsigned int _attempt;
	id <OFDNSResolverQueryDelegate> _delegate;
	OFData *_queryData;
	of_socket_address_t _usedNameServer;
	OFSocketAddress _usedNameServer;
	OFTCPSocket *_TCPSocket;
	OFMutableData *_TCPQueryData;
	void *_TCPBuffer;
	size_t _responseLength;
	OFTimer *_cancelTimer;
}

169
170
171
172
173
174
175
176

177
178
179
180
181
182

183
184
185
186
187
188
189
169
170
171
172
173
174
175

176
177
178
179
180
181

182
183
184
185
186
187
188
189







-
+





-
+








static OF_KINDOF(OFDNSResourceRecord *)
parseResourceRecord(OFString *name, of_dns_class_t DNSClass,
    of_dns_record_type_t recordType, uint32_t TTL, const unsigned char *buffer,
    size_t length, size_t i, uint16_t dataLength)
{
	if (recordType == OF_DNS_RECORD_TYPE_A && DNSClass == OF_DNS_CLASS_IN) {
		of_socket_address_t address;
		OFSocketAddress address;

		if (dataLength != 4)
			@throw [OFInvalidServerReplyException exception];

		memset(&address, 0, sizeof(address));
		address.family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
		address.family = OFSocketAddressFamilyIPv4;
		address.length = sizeof(address.sockaddr.in);

		address.sockaddr.in.sin_family = AF_INET;
		memcpy(&address.sockaddr.in.sin_addr.s_addr, buffer + i, 4);

		return [[[OFADNSResourceRecord alloc]
		    initWithName: name
356
357
358
359
360
361
362
363

364
365
366
367
368
369

370
371
372
373
374
375
376
356
357
358
359
360
361
362

363
364
365
366
367
368

369
370
371
372
373
374
375
376







-
+





-
+







		     initWithName: name
			 DNSClass: DNSClass
			  mailbox: mailbox
		    TXTDomainName: TXTDomainName
			      TTL: TTL] autorelease];
	} else if (recordType == OF_DNS_RECORD_TYPE_AAAA &&
	    DNSClass == OF_DNS_CLASS_IN) {
		of_socket_address_t address;
		OFSocketAddress address;

		if (dataLength != 16)
			@throw [OFInvalidServerReplyException exception];

		memset(&address, 0, sizeof(address));
		address.family = OF_SOCKET_ADDRESS_FAMILY_IPV6;
		address.family = OFSocketAddressFamilyIPv6;
		address.length = sizeof(address.sockaddr.in6);

#ifdef AF_INET6
		address.sockaddr.in6.sin6_family = AF_INET6;
#else
		address.sockaddr.in6.sin6_family = AF_UNSPEC;
#endif
643
644
645
646
647
648
649
650

651
652
653
654
655

656
657
658
659
660
661
662
643
644
645
646
647
648
649

650
651
652
653
654

655
656
657
658
659
660
661
662







-
+




-
+







- (void)setSearchDomains: (OFArray *)searchDomains
{
	OFArray *old = _settings->_searchDomains;
	_settings->_searchDomains = [searchDomains copy];
	[old release];
}

- (of_time_interval_t)timeout
- (OFTimeInterval)timeout
{
	return _settings->_timeout;
}

- (void)setTimeout: (of_time_interval_t)timeout
- (void)setTimeout: (OFTimeInterval)timeout
{
	_settings->_timeout = timeout;
}

- (unsigned int)maxAttempts
{
	return _settings->_maxAttempts;
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
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







-
+




-
+





-
+







}

- (void)setUsesTCP: (bool)usesTCP
{
	_settings->_usesTCP = usesTCP;
}

- (of_time_interval_t)configReloadInterval
- (OFTimeInterval)configReloadInterval
{
	return _settings->_configReloadInterval;
}

- (void)setConfigReloadInterval: (of_time_interval_t)configReloadInterval
- (void)setConfigReloadInterval: (OFTimeInterval)configReloadInterval
{
	_settings->_configReloadInterval = configReloadInterval;
}

- (void)of_sendQueryForContext: (OFDNSResolverContext *)context
		   runLoopMode: (of_run_loop_mode_t)runLoopMode
		   runLoopMode: (OFRunLoopMode)runLoopMode
{
	OFUDPSocket *sock;
	OFString *nameServer;

	[_queries setObject: context forKey: context->_ID];

	[context->_cancelTimer invalidate];
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
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







-
+



-
+

-
-
+
+











-
+

-
-
+
+







		context->_TCPSocket.delegate = self;
		[context->_TCPSocket asyncConnectToHost: nameServer
						   port: 53
					    runLoopMode: runLoopMode];
		return;
	}

	context->_usedNameServer = of_socket_address_parse_ip(nameServer, 53);
	context->_usedNameServer = OFSocketAddressParseIP(nameServer, 53);

	switch (context->_usedNameServer.family) {
#ifdef OF_HAVE_IPV6
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
	case OFSocketAddressFamilyIPv6:
		if (_IPv6Socket == nil) {
			of_socket_address_t address =
			    of_socket_address_parse_ip(@"::", 0);
			OFSocketAddress address =
			    OFSocketAddressParseIPv6(@"::", 0);

			_IPv6Socket = [[OFUDPSocket alloc] init];
			[_IPv6Socket of_bindToAddress: &address
					    extraType: SOCK_DNS];
			_IPv6Socket.canBlock = false;
			_IPv6Socket.delegate = self;
		}

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

			_IPv4Socket = [[OFUDPSocket alloc] init];
			[_IPv4Socket of_bindToAddress: &address
					    extraType: SOCK_DNS];
			_IPv4Socket.canBlock = false;
			_IPv4Socket.delegate = self;
		}
782
783
784
785
786
787
788
789

790
791
792
793
794

795
796
797
798
799
800
801
782
783
784
785
786
787
788

789
790
791
792
793

794
795
796
797
798
799
800
801







-
+




-
+







			 runLoopMode: runLoopMode];
}

- (void)asyncPerformQuery: (OFDNSQuery *)query
		 delegate: (id <OFDNSResolverQueryDelegate>)delegate
{
	[self asyncPerformQuery: query
		    runLoopMode: of_run_loop_mode_default
		    runLoopMode: OFDefaultRunLoopMode
		       delegate: delegate];
}

- (void)asyncPerformQuery: (OFDNSQuery *)query
	      runLoopMode: (of_run_loop_mode_t)runLoopMode
	      runLoopMode: (OFRunLoopMode)runLoopMode
		 delegate: (id <OFDNSResolverQueryDelegate>)delegate
{
	void *pool = objc_autoreleasePoolPush();
	OFNumber *ID;
	OFDNSResolverContext *context;

	/* Random, unused ID */
825
826
827
828
829
830
831
832

833
834
835
836
837
838
839
825
826
827
828
829
830
831

832
833
834
835
836
837
838
839







-
+







	[self of_sendQueryForContext: context runLoopMode: runLoopMode];

	objc_autoreleasePoolPop(pool);
}

- (void)of_contextTimedOut: (OFDNSResolverContext *)context
{
	of_run_loop_mode_t runLoopMode = [OFRunLoop currentRunLoop].currentMode;
	OFRunLoopMode runLoopMode = [OFRunLoop currentRunLoop].currentMode;
	OFDNSQueryFailedException *exception;

	if (context->_TCPSocket != nil) {
		context->_TCPSocket.delegate = nil;
		[context->_TCPSocket cancelAsyncRequests];

		[_TCPQueries removeObjectForKey: context->_TCPSocket];
877
878
879
880
881
882
883
884

885
886
887
888
889
890
891
877
878
879
880
881
882
883

884
885
886
887
888
889
890
891







-
+







		     didPerformQuery: context->_query
			    response: nil
			   exception: exception];
}

- (bool)of_handleResponseBuffer: (unsigned char *)buffer
			 length: (size_t)length
			 sender: (const of_socket_address_t *)sender
			 sender: (const OFSocketAddress *)sender
{
	OFDictionary *answerRecords = nil, *authorityRecords = nil;
	OFDictionary *additionalRecords = nil;
	OFDNSResponse *response = nil;
	id exception = nil;
	OFNumber *ID;
	OFDNSResolverContext *context;
899
900
901
902
903
904
905
906

907
908
909
910
911
912
913
899
900
901
902
903
904
905

906
907
908
909
910
911
912
913







-
+








	if (context == nil)
		return true;

	if (context->_TCPSocket != nil) {
		if ([_TCPQueries objectForKey: context->_TCPSocket] != context)
			return true;
	} else if (!of_socket_address_equal(sender, &context->_usedNameServer))
	} else if (!OFSocketAddressEqual(sender, &context->_usedNameServer))
		return true;

	[context->_cancelTimer invalidate];
	[context->_cancelTimer release];
	context->_cancelTimer = nil;
	[_queries removeObjectForKey: ID];

934
935
936
937
938
939
940
941

942
943
944
945
946
947
948
934
935
936
937
938
939
940

941
942
943
944
945
946
947
948







-
+








		/* Opcode */
		if ((buffer[2] & 0x78) != (queryDataBuffer[2] & 0x78))
			@throw [OFInvalidServerReplyException exception];

		/* TC */
		if (buffer[2] & 0x02) {
			of_run_loop_mode_t runLoopMode;
			OFRunLoopMode runLoopMode;

			if (context->_settings->_usesTCP)
				@throw [OFTruncatedDataException exception];

			context->_settings->_usesTCP = true;
			runLoopMode = [OFRunLoop currentRunLoop].currentMode;
			[self of_sendQueryForContext: context
977
978
979
980
981
982
983
984

985
986
987
988
989
990
991
977
978
979
980
981
982
983

984
985
986
987
988
989
990
991







-
+







			tryNextNameServer = true;
			break;
		}

		if (tryNextNameServer) {
			if (context->_nameServersIndex + 1 <
			    context->_settings->_nameServers.count) {
				of_run_loop_mode_t runLoopMode =
				OFRunLoopMode runLoopMode =
				    [OFRunLoop currentRunLoop].currentMode;

				context->_nameServersIndex++;

				[self of_sendQueryForContext: context
						 runLoopMode: runLoopMode];
				return false;
1039
1040
1041
1042
1043
1044
1045
1046

1047
1048
1049
1050
1051
1052
1053
1039
1040
1041
1042
1043
1044
1045

1046
1047
1048
1049
1050
1051
1052
1053







-
+








	return false;
}

-	  (bool)socket: (OFDatagramSocket *)sock
  didReceiveIntoBuffer: (void *)buffer
		length: (size_t)length
		sender: (const of_socket_address_t *)sender
		sender: (const OFSocketAddress *)sender
	     exception: (id)exception
{
	if (exception != nil)
		return true;

	return [self of_handleResponseBuffer: buffer
				      length: length
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

1220
1221
1222
1223
1224
1225
1226
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
1220
1221
1222
1223
1224
1225
1226







-
-
+
+




-
+




-
+




-
-
+
+

















-
+







	return false;
}

- (void)asyncResolveAddressesForHost: (OFString *)host
			    delegate: (id <OFDNSResolverHostDelegate>)delegate
{
	[self asyncResolveAddressesForHost: host
			     addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY
			       runLoopMode: of_run_loop_mode_default
			     addressFamily: OFSocketAddressFamilyAny
			       runLoopMode: OFDefaultRunLoopMode
				  delegate: delegate];
}

- (void)asyncResolveAddressesForHost: (OFString *)host
		       addressFamily: (of_socket_address_family_t)addressFamily
		       addressFamily: (OFSocketAddressFamily)addressFamily
			    delegate: (id <OFDNSResolverHostDelegate>)delegate
{
	[self asyncResolveAddressesForHost: host
			     addressFamily: addressFamily
			       runLoopMode: of_run_loop_mode_default
			       runLoopMode: OFDefaultRunLoopMode
				  delegate: delegate];
}

- (void)asyncResolveAddressesForHost: (OFString *)host
		       addressFamily: (of_socket_address_family_t)addressFamily
			 runLoopMode: (of_run_loop_mode_t)runLoopMode
		       addressFamily: (OFSocketAddressFamily)addressFamily
			 runLoopMode: (OFRunLoopMode)runLoopMode
			    delegate: (id <OFDNSResolverHostDelegate>)delegate
{
	void *pool = objc_autoreleasePoolPush();
	OFHostAddressResolver *resolver = [[[OFHostAddressResolver alloc]
	    initWithHost: host
	   addressFamily: addressFamily
		resolver: self
		settings: _settings
	     runLoopMode: runLoopMode
		delegate: delegate] autorelease];

	[resolver asyncResolve];

	objc_autoreleasePoolPop(pool);
}

- (OFData *)resolveAddressesForHost: (OFString *)host
		      addressFamily: (of_socket_address_family_t)addressFamily
		      addressFamily: (OFSocketAddressFamily)addressFamily
{
	void *pool = objc_autoreleasePoolPush();
	OFHostAddressResolver *resolver = [[[OFHostAddressResolver alloc]
	    initWithHost: host
	   addressFamily: addressFamily
		resolver: self
		settings: _settings

Modified src/OFDNSResolverSettings.h from [f96b5d98db] to [e160ff7316].

25
26
27
28
29
30
31
32

33
34
35

36
37
38
39
40
41
42
43
25
26
27
28
29
30
31

32
33
34

35
36
37
38
39
40
41
42
43







-
+


-
+








{
@public
	OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC(OFString *) *)
	    *_staticHosts;
	OFArray OF_GENERIC(OFString *) *_nameServers;
	OFString *_Nullable _localDomain;
	OFArray OF_GENERIC(OFString *) *_searchDomains;
	of_time_interval_t _timeout;
	OFTimeInterval _timeout;
	unsigned int _maxAttempts, _minNumberOfDotsInAbsoluteName;
	bool _usesTCP;
	of_time_interval_t _configReloadInterval;
	OFTimeInterval _configReloadInterval;
@protected
	OFDate *_lastConfigReload;
}

- (void)reload;
@end

OF_ASSUME_NONNULL_END

Modified src/OFDNSResolverSettings.m from [a893fa1b35] to [711318f6b6].

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







-
+










-
+







static OFString *
domainFromHostname(OFString *hostname)
{
	if (hostname == nil)
		return nil;

	@try {
		of_socket_address_parse_ip(hostname, 0);
		OFSocketAddressParseIP(hostname, 0);

		/*
		 * If we are still here, the host name is a valid IP address.
		 * We can't use that as local domain.
		 */
		return nil;
	} @catch (OFInvalidFormatException *e) {
		/* Not an IP address -> we can use it if it contains a dot. */
		size_t pos = [hostname rangeOfString: @"."].location;

		if (pos == OF_NOT_FOUND)
		if (pos == OFNotFound)
			return nil;

		return [hostname substringFromIndex: pos + 1];
	}
}
#endif

171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185







-
+








static OFArray OF_GENERIC(OFString *) *
parseNetStackArray(OFString *string)
{
	if (![string hasPrefix: @"["] || ![string hasSuffix: @"]"])
		return nil;

	string = [string substringWithRange: of_range(1, string.length - 2)];
	string = [string substringWithRange: OFMakeRange(1, string.length - 2)];

	return [string componentsSeparatedByString: @"|"];
}
#endif

@implementation OFDNSResolverSettings
- (void)dealloc
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
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







-
+




-
+






-
+








	while ((line = [file readLine]) != nil) {
		OFArray *components, *hosts;
		size_t pos;
		OFString *address;

		pos = [line rangeOfString: @"#"].location;
		if (pos != OF_NOT_FOUND)
		if (pos != OFNotFound)
			line = [line substringToIndex: pos];

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

		if (components.count < 2)
			continue;

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

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

			if (addresses == nil) {
				addresses = [OFMutableArray array];
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
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







-
+




-
+








-
+







	while ((line = [file readLine]) != nil) {
		void *pool2 = objc_autoreleasePoolPush();
		size_t pos;
		OFArray *components, *arguments;
		OFString *option;

		pos = [line indexOfCharacterFromSet: commentCharacters];
		if (pos != OF_NOT_FOUND)
		if (pos != OFNotFound)
			line = [line substringToIndex: pos];

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

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

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

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

418
419
420
421
422
423
424
425

426
427
428
429
430
431
432
418
419
420
421
422
423
424

425
426
427
428
429
430
431
432







-
+







}
# endif
#endif

#ifdef OF_WINDOWS
- (void)obtainWindowsSystemConfig
{
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];
	OFMutableArray *nameServers;
	/*
	 * We need more space than FIXED_INFO in case we have more than one
	 * name server, but we also want it to be properly aligned, meaning we
	 * can't just get a buffer of bytes. Thus, we just get space for 8.
	 */
	FIXED_INFO fixedInfo[8];
477
478
479
480
481
482
483
484

485
486
487
488
489
490
491
477
478
479
480
481
482
483

484
485
486
487
488
489
490
491







-
+







		OFArray *hosts;

		if (components.count < 2)
			continue;

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

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

			if (addresses == nil) {
				addresses = [OFMutableArray array];
505
506
507
508
509
510
511
512

513
514
515
516
517
518
519
505
506
507
508
509
510
511

512
513
514
515
516
517
518
519







-
+







}
#endif

#ifdef OF_AMIGAOS4
- (void)obtainAmigaOS4SystemConfig
{
	OFMutableArray *nameServers = [OFMutableArray array];
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];
	struct List *nameServerList = ObtainDomainNameServerList();
	char buffer[MAXHOSTNAMELEN];

	if (nameServerList == NULL)
		@throw [OFOutOfMemoryException exception];

	@try {

Modified src/OFDNSResourceRecord.h from [cfe4c4fb24] to [7dd514f0ed].

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







-
+





-
+
















-
+












-
+





-
+
















-
+







 * @class OFADNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h
 *
 * @brief A class representing an A DNS resource record.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFADNSResourceRecord: OFDNSResourceRecord
{
	of_socket_address_t _address;
	OFSocketAddress _address;
}

/**
 * @brief The IPv4 address of the resource record.
 */
@property (readonly, nonatomic) const of_socket_address_t *address;
@property (readonly, nonatomic) const OFSocketAddress *address;

- (instancetype)initWithName: (OFString *)name
		    DNSClass: (of_dns_class_t)DNSClass
		  recordType: (of_dns_record_type_t)recordType
			 TTL: (uint32_t)TTL OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated OFADNSResourceRecord with the
 *	  specified name, class, address and time to live.
 *
 * @param name The name for the resource record
 * @param address The address for the resource record
 * @param TTL The time to live for the resource record
 * @return An initialized OFADNSResourceRecord
 */
- (instancetype)initWithName: (OFString *)name
		     address: (const of_socket_address_t *)address
		     address: (const OFSocketAddress *)address
			 TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER;
@end

/**
 * @class OFAAAADNSResourceRecord \
 *	  OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h
 *
 * @brief A class represenging a DNS resource record.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFAAAADNSResourceRecord: OFDNSResourceRecord
{
	of_socket_address_t _address;
	OFSocketAddress _address;
}

/**
 * @brief The IPv6 address of the resource record.
 */
@property (readonly, nonatomic) const of_socket_address_t *address;
@property (readonly, nonatomic) const OFSocketAddress *address;

- (instancetype)initWithName: (OFString *)name
		    DNSClass: (of_dns_class_t)DNSClass
		  recordType: (of_dns_record_type_t)recordType
			 TTL: (uint32_t)TTL OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated OFAAAADNSResourceRecord with the
 *	  specified name, class, address and time to live.
 *
 * @param name The name for the resource record
 * @param address The address for the resource record
 * @param TTL The time to live for the resource record
 * @return An initialized OFAAAADNSResourceRecord
 */
- (instancetype)initWithName: (OFString *)name
		     address: (const of_socket_address_t *)address
		     address: (const OFSocketAddress *)address
			 TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER;
@end

/**
 * @class OFCNAMEDNSResourceRecord \
 *	  OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h
 *

Modified src/OFDNSResourceRecord.m from [50a5f9e1de] to [5cb904a9e3].

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







-
+












-
+







		  recordType: (of_dns_record_type_t)recordType
			 TTL: (uint32_t)TTL
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithName: (OFString *)name
		     address: (const of_socket_address_t *)address
		     address: (const OFSocketAddress *)address
			 TTL: (uint32_t)TTL
{
	self = [super initWithName: name
			  DNSClass: OF_DNS_CLASS_IN
			recordType: OF_DNS_RECORD_TYPE_A
			       TTL: TTL];

	_address = *address;

	return self;
}

- (const of_socket_address_t *)address
- (const OFSocketAddress *)address
{
	return &_address;
}

- (bool)isEqual: (id)object
{
	OFADNSResourceRecord *record;
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

286
287
288
289
290
291
292
293
294
295
296
297
298

299
300
301
302
303
304
305
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
286
287
288
289
290
291
292
293
294
295
296

297
298
299
300
301
302
303
304







-
+
















-
+














-
+
-













-
+












-
+








	if (record->_DNSClass != _DNSClass)
		return false;

	if (record->_recordType != _recordType)
		return false;

	if (!of_socket_address_equal(&record->_address, &_address))
	if (!OFSocketAddressEqual(&record->_address, &_address))
		return false;

	return true;
}

- (unsigned long)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _DNSClass >> 8);
	OF_HASH_ADD(hash, _DNSClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address));
	OF_HASH_ADD_HASH(hash, OFSocketAddressHash(&_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, OFSocketAddressString(&_address), _TTL];
	    of_socket_address_ip_string(&_address, NULL), _TTL];
}
@end

@implementation OFAAAADNSResourceRecord
- (instancetype)initWithName: (OFString *)name
		    DNSClass: (of_dns_class_t)DNSClass
		  recordType: (of_dns_record_type_t)recordType
			 TTL: (uint32_t)TTL
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithName: (OFString *)name
		     address: (const of_socket_address_t *)address
		     address: (const OFSocketAddress *)address
			 TTL: (uint32_t)TTL
{
	self = [super initWithName: name
			  DNSClass: OF_DNS_CLASS_IN
			recordType: OF_DNS_RECORD_TYPE_AAAA
			       TTL: TTL];

	_address = *address;

	return self;
}

- (const of_socket_address_t *)address
- (const OFSocketAddress *)address
{
	return &_address;
}

- (bool)isEqual: (id)object
{
	OFAAAADNSResourceRecord *record;
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
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







-
+
















-
+














-
+
-








	if (record->_DNSClass != _DNSClass)
		return false;

	if (record->_recordType != _recordType)
		return false;

	if (!of_socket_address_equal(&record->_address, &_address))
	if (!OFSocketAddressEqual(&record->_address, &_address))
		return false;

	return true;
}

- (unsigned long)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, _name.hash);
	OF_HASH_ADD(hash, _DNSClass >> 8);
	OF_HASH_ADD(hash, _DNSClass);
	OF_HASH_ADD(hash, _recordType >> 8);
	OF_HASH_ADD(hash, _recordType);
	OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address));
	OF_HASH_ADD_HASH(hash, OFSocketAddressHash(&_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, OFSocketAddressString(&_address), _TTL];
	    of_socket_address_ip_string(&_address, NULL), _TTL];
}
@end

@implementation OFCNAMEDNSResourceRecord
@synthesize alias = _alias;

- (instancetype)initWithName: (OFString *)name

Modified src/OFData+CryptographicHashing.m from [6d7c26a863] to [404b89feab].

52
53
54
55
56
57
58
59

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

59
60
61
62
63
64
65
66







-
+







		cString[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0');
		cString[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0');
	}

	objc_autoreleasePoolPop(pool);

	return [OFString stringWithCString: cString
				  encoding: OF_STRING_ENCODING_ASCII
				  encoding: OFStringEncodingASCII
				    length: digestSize * 2];
}

- (OFString *)stringByMD5Hashing
{
	return stringByHashing([OFMD5Hash class], self);
}

Modified src/OFData.h from [5c1ed5a74d] to [654367484b].

12
13
14
15
16
17
18


19
20
21
22
23
24





25
26



27

28
29
30
31
32
33
34
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34

35
36
37
38
39
40
41
42







+
+






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







 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFObject.h"
#import "OFSerialization.h"
#import "OFMessagePackRepresentation.h"

/*! @file */

OF_ASSUME_NONNULL_BEGIN

@class OFString;
@class OFURL;

/**
 * @brief Options for searching in data.
 *
 * This is a bit mask.
 */
enum {
	OF_DATA_SEARCH_BACKWARDS = 1
typedef enum OFDataSearchOptions {
	/** Search backwards in the data */
	OFDataSearchBackwards = 1
};
} OFDataSearchOptions;

/**
 * @class OFData OFData.h ObjFW/OFData.h
 *
 * @brief A class for storing arbitrary data in an array.
 *
 * For security reasons, serialization and deserialization is only implemented
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
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







-
+















-
+





-
+
-
-
-
-


-
+

-
-
-
+
+
+








/**
 * @brief Compares the data to other data.
 *
 * @param data Data to compare the data to
 * @return The result of the comparison
 */
- (of_comparison_result_t)compare: (OFData *)data;
- (OFComparisonResult)compare: (OFData *)data;

/**
 * @brief Returns a specific item of the OFData.
 *
 * @param index The number of the item to return
 * @return The specified item of the OFData
 */
- (const void *)itemAtIndex: (size_t)index OF_RETURNS_INNER_POINTER;

/**
 * @brief Returns the data in the specified range as a new OFData.
 *
 * @param range The range of the data for the new OFData
 * @return The data in the specified range as a new OFData
 */
- (OFData *)subdataWithRange: (of_range_t)range;
- (OFData *)subdataWithRange: (OFRange)range;

/**
 * @brief Returns the range of the data.
 *
 * @param data The data to search for
 * @param options Options modifying search behavior.@n
 * @param options Options modifying search behavior
 *		  Possible values are:
 *		  Value                      | Description
 *		  ---------------------------|-----------------------------
 *		  `OF_DATA_SEARCH_BACKWARDS` | Search backwards in the data
 * @param range The range in which to search
 * @return The range of the first occurrence of the data or a range with
 *	   `OF_NOT_FOUND` as start position if it was not found.
 *	   `OFNotFound` as start position if it was not found.
 */
- (of_range_t)rangeOfData: (OFData *)data
		  options: (int)options
		    range: (of_range_t)range;
- (OFRange)rangeOfData: (OFData *)data
	       options: (OFDataSearchOptions)options
		 range: (OFRange)range;

#ifdef OF_HAVE_FILES
/**
 * @brief Writes the OFData into the specified file.
 *
 * @param path The path of the file to write to
 */

Modified src/OFData.m from [398b865989] to [98780c8b8b].

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







-
+












-
+
-








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

	@try {
		size_t count = [string
		    cStringLengthWithEncoding: OF_STRING_ENCODING_ASCII];
		    cStringLengthWithEncoding: OFStringEncodingASCII];
		const char *cString;

		if (count % 2 != 0)
			@throw [OFInvalidFormatException exception];

		count /= 2;

		_items = of_alloc(count, 1);
		_count = count;
		_itemSize = 1;
		_freeWhenDone = true;

		cString = [string
		cString = [string cStringWithEncoding: OFStringEncodingASCII];
		    cStringWithEncoding: OF_STRING_ENCODING_ASCII];

		for (size_t i = 0; i < count; i++) {
			uint8_t c1 = cString[2 * i];
			uint8_t c2 = cString[2 * i + 1];
			uint8_t byte;

			if (c1 >= '0' && c1 <= '9')
331
332
333
334
335
336
337
338
339


340
341
342
343
344
345
346
347
330
331
332
333
334
335
336


337
338

339
340
341
342
343
344
345







-
-
+
+
-







		self = [OFMutableData alloc];
	}

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

	@try {
		if (!of_base64_decode((OFMutableData *)self,
		    [string cStringWithEncoding: OF_STRING_ENCODING_ASCII],
		    [string cStringLengthWithEncoding:
		    [string cStringWithEncoding: OFStringEncodingASCII],
		    [string cStringLengthWithEncoding: OFStringEncodingASCII]))
		    OF_STRING_ENCODING_ASCII]))
			@throw [OFInvalidFormatException exception];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	if (!mutable)
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
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







-
+
















-
+

-
+

-
+



-
+

-
+
















-
+







		return false;
	if (memcmp(data.items, _items, _count * _itemSize) != 0)
		return false;

	return true;
}

- (of_comparison_result_t)compare: (OFData *)data
- (OFComparisonResult)compare: (OFData *)data
{
	int comparison;
	size_t count, minCount;

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

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

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

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

		return OF_ORDERED_SAME;
		return OFOrderedSame;
	}

	if (comparison > 0)
		return OF_ORDERED_DESCENDING;
		return OFOrderedDescending;
	else
		return OF_ORDERED_ASCENDING;
		return OFOrderedAscending;
}

- (unsigned long)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	for (size_t i = 0; i < _count * _itemSize; i++)
		OF_HASH_ADD(hash, ((uint8_t *)_items)[i]);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFData *)subdataWithRange: (of_range_t)range
- (OFData *)subdataWithRange: (OFRange)range
{
	OFData *ret;

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

541
542
543
544
545
546
547
548
549
550



551
552
553
554
555
556
557
558
559
560
561
562
563

564
565
566

567
568
569
570

571
572
573
574

575
576
577
578
579
580
581
582
583
584
585

586
587
588

589
590
591
592
593
594
595
539
540
541
542
543
544
545



546
547
548
549
550
551
552
553
554
555
556
557
558
559
560

561
562
563

564
565
566
567

568
569
570
571

572
573
574
575
576
577
578
579
580
581
582

583
584
585

586
587
588
589
590
591
592
593







-
-
-
+
+
+












-
+


-
+



-
+



-
+










-
+


-
+







}

- (OFString *)stringByBase64Encoding
{
	return of_base64_encode(_items, _count * _itemSize);
}

- (of_range_t)rangeOfData: (OFData *)data
		  options: (int)options
		    range: (of_range_t)range
- (OFRange)rangeOfData: (OFData *)data
	       options: (OFDataSearchOptions)options
		 range: (OFRange)range
{
	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)
		@throw [OFInvalidArgumentException exception];

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

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

	search = data.items;

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

			/* No match and we're at the last item */
			if (i == 0)
				break;
		}
	} else {
		for (size_t i = range.location;
		    i <= range.length - searchLength; i++)
			if (memcmp(_items + i * _itemSize, search,
			    searchLength * _itemSize) == 0)
				return of_range(i, searchLength);
				return OFMakeRange(i, searchLength);
	}

	return of_range(OF_NOT_FOUND, 0);
	return OFMakeRange(OFNotFound, 0);
}

#ifdef OF_HAVE_FILES
- (void)writeToFile: (OFString *)path
{
	OFFile *file = [[OFFile alloc] initWithPath: path mode: @"w"];
	@try {

Modified src/OFDatagramSocket.h from [3462a90bc3] to [8778942db1].

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







-
+
-
-
+










-
-
+
+







 *
 * @param length The length of the packet
 * @param sender The address of the sender of the packet
 * @param exception An exception which occurred while receiving or `nil` on
 *		    success
 * @return A bool whether the same block should be used for the next receive
 */
typedef bool (^of_datagram_socket_async_receive_block_t)(
typedef bool (^OFDatagramSocketAsyncReceiveBlock)(size_t length,
    size_t length, const of_socket_address_t *_Nonnull sender,
    id _Nullable exception);
    const OFSocketAddress *_Nonnull sender, id _Nullable exception);

/**
 * @brief A block which is called when a packet has been sent.
 *
 * @param data The data which was sent
 * @param receiver The receiver for the packet
 * @param exception An exception which occurred while reading or `nil` on
 *		    success
 * @return The data to repeat the send with or nil if it should not repeat
 */
typedef OFData *_Nullable (^of_datagram_socket_async_send_data_block_t)(
    OFData *_Nonnull data, const of_socket_address_t *_Nonnull receiver,
typedef OFData *_Nullable (^OFDatagramSocketAsyncSendDataBlock)(
    OFData *_Nonnull data, const OFSocketAddress *_Nonnull receiver,
    id _Nullable exception);
#endif

/**
 * @protocol OFDatagramSocketDelegate OFDatagramSocket.h \
 *	     ObjFW/OFDatagramSocket.h
 *
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
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







-
+













-
+


















-
+







 * @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: (OFDatagramSocket *)socket
  didReceiveIntoBuffer: (void *)buffer
		length: (size_t)length
		sender: (const of_socket_address_t *_Nonnull)sender
		sender: (const OFSocketAddress *_Nonnull)sender
	     exception: (nullable id)exception;

/**
 * @brief This method is called when a packet has been sent.
 *
 * @param socket The datagram socket which sent a packet
 * @param data The data which was sent
 * @param receiver The receiver for the 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: (OFDatagramSocket *)socket
		didSendData: (OFData *)data
		   receiver: (const of_socket_address_t *_Nonnull)receiver
		   receiver: (const OFSocketAddress *_Nonnull)receiver
		  exception: (nullable id)exception;
@end

/**
 * @class OFDatagramSocket OFDatagramSocket.h ObjFW/OFDatagramSocket.h
 *
 * @brief A base class for datagram sockets.
 *
 * @warning Even though the OFCopying protocol is implemented, it does *not*
 *	    return an independent copy of the socket, but instead retains it.
 *	    This is so that the socket can be used as a key for a dictionary,
 *	    so context can be associated with a socket. Using a socket in more
 *	    than one thread at the same time is not thread-safe, even if copy
 *	    was called to create one "instance" for every thread!
 */
@interface OFDatagramSocket: OFObject <OFCopying, OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	of_socket_t _socket;
	OFSocketHandle _socket;
	bool _canBlock;
#ifdef OF_WII
	bool _canSendToBroadcastAddresses;
#endif
	id <OFDatagramSocketDelegate> _Nullable _delegate;
	OF_RESERVE_IVARS(OFDatagramSocket, 4)
}
149
150
151
152
153
154
155
156
157


158
159
160
161
162

163
164
165
166
167
168
169
148
149
150
151
152
153
154


155
156
157
158
159
160

161
162
163
164
165
166
167
168







-
-
+
+




-
+







/**
 * @brief Receives a datagram and stores it into the specified buffer.
 *
 * If the buffer is too small, the datagram is truncated.
 *
 * @param buffer The buffer to write the datagram to
 * @param length The length of the buffer
 * @param sender A pointer to an @ref of_socket_address_t, which will be set to
 *		 the address of the sender
 * @param sender A pointer to an @ref OFSocketAddress, which will be set to the
 *		 address of the sender
 * @return The length of the received datagram
 */
- (size_t)receiveIntoBuffer: (void *)buffer
		     length: (size_t)length
		     sender: (of_socket_address_t *)sender;
		     sender: (OFSocketAddress *)sender;

/**
 * @brief Asynchronously receives a datagram and stores it into the specified
 *	  buffer.
 *
 * If the buffer is too small, the datagram is truncated.
 *
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
282
283
284
285


286
287
288
289
290
291
292
293
294



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


283
284
285
286
287
288
289
290



291
292
293
294
295
296
297
298
299
300







-
+



















-
+



















-
-
+
+







-
-
+
+



-
+





-
-
+
+


-
+





-
-
+
+



-
-
+
+






-
-
+
+





-
-
+
+





-
-
+
+






-
-
-
+
+
+







 *
 * @param buffer The buffer to write the datagram to
 * @param length The length of the buffer
 * @param runLoopMode The run loop mode in which to perform the async receive
 */
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (of_run_loop_mode_t)runLoopMode;
		   runLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously receives a datagram and stores it into the specified
 *	  buffer.
 *
 * If the buffer is too small, the datagram is truncated.
 *
 * @param buffer The buffer to write the datagram to
 * @param length The length of the buffer
 * @param block The block to call when the datagram has been received. If the
 *		block returns true, it will be called again with the same
 *		buffer and maximum length when more datagrams have been
 *		received. If you want the next method in the queue to handle
 *		the datagram received next, you need to return false from the
 *		method.
 */
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
			 block: (of_datagram_socket_async_receive_block_t)block;
			 block: (OFDatagramSocketAsyncReceiveBlock)block;

/**
 * @brief Asynchronously receives a datagram and stores it into the specified
 *	  buffer.
 *
 * If the buffer is too small, the datagram is truncated.
 *
 * @param buffer The buffer to write the datagram to
 * @param length The length of the buffer
 * @param runLoopMode The run loop mode in which to perform the async receive
 * @param block The block to call when the datagram has been received. If the
 *		block returns true, it will be called again with the same
 *		buffer and maximum length when more datagrams have been
 *		received. If you want the next method in the queue to handle
 *		the datagram received next, you need to return false from the
 *		method.
 */
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (of_run_loop_mode_t)runLoopMode
			 block: (of_datagram_socket_async_receive_block_t)block;
		   runLoopMode: (OFRunLoopMode)runLoopMode
			 block: (OFDatagramSocketAsyncReceiveBlock)block;
#endif

/**
 * @brief Sends the specified datagram to the specified address.
 *
 * @param buffer The buffer to send as a datagram
 * @param length The length of the buffer
 * @param receiver A pointer to an @ref of_socket_address_t to which the
 *		   datagram should be sent
 * @param receiver A pointer to an @ref OFSocketAddress to which the datagram
 *		   should be sent
 */
- (void)sendBuffer: (const void *)buffer
	    length: (size_t)length
	  receiver: (const of_socket_address_t *)receiver;
	  receiver: (const OFSocketAddress *)receiver;

/**
 * @brief Asynchronously sends the specified datagram to the specified address.
 *
 * @param data The data to send as a datagram
 * @param receiver A pointer to an @ref of_socket_address_t to which the
 *		   datagram should be sent. The receiver is copied.
 * @param receiver A pointer to an @ref OFSocketAddress to which the datagram
 *		   should be sent. The receiver is copied.
 */
- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver;
	     receiver: (const OFSocketAddress *)receiver;

/**
 * @brief Asynchronously sends the specified datagram to the specified address.
 *
 * @param data The data to send as a datagram
 * @param receiver A pointer to an @ref of_socket_address_t to which the
 *		   datagram should be sent. The receiver is copied.
 * @param receiver A pointer to an @ref OFSocketAddress to which the datgram
 *		   should be sent. The receiver is copied.
 * @param runLoopMode The run loop mode in which to perform the async send
 */
- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
	  runLoopMode: (of_run_loop_mode_t)runLoopMode;
	     receiver: (const OFSocketAddress *)receiver
	  runLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously sends the specified datagram to the specified address.
 *
 * @param data The data to send as a datagram
 * @param receiver A pointer to an @ref of_socket_address_t to which the
 *		   datagram should be sent. The receiver is copied.
 * @param receiver A pointer to an @ref OFSocketAddress to which the datagram
 *		   should be sent. The receiver is copied.
 * @param block The block to call when the packet has been sent. It should
 *		return the data for the next send with the same callback or nil
 *		if it should not repeat.
 */
- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
		block: (of_datagram_socket_async_send_data_block_t)block;
	     receiver: (const OFSocketAddress *)receiver
		block: (OFDatagramSocketAsyncSendDataBlock)block;

/**
 * @brief Asynchronously sends the specified datagram to the specified address.
 *
 * @param data The data to send as a datagram
 * @param receiver A pointer to an @ref of_socket_address_t to which the
 *		   datagram should be sent. The receiver is copied.
 * @param receiver A pointer to an @ref OFSocketAddress to which the datagram
 *		   should be sent. The receiver is copied.
 * @param runLoopMode The run loop mode in which to perform the async send
 * @param block The block to call when the packet has been sent. It should
 *		return the data for the next send with the same callback or nil
 *		if it should not repeat.
 */
- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
	  runLoopMode: (of_run_loop_mode_t)runLoopMode
		block: (of_datagram_socket_async_send_data_block_t)block;
	     receiver: (const OFSocketAddress *)receiver
	  runLoopMode: (OFRunLoopMode)runLoopMode
		block: (OFDatagramSocketAsyncSendDataBlock)block;
#endif

/**
 * @brief Cancels all pending asynchronous requests on the socket.
 */
- (void)cancelAsyncRequests;

Modified src/OFDatagramSocket.m from [ed638b6427] to [a91f3ff6b6].

163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177







-
+







#else
	return _canSendToBroadcastAddresses;
#endif
}

- (size_t)receiveIntoBuffer: (void *)buffer
		     length: (size_t)length
		     sender: (of_socket_address_t *)sender
		     sender: (OFSocketAddress *)sender
{
	ssize_t ret;

	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	sender->length = (socklen_t)sizeof(sender->sockaddr);
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
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







-
+



-
+




-
+



-
+










-
+




-
+














-
+



-
+





-
-
+
+












-
+







		    exceptionWithObject: self
			requestedLength: length
				  errNo: of_socket_errno()];
#endif

	switch (sender->sockaddr.sockaddr.sa_family) {
	case AF_INET:
		sender->family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
		sender->family = OFSocketAddressFamilyIPv4;
		break;
#ifdef OF_HAVE_IPV6
	case AF_INET6:
		sender->family = OF_SOCKET_ADDRESS_FAMILY_IPV6;
		sender->family = OFSocketAddressFamilyIPv6;
		break;
#endif
#ifdef OF_HAVE_IPX
	case AF_IPX:
		sender->family = OF_SOCKET_ADDRESS_FAMILY_IPX;
		sender->family = OFSocketAddressFamilyIPX;
		break;
#endif
	default:
		sender->family = OF_SOCKET_ADDRESS_FAMILY_UNKNOWN;
		sender->family = OFSocketAddressFamilyUnknown;
		break;
	}

	return ret;
}

- (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length
{
	[self asyncReceiveIntoBuffer: buffer
			      length: length
			 runLoopMode: of_run_loop_mode_default];
			 runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (of_run_loop_mode_t)runLoopMode
		   runLoopMode: (OFRunLoopMode)runLoopMode
{
	[OFRunLoop of_addAsyncReceiveForDatagramSocket: self
						buffer: buffer
						length: length
						  mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
						 block: NULL
# endif
					      delegate: _delegate];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
			 block: (of_datagram_socket_async_receive_block_t)block
			 block: (OFDatagramSocketAsyncReceiveBlock)block
{
	[self asyncReceiveIntoBuffer: buffer
			      length: length
			 runLoopMode: of_run_loop_mode_default
			 runLoopMode: OFDefaultRunLoopMode
			       block: block];
}

- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (of_run_loop_mode_t)runLoopMode
			 block: (of_datagram_socket_async_receive_block_t)block
		   runLoopMode: (OFRunLoopMode)runLoopMode
			 block: (OFDatagramSocketAsyncReceiveBlock)block
{
	[OFRunLoop of_addAsyncReceiveForDatagramSocket: self
						buffer: buffer
						length: length
						  mode: runLoopMode
						 block: block
					      delegate: nil];
}
#endif

- (void)sendBuffer: (const void *)buffer
	    length: (size_t)length
	  receiver: (const of_socket_address_t *)receiver
	  receiver: (const OFSocketAddress *)receiver
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

#ifndef OF_WINDOWS
	ssize_t bytesWritten;

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







-
+



-
+



-
-
+
+













-
-
+
+



-
+




-
-
-
+
+
+













-
+







		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: bytesWritten
							     errNo: 0];
}

- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
	     receiver: (const OFSocketAddress *)receiver
{
	[self asyncSendData: data
		   receiver: receiver
		runLoopMode: of_run_loop_mode_default];
		runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
	  runLoopMode: (of_run_loop_mode_t)runLoopMode
	     receiver: (const OFSocketAddress *)receiver
	  runLoopMode: (OFRunLoopMode)runLoopMode
{
	[OFRunLoop of_addAsyncSendForDatagramSocket: self
					       data: data
					   receiver: receiver
					       mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
					      block: NULL
# endif
					   delegate: _delegate];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
		block: (of_datagram_socket_async_send_data_block_t)block
	     receiver: (const OFSocketAddress *)receiver
		block: (OFDatagramSocketAsyncSendDataBlock)block
{
	[self asyncSendData: data
		   receiver: receiver
		runLoopMode: of_run_loop_mode_default
		runLoopMode: OFDefaultRunLoopMode
		      block: block];
}

- (void)asyncSendData: (OFData *)data
	     receiver: (const of_socket_address_t *)receiver
	  runLoopMode: (of_run_loop_mode_t)runLoopMode
		block: (of_datagram_socket_async_send_data_block_t)block
	     receiver: (const OFSocketAddress *)receiver
	  runLoopMode: (OFRunLoopMode)runLoopMode
		block: (OFDatagramSocketAsyncSendDataBlock)block
{
	[OFRunLoop of_addAsyncSendForDatagramSocket: self
					       data: data
					   receiver: receiver
					       mode: runLoopMode
					      block: block
					   delegate: nil];
}
#endif

- (void)cancelAsyncRequests
{
	[OFRunLoop of_cancelAsyncRequestsForObject: self
					      mode: of_run_loop_mode_default];
					      mode: OFDefaultRunLoopMode];
}

- (int)fileDescriptorForReading
{
#ifndef OF_WINDOWS
	return _socket;
#else

Modified src/OFDate.h from [dff8b1eb37] to [67980cebbc].

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







-
+







 */
#ifndef OF_DATE_M
OF_SUBCLASSING_RESTRICTED
#endif
@interface OFDate: OFObject <OFCopying, OFComparing, OFSerialization,
    OFMessagePackRepresentation>
{
	of_time_interval_t _seconds;
	OFTimeInterval _seconds;
}

#ifdef OF_HAVE_CLASS_PROPERTIES
@property (class, readonly, nonatomic) OFDate *distantFuture;
@property (class, readonly, nonatomic) OFDate *distantPast;
#endif

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







-
+




-
+















-
+







-
+







 * @brief The day of the year of the date in local time.
 */
@property (readonly, nonatomic) unsigned short localDayOfYear;

/**
 * @brief The seconds since 1970-01-01T00:00:00Z.
 */
@property (readonly, nonatomic) of_time_interval_t timeIntervalSince1970;
@property (readonly, nonatomic) OFTimeInterval timeIntervalSince1970;

/**
 * @brief The seconds the date is in the future.
 */
@property (readonly, nonatomic) of_time_interval_t timeIntervalSinceNow;
@property (readonly, nonatomic) OFTimeInterval timeIntervalSinceNow;

/**
 * @brief Creates a new OFDate with the current date and time.
 *
 * @return A new, autoreleased OFDate with the current date and time
 */
+ (instancetype)date;

/**
 * @brief Creates a new OFDate with the specified date and time since
 *	  1970-01-01T00:00:00Z.
 *
 * @param seconds The seconds since 1970-01-01T00:00:00Z
 * @return A new, autoreleased OFDate with the specified date and time
 */
+ (instancetype)dateWithTimeIntervalSince1970: (of_time_interval_t)seconds;
+ (instancetype)dateWithTimeIntervalSince1970: (OFTimeInterval)seconds;

/**
 * @brief Creates a new OFDate with the specified date and time since now.
 *
 * @param seconds The seconds since now
 * @return A new, autoreleased OFDate with the specified date and time
 */
+ (instancetype)dateWithTimeIntervalSinceNow: (of_time_interval_t)seconds;
+ (instancetype)dateWithTimeIntervalSinceNow: (OFTimeInterval)seconds;

/**
 * @brief Creates a new OFDate with the specified string in the specified
 *	  format.
 *
 * The time zone used is UTC. See @ref dateWithLocalDateString:format: if you
 * want local time.
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
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







-
+









-
+







/**
 * @brief Initializes an already allocated OFDate with the specified date and
 *	  time since 1970-01-01T00:00:00Z.
 *
 * @param seconds The seconds since 1970-01-01T00:00:00Z
 * @return An initialized OFDate with the specified date and time
 */
- (instancetype)initWithTimeIntervalSince1970: (of_time_interval_t)seconds
- (instancetype)initWithTimeIntervalSince1970: (OFTimeInterval)seconds
    OF_DESIGNATED_INITIALIZER;

/**
 * @brief Initializes an already allocated OFDate with the specified date and
 *	  time since now.
 *
 * @param seconds The seconds since now
 * @return An initialized OFDate with the specified date and time
 */
- (instancetype)initWithTimeIntervalSinceNow: (of_time_interval_t)seconds;
- (instancetype)initWithTimeIntervalSinceNow: (OFTimeInterval)seconds;

/**
 * @brief Initializes an already allocated OFDate with the specified string in
 *	  the specified format.
 *
 * The time zone used is UTC. If a time zone is specified anyway, an
 * OFInvalidFormatException is thrown. See @ref initWithLocalDateString:format:
269
270
271
272
273
274
275
276

277
278
279
280
281
282
283
269
270
271
272
273
274
275

276
277
278
279
280
281
282
283







-
+








/**
 * @brief Compares the date to another date.
 *
 * @param date The date to compare the date to
 * @return The result of the comparison
 */
- (of_comparison_result_t)compare: (OFDate *)date;
- (OFComparisonResult)compare: (OFDate *)date;

/**
 * @brief Creates a string of the date with the specified format.
 *
 * See the man page for `strftime` for information on the format.
 *
 * @param format The format for the date string
317
318
319
320
321
322
323
324

325
326
327
328
329
330
331
332

333
334
335
317
318
319
320
321
322
323

324
325
326
327
328
329
330
331

332
333
334
335







-
+







-
+




/**
 * @brief Returns the seconds the receiver is after the date.
 *
 * @param otherDate Date date to generate the difference with receiver
 * @return The seconds the receiver is after the date.
 */
- (of_time_interval_t)timeIntervalSinceDate: (OFDate *)otherDate;
- (OFTimeInterval)timeIntervalSinceDate: (OFDate *)otherDate;

/**
 * @brief Creates a new date with the specified time interval added.
 *
 * @param seconds The seconds after the date
 * @return A new, autoreleased OFDate
 */
- (OFDate *)dateByAddingTimeInterval: (of_time_interval_t)seconds;
- (OFDate *)dateByAddingTimeInterval: (OFTimeInterval)seconds;
@end

OF_ASSUME_NONNULL_END

Modified src/OFDate.m from [c1ec0de284] to [5b10481bac].

87
88
89
90
91
92
93
94

95
96
97
98

99
100
101
102
103

104
105
106
107
108
109
110
87
88
89
90
91
92
93

94
95
96
97

98
99
100
101
102

103
104
105
106
107
108
109
110







-
+



-
+




-
+







static void
initDistantPast(void)
{
	distantPast = [[OFDateSingleton alloc]
	    initWithTimeIntervalSince1970: -62167219200.0];
}

static of_time_interval_t
static OFTimeInterval
now(void)
{
	struct timeval tv;
	of_time_interval_t seconds;
	OFTimeInterval seconds;

	OF_ENSURE(gettimeofday(&tv, NULL) == 0);

	seconds = tv.tv_sec;
	seconds += (of_time_interval_t)tv.tv_usec / 1000000;
	seconds += (OFTimeInterval)tv.tv_usec / 1000000;

	return seconds;
}

#if (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)) && \
    defined(OF_HAVE_THREADS)
static OFMutex *mutex;
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
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







-
+











-
+













-
+

















-
+


















-
+











-
+








#ifdef OF_WINDOWS
static __time64_t (*func__mktime64)(struct tm *);
#endif

#ifdef HAVE_GMTIME_R
# define GMTIME_RET(field)						\
	of_time_interval_t timeInterval = self.timeIntervalSince1970;	\
	OFTimeInterval timeInterval = self.timeIntervalSince1970;	\
	time_t seconds = (time_t)timeInterval;				\
	struct tm tm;							\
									\
	if (seconds != trunc(timeInterval))				\
		@throw [OFOutOfRangeException exception];		\
									\
	if (gmtime_r(&seconds, &tm) == NULL)				\
		@throw [OFOutOfRangeException exception];		\
									\
	return tm.field;
# define LOCALTIME_RET(field)						\
	of_time_interval_t timeInterval = self.timeIntervalSince1970;	\
	OFTimeInterval timeInterval = self.timeIntervalSince1970;	\
	time_t seconds = (time_t)timeInterval;				\
	struct tm tm;							\
									\
	if (seconds != trunc(timeInterval))				\
		@throw [OFOutOfRangeException exception];		\
									\
	if (localtime_r(&seconds, &tm) == NULL)				\
		@throw [OFOutOfRangeException exception];		\
									\
	return tm.field;
#else
# ifdef OF_HAVE_THREADS
#  define GMTIME_RET(field)						\
	of_time_interval_t timeInterval = self.timeIntervalSince1970;	\
	OFTimeInterval timeInterval = self.timeIntervalSince1970;	\
	time_t seconds = (time_t)timeInterval;				\
	struct tm *tm;							\
									\
	if (seconds != trunc(timeInterval))				\
		@throw [OFOutOfRangeException exception];		\
									\
	[mutex lock];							\
									\
	@try {								\
		if ((tm = gmtime(&seconds)) == NULL)			\
			@throw [OFOutOfRangeException exception];	\
									\
		return tm->field;					\
	} @finally {							\
		[mutex unlock];						\
	}
#  define LOCALTIME_RET(field)						\
	of_time_interval_t timeInterval = self.timeIntervalSince1970;	\
	OFTimeInterval timeInterval = self.timeIntervalSince1970;	\
	time_t seconds = (time_t)timeInterval;				\
	struct tm *tm;							\
									\
	if (seconds != trunc(timeInterval))				\
		@throw [OFOutOfRangeException exception];		\
									\
	[mutex lock];							\
									\
	@try {								\
		if ((tm = localtime(&seconds)) == NULL)			\
			@throw [OFOutOfRangeException exception];	\
									\
		return tm->field;					\
	} @finally {							\
		[mutex unlock];						\
	}
# else
#  define GMTIME_RET(field)						\
	of_time_interval_t timeInterval = self.timeIntervalSince1970;	\
	OFTimeInterval timeInterval = self.timeIntervalSince1970;	\
	time_t seconds = (time_t)timeInterval;				\
	struct tm *tm;							\
									\
	if (seconds != trunc(timeInterval))				\
		@throw [OFOutOfRangeException exception];		\
									\
	if ((tm = gmtime(&seconds)) == NULL)				\
		@throw [OFOutOfRangeException exception];		\
									\
	return tm->field;
#  define LOCALTIME_RET(field)						\
	of_time_interval_t timeInterval = self.timeIntervalSince1970;	\
	OFTimeInterval timeInterval = self.timeIntervalSince1970;	\
	time_t seconds = (time_t)timeInterval;				\
	struct tm *tm;							\
									\
	if (seconds != trunc(timeInterval))				\
		@throw [OFOutOfRangeException exception];		\
									\
	if ((tm = localtime(&seconds)) == NULL)				\
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298







-
+







@implementation OFDatePlaceholder
#ifdef __clang__
/* We intentionally don't call into super, so silence the warning. */
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-pragmas"
# pragma clang diagnostic ignored "-Wobjc-designated-initializers"
#endif
- (instancetype)initWithTimeIntervalSince1970: (of_time_interval_t)seconds
- (instancetype)initWithTimeIntervalSince1970: (OFTimeInterval)seconds
{
#if defined(OF_OBJFW_RUNTIME) && UINTPTR_MAX == UINT64_MAX
	uint64_t value;
#endif

	if (seconds == 0) {
		static of_once_t once = OF_ONCE_INIT;
319
320
321
322
323
324
325
326

327
328
329
330
331
332
333
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333







-
+







#ifdef __clang__
# pragma clang diagnostic pop
#endif
@end

#if defined(OF_OBJFW_RUNTIME) && UINTPTR_MAX == UINT64_MAX
@implementation OFTaggedPointerDate
- (of_time_interval_t)timeIntervalSince1970
- (OFTimeInterval)timeIntervalSince1970
{
	uint64_t value = (uint64_t)object_getTaggedPointerValue(self);

	value |= UINT64_C(4) << 60;

	return OF_BSWAP_DOUBLE_IF_LE(OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE(
	    value)));
378
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
397
398







-
+





-
+







}

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

+ (instancetype)dateWithTimeIntervalSince1970: (of_time_interval_t)seconds
+ (instancetype)dateWithTimeIntervalSince1970: (OFTimeInterval)seconds
{
	return [[[self alloc]
	    initWithTimeIntervalSince1970: seconds] autorelease];
}

+ (instancetype)dateWithTimeIntervalSinceNow: (of_time_interval_t)seconds
+ (instancetype)dateWithTimeIntervalSinceNow: (OFTimeInterval)seconds
{
	return [[[self alloc]
	    initWithTimeIntervalSinceNow: seconds] autorelease];
}

+ (instancetype)dateWithDateString: (OFString *)string
			    format: (OFString *)format
423
424
425
426
427
428
429
430

431
432
433
434
435
436
437
438
439

440
441
442
443
444
445
446
423
424
425
426
427
428
429

430
431
432
433
434
435
436
437
438

439
440
441
442
443
444
445
446







-
+








-
+







}

- (instancetype)init
{
	return [self initWithTimeIntervalSince1970: now()];
}

- (instancetype)initWithTimeIntervalSince1970: (of_time_interval_t)seconds
- (instancetype)initWithTimeIntervalSince1970: (OFTimeInterval)seconds
{
	self = [super init];

	_seconds = seconds;

	return self;
}

- (instancetype)initWithTimeIntervalSinceNow: (of_time_interval_t)seconds
- (instancetype)initWithTimeIntervalSinceNow: (OFTimeInterval)seconds
{
	return [self initWithTimeIntervalSince1970: now() + seconds];
}

- (instancetype)initWithDateString: (OFString *)string
			    format: (OFString *)format
{
466
467
468
469
470
471
472
473

474
475
476
477
478
479
480
466
467
468
469
470
471
472

473
474
475
476
477
478
479
480







-
+







	struct tm tm = { .tm_isdst = -1 };
	/*
	 * of_strptime() can never set this to SHRT_MAX, no matter what is
	 * passed to it, so this is a safe way to figure out if the date
	 * contains a time zone.
	 */
	short tz = SHRT_MAX;
	of_time_interval_t seconds;
	OFTimeInterval seconds;

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

	if (tz == SHRT_MAX) {
#ifdef OF_WINDOWS
494
495
496
497
498
499
500
501

502
503
504
505
506
507
508
494
495
496
497
498
499
500

501
502
503
504
505
506
507
508







-
+







	objc_autoreleasePoolPop(pool);

	return [self initWithTimeIntervalSince1970: seconds];
}

- (instancetype)initWithSerialization: (OFXMLElement *)element
{
	of_time_interval_t seconds;
	OFTimeInterval seconds;

	@try {
		void *pool = objc_autoreleasePoolPush();
		unsigned long long value;

		if (![element.name isEqual: @"OFDate"] ||
		    ![element.namespace isEqual: OF_SERIALIZATION_NS])
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
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







-
+





-
+

-
+

-
+







}

- (id)copy
{
	return [self retain];
}

- (of_comparison_result_t)compare: (OFDate *)date
- (OFComparisonResult)compare: (OFDate *)date
{
	if (![date isKindOfClass: [OFDate class]])
		@throw [OFInvalidArgumentException exception];

	if (self.timeIntervalSince1970 < date.timeIntervalSince1970)
		return OF_ORDERED_ASCENDING;
		return OFOrderedAscending;
	if (self.timeIntervalSince1970 > date.timeIntervalSince1970)
		return OF_ORDERED_DESCENDING;
		return OFOrderedDescending;

	return OF_ORDERED_SAME;
	return OFOrderedSame;
}

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

601
602
603
604
605
606
607
608

609
610
611
612
613
614
615
601
602
603
604
605
606
607

608
609
610
611
612
613
614
615







-
+








	return [element autorelease];
}

- (OFData *)messagePackRepresentation
{
	void *pool = objc_autoreleasePoolPush();
	of_time_interval_t timeInterval = self.timeIntervalSince1970;
	OFTimeInterval timeInterval = self.timeIntervalSince1970;
	int64_t seconds = (int64_t)timeInterval;
	uint32_t nanoseconds =
	    (uint32_t)((timeInterval - trunc(timeInterval)) * 1000000000);
	OFData *ret;

	if (seconds >= 0 && seconds < 0x400000000) {
		if (seconds <= UINT32_MAX && nanoseconds == 0) {
654
655
656
657
658
659
660
661

662
663
664
665
666
667
668
654
655
656
657
658
659
660

661
662
663
664
665
666
667
668







-
+







	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}

- (unsigned long)microsecond
{
	of_time_interval_t timeInterval = self.timeIntervalSince1970;
	OFTimeInterval timeInterval = self.timeIntervalSince1970;

	return (unsigned long)((timeInterval - trunc(timeInterval)) * 1000000);
}

- (unsigned char)second
{
	GMTIME_RET(tm_sec)
737
738
739
740
741
742
743
744

745
746
747
748
749
750
751
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751







-
+







{
	LOCALTIME_RET(tm_yday + 1)
}

- (OFString *)dateStringWithFormat: (OFConstantString *)format
{
	OFString *ret;
	of_time_interval_t timeInterval = self.timeIntervalSince1970;
	OFTimeInterval timeInterval = self.timeIntervalSince1970;
	time_t seconds = (time_t)timeInterval;
	struct tm tm;
	size_t pageSize;
#ifndef OF_WINDOWS
	char *buffer;
#else
	wchar_t *buffer;
797
798
799
800
801
802
803
804

805
806
807
808
809
810
811
797
798
799
800
801
802
803

804
805
806
807
808
809
810
811







-
+








	return ret;
}

- (OFString *)localDateStringWithFormat: (OFConstantString *)format
{
	OFString *ret;
	of_time_interval_t timeInterval = self.timeIntervalSince1970;
	OFTimeInterval timeInterval = self.timeIntervalSince1970;
	time_t seconds = (time_t)timeInterval;
	struct tm tm;
	size_t pageSize;
#ifndef OF_WINDOWS
	char *buffer;
#else
	wchar_t *buffer;
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
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







-
+










-
+





-
+




-
+




-
+


-
+




-
+




-
+





}

- (OFDate *)earlierDate: (OFDate *)otherDate
{
	if (otherDate == nil)
		return self;

	if ([self compare: otherDate] == OF_ORDERED_DESCENDING)
	if ([self compare: otherDate] == OFOrderedDescending)
		return otherDate;

	return self;
}

- (OFDate *)laterDate: (OFDate *)otherDate
{
	if (otherDate == nil)
		return self;

	if ([self compare: otherDate] == OF_ORDERED_ASCENDING)
	if ([self compare: otherDate] == OFOrderedAscending)
		return otherDate;

	return self;
}

- (of_time_interval_t)timeIntervalSince1970
- (OFTimeInterval)timeIntervalSince1970
{
	return _seconds;
}

- (of_time_interval_t)timeIntervalSinceDate: (OFDate *)otherDate
- (OFTimeInterval)timeIntervalSinceDate: (OFDate *)otherDate
{
	return self.timeIntervalSince1970 - otherDate.timeIntervalSince1970;
}

- (of_time_interval_t)timeIntervalSinceNow
- (OFTimeInterval)timeIntervalSinceNow
{
	struct timeval t;
	of_time_interval_t seconds;
	OFTimeInterval seconds;

	OF_ENSURE(gettimeofday(&t, NULL) == 0);

	seconds = t.tv_sec;
	seconds += (of_time_interval_t)t.tv_usec / 1000000;
	seconds += (OFTimeInterval)t.tv_usec / 1000000;

	return self.timeIntervalSince1970 - seconds;
}

- (OFDate *)dateByAddingTimeInterval: (of_time_interval_t)seconds
- (OFDate *)dateByAddingTimeInterval: (OFTimeInterval)seconds
{
	return [OFDate dateWithTimeIntervalSince1970:
	    self.timeIntervalSince1970 + seconds];
}
@end

Modified src/OFDictionary.h from [72e24e9365] to [a266eaef28].

30
31
32
33
34
35
36
37

38
39
40


41
42
43
44
45
46
47
30
31
32
33
34
35
36

37



38
39
40
41
42
43
44
45
46







-
+
-
-
-
+
+







#import "OFMessagePackRepresentation.h"

OF_ASSUME_NONNULL_BEGIN

@class OFArray OF_GENERIC(ObjectType);

#ifdef OF_HAVE_BLOCKS
typedef void (^of_dictionary_enumeration_block_t)(id key, id object,
typedef void (^OFDictionaryEnumerationBlock)(id key, id object, bool *stop);
     bool *stop);
typedef bool (^of_dictionary_filter_block_t)(id key, id object);
typedef id _Nonnull (^of_dictionary_map_block_t)(id key, id object);
typedef bool (^OFDictionaryFilterBlock)(id key, id object);
typedef id _Nonnull (^OFDictionaryMapBlock)(id key, id object);
#endif

/**
 * @class OFDictionary OFDictionary.h ObjFW/OFDictionary.h
 *
 * @brief An abstract class for storing objects in a dictionary.
 *
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
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







-
+
-








-
-
+
+









-
-
+
+








#ifdef OF_HAVE_BLOCKS
/**
 * @brief Executes a block for each key / object pair.
 *
 * @param block The block to execute for each key / object pair.
 */
- (void)enumerateKeysAndObjectsUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock: (OFDictionaryEnumerationBlock)block;
    (of_dictionary_enumeration_block_t)block;

/**
 * @brief Creates a new dictionary, mapping each object using the specified
 *	  block.
 *
 * @param block A block which maps an object for each object
 * @return A new autoreleased OFDictionary
 */
- (OFDictionary OF_GENERIC(KeyType, id) *)mappedDictionaryUsingBlock:
    (of_dictionary_map_block_t)block;
- (OFDictionary OF_GENERIC(KeyType, id) *)
    mappedDictionaryUsingBlock: (OFDictionaryMapBlock)block;

/**
 * @brief Creates a new dictionary, only containing the objects for which the
 *	  block returns true.
 *
 * @param block A block which determines if the object should be in the new
 *		dictionary
 * @return A new autoreleased OFDictionary
 */
- (OFDictionary OF_GENERIC(KeyType, ObjectType) *)filteredDictionaryUsingBlock:
    (of_dictionary_filter_block_t)block;
- (OFDictionary OF_GENERIC(KeyType, ObjectType) *)
    filteredDictionaryUsingBlock: (OFDictionaryFilterBlock)block;
#endif
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef KeyType
# undef ObjectType
#endif
@end

Modified src/OFDictionary.m from [45778dda9e] to [18419a43d0].

170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
170
171
172
173
174
175
176

177
178
179
180
181
182
183
184







-
+







}

- (unsigned int)retainCount
{
	return OF_RETAIN_COUNT_MAX;
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character < CHAR_MAX && of_ascii_isalnum(character))
		return true;

	switch (character) {
	case '-':
	case '.':
503
504
505
506
507
508
509
510

511
512
513
514
515
516
517
503
504
505
506
507
508
509

510
511
512
513
514
515
516
517







-
+








- (OFEnumerator *)objectEnumerator
{
	return [[[OFDictionaryObjectEnumerator alloc]
	    initWithDictionary: self] autorelease];
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	OFEnumerator *enumerator;
	int i;

	memcpy(&enumerator, state->extra, sizeof(enumerator));
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
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







-
+
-











-
+













-
+
-







		objects[i] = object;
	}

	return i;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndObjectsUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock: (OFDictionaryEnumerationBlock)block
    (of_dictionary_enumeration_block_t)block
{
	bool stop = false;

	for (id key in self) {
		block(key, [self objectForKey: key], &stop);

		if (stop)
			break;
	}
}

- (OFDictionary *)mappedDictionaryUsingBlock: (of_dictionary_map_block_t)block
- (OFDictionary *)mappedDictionaryUsingBlock: (OFDictionaryMapBlock)block
{
	OFMutableDictionary *new = [OFMutableDictionary dictionary];

	[self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object,
	    bool *stop) {
		[new setObject: block(key, object) forKey: key];
	}];

	[new makeImmutable];

	return new;
}

- (OFDictionary *)filteredDictionaryUsingBlock:
- (OFDictionary *)filteredDictionaryUsingBlock: (OFDictionaryFilterBlock)block
    (of_dictionary_filter_block_t)block
{
	OFMutableDictionary *new = [OFMutableDictionary dictionary];

	[self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object,
	    bool *stop) {
		if (block(key, object))
			[new setObject: object forKey: key];

Deleted src/OFDimensionValue.h version [1e5243cb9c].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28




























-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFValue.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFDimensionValue: OFValue
{
	of_dimension_t _dimension;
}

- (instancetype)initWithDimension: (of_dimension_t)dimension;
@end

OF_ASSUME_NONNULL_END

Deleted src/OFDimensionValue.m version [8d1db9e33c].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53





















































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFDimensionValue.h"
#import "OFMethodSignature.h"
#import "OFString.h"

#import "OFOutOfRangeException.h"

@implementation OFDimensionValue
@synthesize dimensionValue = _dimension;

- (instancetype)initWithDimension: (of_dimension_t)dimension
{
	self = [super init];

	_dimension = dimension;

	return self;
}

- (const char *)objCType
{
	return @encode(of_dimension_t);
}

- (void)getValue: (void *)value size: (size_t)size
{
	if (size != sizeof(_dimension))
		@throw [OFOutOfRangeException exception];

	memcpy(value, &_dimension, sizeof(_dimension));
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFValue: of_dimension_t { %f, %f }>",
	    _dimension.width, _dimension.height];
}
@end

Modified src/OFEnumerator.h from [a48f5dd585] to [aa2de24ec1].

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







-
+



-
+










-
+







/*
 * This needs to be exactly like this because it's hard-coded in the compiler.
 *
 * We need this bad check to see if we already imported Cocoa, which defines
 * this as well.
 */
/**
 * @struct of_fast_enumeration_state_t OFEnumerator.h ObjFW/OFEnumerator.h
 * @struct OFFastEnumerationState OFEnumerator.h ObjFW/OFEnumerator.h
 *
 * @brief State information for fast enumerations.
 */
#define of_fast_enumeration_state_t NSFastEnumerationState
#define OFFastEnumerationState 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;
	/** Arbitrary state information to detect mutations */
	unsigned long *_Nullable mutationsPtr;
	/** Additional arbitrary state information */
	unsigned long extra[5];
} of_fast_enumeration_state_t;
} OFFastEnumerationState;
#endif

/**
 * @protocol OFFastEnumeration OFEnumerator.h ObjFW/OFEnumerator.h
 *
 * @brief A protocol for fast enumeration.
 *
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







-
+







 *
 * @param state Context information for the enumeration
 * @param objects A pointer to an array where to put the objects
 * @param count The number of objects that can be stored at objects
 * @return The number of objects returned in objects or 0 when the enumeration
 *	   finished.
 */
- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id __unsafe_unretained _Nonnull *_Nonnull)
					objects
			     count: (int)count;
@end

/**
 * @class OFEnumerator OFEnumerator.h ObjFW/OFEnumerator.h

Modified src/OFEnumerator.m from [c36212a268] to [e234a4699e].

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







-
+







	[ret makeImmutable];

	objc_autoreleasePoolPop(pool);

	return ret;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	int i;

	state->itemsPtr = objects;
	state->mutationsPtr = (unsigned long *)self;

Modified src/OFEpollKernelEventObserver.m from [11ad156308] to [deb106197e].

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







-
+







	[self of_removeObject: object
	       fileDescriptor: object.fileDescriptorForWriting
		       events: EPOLLOUT];

	[super removeObjectForWriting: object];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
- (void)observeForTimeInterval: (OFTimeInterval)timeInterval
{
	OFNull *nullObject = [OFNull null];
	struct epoll_event eventList[EVENTLIST_SIZE];
	int events;

	if ([self of_processReadBuffers])
		return;

Modified src/OFFileManager.h from [056f59171f] to [a969db1ae2].

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












61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77








78
79
80
81

82
83
84
85


86
87

88
89
90
91
92


93
94
95


96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111

112
113
114
115
116

117
118
119
120
121
122
123
124

125
126
127

128
129
130

131
132

133
134
135

136
137
138

139
140

141
142
143

144
145
146

147
148

149
150
151

152
153
154

155
156

157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172

173
174
175
176
177
178
179
180

181
182
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
42
43
44
45
46
47
48












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

64
65
66
67
68
69
70







71
72
73
74
75
76
77
78
79
80
81

82
83
84


85
86
87

88

89
90


91
92
93


94
95
96
97
98
99
100
101
102
103
104
105

106
107
108
109
110

111
112
113
114
115

116
117
118
119
120
121
122
123

124
125
126

127
128
129

130
131

132
133
134

135
136
137

138
139

140
141
142

143
144
145

146
147

148
149
150

151
152
153

154
155

156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171

172
173
174
175
176
177
178
179

180
181
182
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







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



-
+






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



-
+


-
-
+
+

-
+
-


-
-
+
+

-
-
+
+










-
+




-
+




-
+







-
+


-
+


-
+

-
+


-
+


-
+

-
+


-
+


-
+

-
+


-
+


-
+

-
+







-
+







-
+







-
+







-
+







-
+
-




-
+




-
+




-
+




-
+




-
+




-
+




-
+







@class OFURL;

/**
 * @brief A key for a file attribute in the file attributes dictionary.
 *
 * Possible keys for file URLs are:
 *
 *  * @ref of_file_attribute_key_size
 *  * @ref of_file_attribute_key_type
 *  * @ref of_file_attribute_key_posix_permissions
 *  * @ref of_file_attribute_key_posix_uid
 *  * @ref of_file_attribute_key_posix_gid
 *  * @ref of_file_attribute_key_owner
 *  * @ref of_file_attribute_key_group
 *  * @ref of_file_attribute_key_last_access_date
 *  * @ref of_file_attribute_key_modification_date
 *  * @ref of_file_attribute_key_status_change_date
 *  * @ref of_file_attribute_key_creation_date
 *  * @ref of_file_attribute_key_symbolic_link_destination
 *  * @ref OFFileSize
 *  * @ref OFFileType
 *  * @ref OFFilePOSIXPermissions
 *  * @ref OFFileOwnerAccountID
 *  * @ref OFFileGroupOwnerAccountID
 *  * @ref OFFileOwnerAccountName
 *  * @ref OFFileGroupOwnerAccountName
 *  * @ref OFFileLastAccessDate
 *  * @ref OFFileModificationDate
 *  * @ref OFFileStatusChangeDate
 *  * @ref OFFileCreationDate
 *  * @ref OFFileSymbolicLinkDestination
 *
 * Other URL schemes might not have all keys and might have keys not listed.
 */
typedef OFConstantString *of_file_attribute_key_t;
typedef OFConstantString *OFFileAttributeKey;

/**
 * @brief The type of a file.
 *
 * Possibles values for file URLs are:
 *
 *  * @ref of_file_type_regular
 *  * @ref of_file_type_directory
 *  * @ref of_file_type_symbolic_link
 *  * @ref of_file_type_fifo
 *  * @ref of_file_type_character_special
 *  * @ref of_file_type_block_special
 *  * @ref of_file_type_socket
 *  * @ref OFFileTypeRegular
 *  * @ref OFFileTypeDirectory
 *  * @ref OFFileTypeSymbolicLink
 *  * @ref OFFileTypeFIFO
 *  * @ref OFFileTypeCharacterSpecial
 *  * @ref OFFileTypeBlockSpecial
 *  * @ref OFFileTypeSocket
 *  * @ref OFFileTypeUnknown
 *
 * Other URL schemes might not have all types and might have types not listed.
 */
typedef OFConstantString *of_file_type_t;
typedef OFConstantString *OFFileAttributeType;

/**
 * @brief A dictionary mapping keys of type @ref of_file_attribute_key_t
 *	  to their attribute values.
 * @brief A dictionary mapping keys of type @ref OFFileAttributeKey to their
 *	  attribute values.
 */
typedef OFDictionary OF_GENERIC(of_file_attribute_key_t, id)
typedef OFDictionary OF_GENERIC(OFFileAttributeKey, id) *OFFileAttributes;
    *of_file_attributes_t;

/**
 * @brief A mutable dictionary mapping keys of type
 *	  @ref of_file_attribute_key_t to their attribute values.
 * @brief A mutable dictionary mapping keys of type @ref OFFileAttributeKey to
 *	  their attribute values.
 */
typedef OFMutableDictionary OF_GENERIC(of_file_attribute_key_t, id)
    *of_mutable_file_attributes_t;
typedef OFMutableDictionary OF_GENERIC(OFFileAttributeKey, id)
    *OFMutableFileAttributes;

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief The size of the file as an @ref OFNumber.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileSize.
 */
extern const of_file_attribute_key_t of_file_attribute_key_size;
extern const OFFileAttributeKey OFFileSize;

/**
 * @brief The type of the file.
 *
 * The corresponding value is of type @ref of_file_type_t.
 * The corresponding value is of type @ref OFFileAttributeType.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileType.
 */
extern const of_file_attribute_key_t of_file_attribute_key_type;
extern const OFFileAttributeKey OFFileType;

/**
 * @brief The POSIX permissions of the file as an @ref OFNumber.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#filePOSIXPermissions.
 */
extern const of_file_attribute_key_t of_file_attribute_key_posix_permissions;
extern const OFFileAttributeKey OFFilePOSIXPermissions;

/**
 * @brief The POSIX UID of the file as an @ref OFNumber.
 * @brief The account ID of the owner of the file as an @ref OFNumber.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#filePOSIXUID.
 * via @ref OFDictionary#fileOwnerAccountID.
 */
extern const of_file_attribute_key_t of_file_attribute_key_posix_uid;
extern const OFFileAttributeKey OFFileOwnerAccountID;

/**
 * @brief The POSIX GID of the file as an @ref OFNumber.
 * @brief The account ID of the group owner of the file as an @ref OFNumber.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#filePOSIXGID.
 * via @ref OFDictionary#fileGroupOwnerAccountID.
 */
extern const of_file_attribute_key_t of_file_attribute_key_posix_gid;
extern const OFFileAttributeKey OFFileGroupOwnerAccountID;

/**
 * @brief The owner of the file as an OFString.
 * @brief The account name of the owner of the file as an OFString.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileOwner.
 * via @ref OFDictionary#fileOwnerAccountName.
 */
extern const of_file_attribute_key_t of_file_attribute_key_owner;
extern const OFFileAttributeKey OFFileOwnerAccountName;

/**
 * @brief The group of the file as an OFString.
 * @brief The account name of the group owner of the file as an OFString.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileGroup.
 * via @ref OFDictionary#fileGroupOwnerAccountName.
 */
extern const of_file_attribute_key_t of_file_attribute_key_group;
extern const OFFileAttributeKey OFFileGroupOwnerAccountName;

/**
 * @brief The last access date of the file as an @ref OFDate.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileLastAccessDate.
 */
extern const of_file_attribute_key_t of_file_attribute_key_last_access_date;
extern const OFFileAttributeKey OFFileLastAccessDate;

/**
 * @brief The last modification date of the file as an @ref OFDate.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileModificationDate.
 */
extern const of_file_attribute_key_t of_file_attribute_key_modification_date;
extern const OFFileAttributeKey OFFileModificationDate;

/**
 * @brief The last status change date of the file as an @ref OFDate.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileStatusChangeDate.
 */
extern const of_file_attribute_key_t of_file_attribute_key_status_change_date;
extern const OFFileAttributeKey OFFileStatusChangeDate;

/**
 * @brief The creation date of the file as an @ref OFDate.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileCreationDate.
 */
extern const of_file_attribute_key_t of_file_attribute_key_creation_date;
extern const OFFileAttributeKey OFFileCreationDate;

/**
 * @brief The destination of a symbolic link as an OFString.
 *
 * For convenience, a category on @ref OFDictionary is provided to access this
 * via @ref OFDictionary#fileSymbolicLinkDestination.
 */
extern const of_file_attribute_key_t
extern const OFFileAttributeKey OFFileSymbolicLinkDestination;
    of_file_attribute_key_symbolic_link_destination;

/**
 * @brief A regular file.
 */
extern const of_file_type_t of_file_type_regular;
extern const OFFileAttributeType OFFileTypeRegular;

/**
 * @brief A directory.
 */
extern const of_file_type_t of_file_type_directory;
extern const OFFileAttributeType OFFileTypeDirectory;

/**
 * @brief A symbolic link.
 */
extern const of_file_type_t of_file_type_symbolic_link;
extern const OFFileAttributeType OFFileTypeSymbolicLink;

/**
 * @brief A FIFO.
 */
extern const of_file_type_t of_file_type_fifo;
extern const OFFileAttributeType OFFileTypeFIFO;

/**
 * @brief A character special file.
 */
extern const of_file_type_t of_file_type_character_special;
extern const OFFileAttributeType OFFileTypeCharacterSpecial;

/**
 * @brief A block special file.
 */
extern const of_file_type_t of_file_type_block_special;
extern const OFFileAttributeType OFFileTypeBlockSpecial;

/**
 * @brief A socket.
 */
extern const of_file_type_t of_file_type_socket;
extern const OFFileAttributeType OFFileTypeSocket;
#ifdef __cplusplus
}
#endif

/**
 * @class OFFileManager OFFileManager.h ObjFW/OFFileManager.h
 *
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
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







-
+

-
+







-
+

-
+










-
+











-
-
+








#ifdef OF_HAVE_FILES
/**
 * @brief Returns the attributes for the item at the specified path.
 *
 * @param path The path to return the attributes for
 * @return A dictionary of attributes for the specified path, with the keys of
 *	   type @ref of_file_attribute_key_t
 *	   type @ref OFFileAttributeKey
 */
- (of_file_attributes_t)attributesOfItemAtPath: (OFString *)path;
- (OFFileAttributes)attributesOfItemAtPath: (OFString *)path;
#endif

/**
 * @brief Returns the attributes for the item at the specified URL.
 *
 * @param URL The URL to return the attributes for
 * @return A dictionary of attributes for the specified URL, with the keys of
 *	   type @ref of_file_attribute_key_t
 *	   type @ref OFFileAttributeKey
 */
- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL;
- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL;

#ifdef OF_HAVE_FILES
/**
 * @brief Sets the attributes for the item at the specified path.
 *
 * All attributes not part of the dictionary are left unchanged.
 *
 * @param attributes The attributes to set for the specified path
 * @param path The path of the item to set the attributes for
 */
- (void)setAttributes: (of_file_attributes_t)attributes
- (void)setAttributes: (OFFileAttributes)attributes
	 ofItemAtPath: (OFString *)path;
#endif

/**
 * @brief Sets the attributes for the item at the specified URL.
 *
 * All attributes not part of the dictionary are left unchanged.
 *
 * @param attributes The attributes to set for the specified URL
 * @param URL The URL of the item to set the attributes for
 */
- (void)setAttributes: (of_file_attributes_t)attributes
	  ofItemAtURL: (OFURL *)URL;
- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL;

#ifdef OF_HAVE_FILES
/**
 * @brief Checks whether a file exists at the specified path.
 *
 * @param path The path to check
 * @return A boolean whether there is a file at the specified path
562
563
564
565
566
567
568
569

570
571
572
573
574
575
576

577
578
579
580

581
582
583

584
585
586
587
588
589
590
591

592
593
594
595

596
597
598

599
600
601
602

603
604
605

606
607
608
609

610
611
612

613
614
615
616

617
618
619
620

621
622
623
624
625
626
627
628

629
630
631
632
633
634
635
636

637
638
639
640
641
642
643

644
645
646
647
648
649
650

651
652
653
654
655
656
657
658
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







-
+






-
+



-
+


-
+
-






-
+



-
+


-
+



-
+


-
+



-
+


-
+



-
+


-
-
+






-
-
+






-
-
+






-
+






-
+
-







 */
- (void)createSymbolicLinkAtURL: (OFURL *)URL
	    withDestinationPath: (OFString *)target;
@end

@interface OFDictionary (FileAttributes)
/**
 * @brief The @ref of_file_attribute_key_size key from the dictionary.
 * @brief The @ref OFFileSize key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) unsigned long long fileSize;

/**
 * @brief The @ref of_file_attribute_key_type key from the dictionary.
 * @brief The @ref OFFileType key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) of_file_type_t fileType;
@property (readonly, nonatomic) OFFileAttributeType fileType;

/**
 * @brief The @ref of_file_attribute_key_posix_permissions key from the
 * @brief The @ref OFFilePOSIXPermissions key from the dictionary.
 *	  dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) unsigned long filePOSIXPermissions;

/**
 * @brief The @ref of_file_attribute_key_posix_uid key from the dictionary.
 * @brief The @ref OFFileOwnerAccountID key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) unsigned long filePOSIXUID;
@property (readonly, nonatomic) unsigned long fileOwnerAccountID;

/**
 * @brief The @ref of_file_attribute_key_posix_gid key from the dictionary.
 * @brief The @ref OFFileGroupOwnerAccountID key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) unsigned long filePOSIXGID;
@property (readonly, nonatomic) unsigned long fileGroupOwnerAccountID;

/**
 * @brief The @ref of_file_attribute_key_owner key from the dictionary.
 * @brief The @ref OFFileOwnerAccountName key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFString *fileOwner;
@property (readonly, nonatomic) OFString *fileOwnerAccountName;

/**
 * @brief The @ref of_file_attribute_key_group key from the dictionary.
 * @brief The @ref OFFileGroupOwnerAccountName key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFString *fileGroup;
@property (readonly, nonatomic) OFString *fileGroupOwnerAccountName;

/**
 * @brief The @ref of_file_attribute_key_last_access_date key from the
 *	  dictionary.
 * @brief The @ref OFFileLastAccessDate key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFDate *fileLastAccessDate;

/**
 * @brief The @ref of_file_attribute_key_modification_date key from the
 *	  dictionary.
 * @brief The @ref OFFileModificationDate key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFDate *fileModificationDate;

/**
 * @brief The @ref of_file_attribute_key_status_change_date key from the
 *	  dictionary.
 * @brief The @ref OFFileStatusChangeDate key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFDate *fileStatusChangeDate;

/**
 * @brief The @ref of_file_attribute_key_creation_date key from the dictionary.
 * @brief The @ref OFFileCreationDate key from the dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFDate *fileCreationDate;

/**
 * @brief The @ref of_file_attribute_key_symbolic_link_destination key from the
 * @brief The @ref OFFileSymbolicLinkDestination key from the dictionary.
 *	  dictionary.
 *
 * Raises an @ref OFUndefinedKeyException if the key is missing.
 */
@property (readonly, nonatomic) OFString *fileSymbolicLinkDestination;
@end

OF_ASSUME_NONNULL_END

Modified src/OFFileManager.m from [89ccc3daf1] to [abf911c67b].

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







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

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



















-
+
-







# include <proto/exec.h>
# include <proto/dos.h>
#endif

@interface OFDefaultFileManager: OFFileManager
@end

const of_file_attribute_key_t of_file_attribute_key_size =
    @"of_file_attribute_key_size";
const OFFileAttributeKey OFFileSize = @"OFFileSize";
const of_file_attribute_key_t of_file_attribute_key_type =
    @"of_file_attribute_key_type";
const OFFileAttributeKey OFFileType = @"OFFileType";
const of_file_attribute_key_t of_file_attribute_key_posix_permissions =
    @"of_file_attribute_key_posix_permissions";
const OFFileAttributeKey OFFilePOSIXPermissions = @"OFFilePOSIXPermissions";
const of_file_attribute_key_t of_file_attribute_key_posix_uid =
    @"of_file_attribute_key_posix_uid";
const OFFileAttributeKey OFFileOwnerAccountID = @"OFFileOwnerAccountID";
const of_file_attribute_key_t of_file_attribute_key_posix_gid =
    @"of_file_attribute_key_posix_gid";
const OFFileAttributeKey OFFileGroupOwnerAccountID =
const of_file_attribute_key_t of_file_attribute_key_owner =
    @"of_file_attribute_key_owner";
const of_file_attribute_key_t of_file_attribute_key_group =
    @"of_file_attribute_key_group";
    @"OFFileGroupOwnerAccountID";
const OFFileAttributeKey OFFileOwnerAccountName = @"OFFileOwnerAccountName";
const OFFileAttributeKey OFFileGroupOwnerAccountName =
    @"OFFileGroupOwnerAccountName";
const of_file_attribute_key_t of_file_attribute_key_last_access_date =
    @"of_file_attribute_key_last_access_date";
const of_file_attribute_key_t of_file_attribute_key_modification_date =
    @"of_file_attribute_key_modification_date";
const OFFileAttributeKey OFFileLastAccessDate = @"OFFileLastAccessDate";
const OFFileAttributeKey OFFileModificationDate = @"OFFileModificationDate";
const OFFileAttributeKey OFFileStatusChangeDate = @"OFFileStatusChangeDate";
const of_file_attribute_key_t of_file_attribute_key_status_change_date =
    @"of_file_attribute_key_status_change_date";
const OFFileAttributeKey OFFileCreationDate = @"OFFileCreationDate";
const of_file_attribute_key_t of_file_attribute_key_creation_date =
    @"of_file_attribute_key_creation_date";
const OFFileAttributeKey OFFileSymbolicLinkDestination =
const of_file_attribute_key_t of_file_attribute_key_symbolic_link_destination =
    @"of_file_attribute_key_symbolic_link_destination";
    @"OFFileSymbolicLinkDestination";

const of_file_type_t of_file_type_regular = @"of_file_type_regular";
const OFFileAttributeType OFFileTypeRegular = @"OFFileTypeRegular";
const of_file_type_t of_file_type_directory = @"of_file_type_directory";
const of_file_type_t of_file_type_symbolic_link = @"of_file_type_symbolic_link";
const of_file_type_t of_file_type_fifo = @"of_file_type_fifo";
const of_file_type_t of_file_type_character_special =
    @"of_file_type_character_special";
const OFFileAttributeType OFFileTypeDirectory = @"OFFileTypeDirectory";
const OFFileAttributeType OFFileTypeSymbolicLink = @"OFFileTypeSymbolicLink";
const OFFileAttributeType OFFileTypeFIFO = @"OFFileTypeFIFO";
const OFFileAttributeType OFFileTypeCharacterSpecial =
    @"OFFileTypeCharacterSpecial";
const of_file_type_t of_file_type_block_special = @"of_file_type_block_special";
const of_file_type_t of_file_type_socket = @"of_file_type_socket";
const OFFileAttributeType OFFileTypeBlockSpecial = @"OFFileTypeBlockSpecial";
const OFFileAttributeType OFFileTypeSocket = @"OFFileTypeSocket";

#ifdef OF_AMIGAOS4
# define CurrentDir(lock) SetCurrentDir(lock)
#endif

static OFFileManager *defaultManager;

#ifdef OF_AMIGAOS
static bool dirChanged = false;
static BPTR originalDirLock = 0;

OF_DESTRUCTOR()
{
	if (dirChanged)
		UnLock(CurrentDir(originalDirLock));
}
#endif

static id
attributeForKeyOrException(of_file_attributes_t attributes,
attributeForKeyOrException(OFFileAttributes attributes, OFFileAttributeKey key)
    of_file_attribute_key_t key)
{
	id object = [attributes objectForKey: key];

	if (object == nil)
		@throw [OFUndefinedKeyException exceptionWithObject: attributes
								key: key];

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







-
+













-
+


-
+











-
-
+













-
+








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

- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL
- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL
{
	OFURLHandler *URLHandler;

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

	if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil)
		@throw [OFUnsupportedProtocolException exceptionWithURL: URL];

	return [URLHandler attributesOfItemAtURL: URL];
}

#ifdef OF_HAVE_FILES
- (of_file_attributes_t)attributesOfItemAtPath: (OFString *)path
- (OFFileAttributes)attributesOfItemAtPath: (OFString *)path
{
	void *pool = objc_autoreleasePoolPush();
	of_file_attributes_t ret;
	OFFileAttributes ret;

	ret = [self attributesOfItemAtURL: [OFURL fileURLWithPath: path]];

	[ret retain];

	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}
#endif

- (void)setAttributes: (of_file_attributes_t)attributes
	  ofItemAtURL: (OFURL *)URL
- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL
{
	OFURLHandler *URLHandler;

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

	if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil)
		@throw [OFUnsupportedProtocolException exceptionWithURL: URL];

	[URLHandler setAttributes: attributes ofItemAtURL: URL];
}

#ifdef OF_HAVE_FILES
- (void)setAttributes: (of_file_attributes_t)attributes
- (void)setAttributes: (OFFileAttributes)attributes
	 ofItemAtPath: (OFString *)path
{
	void *pool = objc_autoreleasePoolPush();
	[self setAttributes: attributes
		ofItemAtURL: [OFURL fileURLWithPath: path]];
	objc_autoreleasePoolPop(pool);
}
565
566
567
568
569
570
571
572
573


574
575
576
577
578
579
580
554
555
556
557
558
559
560


561
562
563
564
565
566
567
568
569







-
-
+
+







}
#endif

- (void)copyItemAtURL: (OFURL *)source toURL: (OFURL *)destination
{
	void *pool;
	OFURLHandler *URLHandler;
	of_file_attributes_t attributes;
	of_file_type_t type;
	OFFileAttributes attributes;
	OFFileAttributeType type;

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

	pool = objc_autoreleasePoolPush();

	if ((URLHandler = [OFURLHandler handlerForURL: source]) == nil)
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
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







-
+






-
+
-


-
+







		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: e.errNo];
	}

	type = attributes.fileType;

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

		@try {
			[self createDirectoryAtURL: destination];

			@try {
				of_file_attribute_key_t key =
				OFFileAttributeKey key = OFFilePOSIXPermissions;
				    of_file_attribute_key_posix_permissions;
				OFNumber *permissions =
				    [attributes objectForKey: key];
				of_file_attributes_t destinationAttributes;
				OFFileAttributes destinationAttributes;

				if (permissions != nil) {
					destinationAttributes = [OFDictionary
					    dictionaryWithObject: permissions
							  forKey: key];
					[self
					    setAttributes: destinationAttributes
648
649
650
651
652
653
654
655

656
657
658
659
660
661
662
636
637
638
639
640
641
642

643
644
645
646
647
648
649
650







-
+







			    URLByAppendingPathComponent:
			    item.lastPathComponent];

			[self copyItemAtURL: item toURL: destinationURL];

			objc_autoreleasePoolPop(pool2);
		}
	} else if ([type isEqual: of_file_type_regular]) {
	} else if ([type isEqual: OFFileTypeRegular]) {
		size_t pageSize = [OFSystemInfo pageSize];
		OFStream *sourceStream = nil;
		OFStream *destinationStream = nil;
		char *buffer;

		buffer = of_alloc(1, pageSize);
		@try {
674
675
676
677
678
679
680
681

682
683
684
685

686
687
688
689
690
691
692
662
663
664
665
666
667
668

669

670
671

672
673
674
675
676
677
678
679







-
+
-


-
+







				    readIntoBuffer: buffer
					    length: pageSize];
				[destinationStream writeBuffer: buffer
							length: length];
			}

			@try {
				of_file_attribute_key_t key =
				OFFileAttributeKey key = OFFilePOSIXPermissions;
				    of_file_attribute_key_posix_permissions;
				OFNumber *permissions = [attributes
				    objectForKey: key];
				of_file_attributes_t destinationAttributes;
				OFFileAttributes destinationAttributes;

				if (permissions != nil) {
					destinationAttributes = [OFDictionary
					    dictionaryWithObject: permissions
							  forKey: key];
					[self
					    setAttributes: destinationAttributes
709
710
711
712
713
714
715
716

717
718
719
720
721
722
723
696
697
698
699
700
701
702

703
704
705
706
707
708
709
710







-
+








			@throw e;
		} @finally {
			[sourceStream close];
			[destinationStream close];
			free(buffer);
		}
	} else if ([type isEqual: of_file_type_symbolic_link]) {
	} else if ([type isEqual: OFFileTypeSymbolicLink]) {
		@try {
			OFString *linkDestination =
			    attributes.fileSymbolicLinkDestination;

			[self createSymbolicLinkAtURL: destination
				  withDestinationPath: linkDestination];
		} @catch (id e) {
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
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







-
+



-
+

-
+





-
+


-
+


-
+


-
+


-
+


-
+

-
+


-
+

-
+




-
+
-




-
+
-




-
+
-




-
+
-




-
+
-


	return OF_RETAIN_COUNT_MAX;
}
@end

@implementation OFDictionary (FileAttributes)
- (unsigned long long)fileSize
{
	return [attributeForKeyOrException(self, of_file_attribute_key_size)
	return [attributeForKeyOrException(self, OFFileSize)
	    unsignedLongLongValue];
}

- (of_file_type_t)fileType
- (OFFileAttributeType)fileType
{
	return attributeForKeyOrException(self, of_file_attribute_key_type);
	return attributeForKeyOrException(self, OFFileType);
}

- (unsigned long)filePOSIXPermissions
{
	return [attributeForKeyOrException(self,
	    of_file_attribute_key_posix_permissions) unsignedLongValue];
	    OFFilePOSIXPermissions) unsignedLongValue];
}

- (unsigned long)filePOSIXUID
- (unsigned long)fileOwnerAccountID
{
	return [attributeForKeyOrException(self,
	    of_file_attribute_key_posix_uid) unsignedLongValue];
	    OFFileOwnerAccountID) unsignedLongValue];
}

- (unsigned long)filePOSIXGID
- (unsigned long)fileGroupOwnerAccountID
{
	return [attributeForKeyOrException(self,
	    of_file_attribute_key_posix_gid) unsignedLongValue];
	    OFFileGroupOwnerAccountID) unsignedLongValue];
}

- (OFString *)fileOwner
- (OFString *)fileOwnerAccountName
{
	return attributeForKeyOrException(self, of_file_attribute_key_owner);
	return attributeForKeyOrException(self, OFFileOwnerAccountName);
}

- (OFString *)fileGroup
- (OFString *)fileGroupOwnerAccountName
{
	return attributeForKeyOrException(self, of_file_attribute_key_group);
	return attributeForKeyOrException(self, OFFileGroupOwnerAccountName);
}

- (OFDate *)fileLastAccessDate
{
	return attributeForKeyOrException(self,
	return attributeForKeyOrException(self, OFFileLastAccessDate);
	    of_file_attribute_key_last_access_date);
}

- (OFDate *)fileModificationDate
{
	return attributeForKeyOrException(self,
	return attributeForKeyOrException(self, OFFileModificationDate);
	    of_file_attribute_key_modification_date);
}

- (OFDate *)fileStatusChangeDate
{
	return attributeForKeyOrException(self,
	return attributeForKeyOrException(self, OFFileStatusChangeDate);
	    of_file_attribute_key_status_change_date);
}

- (OFDate *)fileCreationDate
{
	return attributeForKeyOrException(self,
	return attributeForKeyOrException(self, OFFileCreationDate);
	    of_file_attribute_key_creation_date);
}

- (OFString *)fileSymbolicLinkDestination
{
	return attributeForKeyOrException(self,
	return attributeForKeyOrException(self, OFFileSymbolicLinkDestination);
	    of_file_attribute_key_symbolic_link_destination);
}
@end

Modified src/OFFileURLHandler.m from [db7a703dd2] to [46f9d28643].

85
86
87
88
89
90
91
92

93
94
95

96
97
98
99
100
101
102
85
86
87
88
89
90
91

92
93
94

95
96
97
98
99
100
101
102







-
+


-
+







# endif
#endif

#if defined(OF_WINDOWS) || defined(OF_AMIGAOS)
typedef struct {
	of_offset_t st_size;
	unsigned int st_mode;
	of_time_interval_t st_atime, st_mtime, st_ctime;
	OFTimeInterval st_atime, st_mtime, st_ctime;
# ifdef OF_WINDOWS
#  define HAVE_STRUCT_STAT_ST_BIRTHTIME
	of_time_interval_t st_birthtime;
	OFTimeInterval st_birthtime;
	DWORD fileAttributes;
# endif
} of_stat_t;
#elif defined(HAVE_STAT64)
typedef struct stat64 of_stat_t;
#else
typedef struct stat of_stat_t;
130
131
132
133
134
135
136
137

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

137
138
139
140
141
142
143
144







-
+







static int (*func__wutime64)(const wchar_t *, struct __utimbuf64 *);
static WINAPI BOOLEAN (*func_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD);
static WINAPI BOOLEAN (*func_CreateHardLinkW)(LPCWSTR, LPCWSTR,
    LPSECURITY_ATTRIBUTES);
#endif

#ifdef OF_WINDOWS
static of_time_interval_t
static OFTimeInterval
filetimeToTimeInterval(const FILETIME *filetime)
{
	return (double)((int64_t)filetime->dwHighDateTime << 32 |
	    filetime->dwLowDateTime) / 10000000.0 - 11644473600.0;
}

static int
258
259
260
261
262
263
264
265

266
267
268
269
270
271
272
258
259
260
261
262
263
264

265
266
267
268
269
270
271
272







-
+







#elif defined(OF_AMIGAOS)
	BPTR lock;
# ifdef OF_AMIGAOS4
	struct ExamineData *ed;
# else
	struct FileInfoBlock fib;
# endif
	of_time_interval_t timeInterval;
	OFTimeInterval timeInterval;
	struct Locale *locale;
	struct DateStamp *date;

	if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]],
	    SHARED_LOCK)) == 0)
		return retrieveError();

311
312
313
314
315
316
317
318

319
320
321
322
323
324
325
311
312
313
314
315
316
317

318
319
320
321
322
323
324
325







-
+







# ifdef OF_AMIGAOS4
	date = &ed->Date;
# else
	date = &fib.fib_Date;
# endif
	timeInterval += date->ds_Days * 86400.0;
	timeInterval += date->ds_Minute * 60.0;
	timeInterval += date->ds_Tick / (of_time_interval_t)TICKS_PER_SECOND;
	timeInterval += date->ds_Tick / (OFTimeInterval)TICKS_PER_SECOND;

	buffer->st_atime = buffer->st_mtime = buffer->st_ctime = timeInterval;

# ifdef OF_AMIGAOS4
	FreeDosObject(DOS_EXAMINEDATA, ed);
# endif

355
356
357
358
359
360
361
362

363
364
365

366
367
368

369
370
371
372
373


374
375
376
377

378
379
380
381
382
383


384
385
386
387
388


389
390
391
392

393
394
395
396
397
398

399
400
401
402
403

404
405
406

407
408
409

410
411
412
413

414
415
416
417
418

419
420
421
422
423

424
425

426
427
428
429
430
431

432
433
434
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
355
356
357
358
359
360
361

362
363
364

365

366

367

368
369


370
371
372
373
374

375

376
377
378


379
380
381
382
383


384
385
386
387
388

389

390
391
392
393

394
395
396
397
398

399
400
401

402
403
404

405
406
407
408

409
410
411
412
413

414

415
416
417

418
419

420
421
422
423
424
425

426
427
428
429
430
431
432
433
434
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







-
+


-
+
-

-
+
-


-
-
+
+



-
+
-



-
-
+
+



-
-
+
+



-
+
-




-
+




-
+


-
+


-
+



-
+




-
+
-



-
+

-
+





-
+









-
+








-
+











-
+




-
+



-













-
-
+
+







	return 0;
#else
	return of_stat(path, buffer);
#endif
}

static void
setTypeAttribute(of_mutable_file_attributes_t attributes, of_stat_t *s)
setTypeAttribute(OFMutableFileAttributes attributes, of_stat_t *s)
{
	if (S_ISREG(s->st_mode))
		[attributes setObject: of_file_type_regular
		[attributes setObject: OFFileTypeRegular forKey: OFFileType];
			       forKey: of_file_attribute_key_type];
	else if (S_ISDIR(s->st_mode))
		[attributes setObject: of_file_type_directory
		[attributes setObject: OFFileTypeDirectory forKey: OFFileType];
			       forKey: of_file_attribute_key_type];
#ifdef S_ISLNK
	else if (S_ISLNK(s->st_mode))
		[attributes setObject: of_file_type_symbolic_link
			       forKey: of_file_attribute_key_type];
		[attributes setObject: OFFileTypeSymbolicLink
			       forKey: OFFileType];
#endif
#ifdef S_ISFIFO
	else if (S_ISFIFO(s->st_mode))
		[attributes setObject: of_file_type_fifo
		[attributes setObject: OFFileTypeFIFO forKey: OFFileType];
			       forKey: of_file_attribute_key_type];
#endif
#ifdef S_ISCHR
	else if (S_ISCHR(s->st_mode))
		[attributes setObject: of_file_type_character_special
			       forKey: of_file_attribute_key_type];
		[attributes setObject: OFFileTypeCharacterSpecial
			       forKey: OFFileType];
#endif
#ifdef S_ISBLK
	else if (S_ISBLK(s->st_mode))
		[attributes setObject: of_file_type_block_special
			       forKey: of_file_attribute_key_type];
		[attributes setObject: OFFileTypeBlockSpecial
			       forKey: OFFileType];
#endif
#ifdef S_ISSOCK
	else if (S_ISSOCK(s->st_mode))
		[attributes setObject: of_file_type_socket
		[attributes setObject: OFFileTypeSocket forKey: OFFileType];
			       forKey: of_file_attribute_key_type];
#endif
}

static void
setDateAttributes(of_mutable_file_attributes_t attributes, of_stat_t *s)
setDateAttributes(OFMutableFileAttributes attributes, of_stat_t *s)
{
	/* FIXME: We could be more precise on some OSes */
	[attributes
	    setObject: [OFDate dateWithTimeIntervalSince1970: s->st_atime]
	       forKey: of_file_attribute_key_last_access_date];
	       forKey: OFFileLastAccessDate];
	[attributes
	    setObject: [OFDate dateWithTimeIntervalSince1970: s->st_mtime]
	       forKey: of_file_attribute_key_modification_date];
	       forKey: OFFileModificationDate];
	[attributes
	    setObject: [OFDate dateWithTimeIntervalSince1970: s->st_ctime]
	       forKey: of_file_attribute_key_status_change_date];
	       forKey: OFFileStatusChangeDate];
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
	[attributes
	    setObject: [OFDate dateWithTimeIntervalSince1970: s->st_birthtime]
	       forKey: of_file_attribute_key_creation_date];
	       forKey: OFFileCreationDate];
#endif
}

static void
setOwnerAndGroupAttributes(of_mutable_file_attributes_t attributes,
setOwnerAndGroupAttributes(OFMutableFileAttributes attributes, of_stat_t *s)
    of_stat_t *s)
{
#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER
	[attributes setObject: [NSNumber numberWithUnsignedLong: s->st_uid]
		       forKey: of_file_attribute_key_posix_uid];
		       forKey: OFFileOwnerAccountID];
	[attributes setObject: [NSNumber numberWithUnsignedLong: s->st_gid]
		       forKey: of_file_attribute_key_posix_gid];
		       forKey: OFFileGroupOwnerAccountID];

# ifdef OF_HAVE_THREADS
	[passwdMutex lock];
	@try {
# endif
		of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];
		struct passwd *passwd = getpwuid(s->st_uid);
		struct group *group_ = getgrgid(s->st_gid);

		if (passwd != NULL) {
			OFString *owner = [OFString
			    stringWithCString: passwd->pw_name
				     encoding: encoding];

			[attributes setObject: owner
				       forKey: of_file_attribute_key_owner];
				       forKey: OFFileOwnerAccountName];
		}

		if (group_ != NULL) {
			OFString *group = [OFString
			    stringWithCString: group_->gr_name
				     encoding: encoding];

			[attributes setObject: group
				       forKey: of_file_attribute_key_group];
				       forKey: OFFileGroupOwnerAccountName];
		}
# ifdef OF_HAVE_THREADS
	} @finally {
		[passwdMutex unlock];
	}
# endif
#endif
}

#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS
static void
setSymbolicLinkDestinationAttribute(of_mutable_file_attributes_t attributes,
setSymbolicLinkDestinationAttribute(OFMutableFileAttributes attributes,
    OFURL *URL)
{
	OFString *path = URL.fileSystemRepresentation;
# ifndef OF_WINDOWS
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];
	char destinationC[PATH_MAX];
	ssize_t length;
	OFString *destination;
	of_file_attribute_key_t key;

	length = readlink([path cStringWithEncoding: encoding], destinationC,
	    PATH_MAX);

	if (length < 0)
		@throw [OFRetrieveItemAttributesFailedException
		    exceptionWithURL: URL
			       errNo: errno];

	destination = [OFString stringWithCString: destinationC
					 encoding: encoding
					   length: length];

	key = of_file_attribute_key_symbolic_link_destination;
	[attributes setObject: destination forKey: key];
	[attributes setObject: destination
		       forKey: OFFileSymbolicLinkDestination];
# else
	HANDLE handle;
	OFString *destination;

	if (func_CreateSymbolicLinkW == NULL)
		return;

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
495
496
497
498
499
500
501

502
503
504
505
506
507
508







-







	@try {
		union {
			char bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
			REPARSE_DATA_BUFFER data;
		} buffer;
		DWORD size;
		wchar_t *tmp;
		of_file_attribute_key_t key;

		if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0,
		    buffer.bytes, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size,
		    NULL))
			@throw [OFRetrieveItemAttributesFailedException
			    exceptionWithURL: URL
				       errNo: retrieveError()];
524
525
526
527
528
529
530
531
532


533
534


535
536
537
538
539
540
541
517
518
519
520
521
522
523


524
525


526
527
528
529
530
531
532
533
534







-
-
+
+
-
-
+
+







		    (slrb.SubstituteNameOffset / sizeof(wchar_t));

		destination = [OFString
		    stringWithUTF16String: tmp
				   length: slrb.SubstituteNameLength /
					   sizeof(wchar_t)];

		[attributes setObject: of_file_type_symbolic_link
			       forKey: of_file_attribute_key_type];
		[attributes setObject: OFFileTypeSymbolicLink
			       forKey: OFFileType];
		key = of_file_attribute_key_symbolic_link_destination;
		[attributes setObject: destination forKey: key];
		[attributes setObject: destination
			       forKey: OFFileSymbolicLinkDestination];
#  undef slrb
	} @finally {
		CloseHandle(handle);
	}
# endif
}
#endif
600
601
602
603
604
605
606
607

608
609

610
611
612
613
614
615
616
593
594
595
596
597
598
599

600
601

602
603
604
605
606
607
608
609







-
+

-
+







		    mode: mode];

	objc_autoreleasePoolPop(pool);

	return [file autorelease];
}

- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL
- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL
{
	of_mutable_file_attributes_t ret = [OFMutableDictionary dictionary];
	OFMutableFileAttributes ret = [OFMutableDictionary dictionary];
	void *pool = objc_autoreleasePoolPush();
	OFString *path;
	int error;
	of_stat_t s;

	if (URL == nil)
		@throw [OFInvalidArgumentException exception];
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
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







-
+




-
+

















-
+


-
-
+
+
-







		    exceptionWithURL: URL
			       errNo: error];

	if (s.st_size < 0)
		@throw [OFOutOfRangeException exception];

	[ret setObject: [NSNumber numberWithUnsignedLongLong: s.st_size]
		forKey: of_file_attribute_key_size];
		forKey: OFFileSize];

	setTypeAttribute(ret, &s);

	[ret setObject: [NSNumber numberWithUnsignedLong: s.st_mode]
		forKey: of_file_attribute_key_posix_permissions];
		forKey: OFFilePOSIXPermissions];

	setOwnerAndGroupAttributes(ret, &s);
	setDateAttributes(ret, &s);

#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS
	if (S_ISLNK(s.st_mode))
		setSymbolicLinkDestinationAttribute(ret, URL);
#endif

	objc_autoreleasePoolPop(pool);

	return ret;
}

- (void)of_setLastAccessDate: (OFDate *)lastAccessDate
	 andModificationDate: (OFDate *)modificationDate
		 ofItemAtURL: (OFURL *)URL
		  attributes: (of_file_attributes_t)attributes OF_DIRECT
		  attributes: (OFFileAttributes)attributes OF_DIRECT
{
	OFString *path = URL.fileSystemRepresentation;
	of_file_attribute_key_t attributeKey = (modificationDate != nil
	    ? of_file_attribute_key_modification_date
	OFFileAttributeKey attributeKey = (modificationDate != nil
	    ? OFFileModificationDate : OFFileLastAccessDate);
	    : of_file_attribute_key_last_access_date);

	if (lastAccessDate == nil)
		lastAccessDate = modificationDate;
	if (modificationDate == nil)
		modificationDate = lastAccessDate;

#if defined(OF_WINDOWS)
699
700
701
702
703
704
705
706

707
708
709
710
711
712
713
691
692
693
694
695
696
697

698
699
700
701
702
703
704
705







-
+







			    exceptionWithURL: URL
				  attributes: attributes
			     failedAttribute: attributeKey
				       errNo: errno];
	}
#elif defined(OF_AMIGAOS)
	/* AmigaOS does not support access time. */
	of_time_interval_t modificationTime =
	OFTimeInterval modificationTime =
	    modificationDate.timeIntervalSince1970;
	struct Locale *locale;
	struct DateStamp date;

	modificationTime -= 252460800;	/* 1978-01-01 */

	if (modificationTime < 0)
735
736
737
738
739
740
741
742
743
744


745
746
747
748
749
750
751
727
728
729
730
731
732
733



734
735
736
737
738
739
740
741
742







-
-
-
+
+







# endif
		@throw [OFSetItemAttributesFailedException
		    exceptionWithURL: URL
			  attributes: attributes
		     failedAttribute: attributeKey
			       errNo: retrieveError()];
#else
	of_time_interval_t lastAccessTime =
	    lastAccessDate.timeIntervalSince1970;
	of_time_interval_t modificationTime =
	OFTimeInterval lastAccessTime = lastAccessDate.timeIntervalSince1970;
	OFTimeInterval modificationTime =
	    modificationDate.timeIntervalSince1970;
	struct timeval times[2] = {
		{
			.tv_sec = (time_t)lastAccessTime,
			.tv_usec =
			    (int)((lastAccessTime - times[0].tv_sec) * 1000000)
		},
763
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789

790
791
792
793
794
795
796
797
798
799
800





801
802
803
804
805
806

807
808
809
810
811
812
813
754
755
756
757
758
759
760

761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779

780
781
782
783
784
785
786





787
788
789
790
791
792
793
794
795
796

797
798
799
800
801
802
803
804







-
+


















-
+






-
-
-
-
-
+
+
+
+
+





-
+







		     failedAttribute: attributeKey
			       errNo: errno];
#endif
}

- (void)of_setPOSIXPermissions: (OFNumber *)permissions
		   ofItemAtURL: (OFURL *)URL
		    attributes: (of_file_attributes_t)attributes OF_DIRECT
		    attributes: (OFFileAttributes)attributes OF_DIRECT
{
#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
	mode_t mode = (mode_t)permissions.unsignedLongValue;
	OFString *path = URL.fileSystemRepresentation;
	int status;

# ifdef OF_WINDOWS
	if ([OFSystemInfo isWindowsNT])
		status = _wchmod(path.UTF16String, mode);
	else
# endif
		status = chmod(
		    [path cStringWithEncoding: [OFLocale encoding]], mode);

	if (status != 0)
		@throw [OFSetItemAttributesFailedException
		    exceptionWithURL: URL
			  attributes: attributes
		     failedAttribute: of_file_attribute_key_posix_permissions
		     failedAttribute: OFFilePOSIXPermissions
			       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 OF_DIRECT
- (void)of_setOwnerAccountName: (OFString *)owner
      andGroupOwnerAccountName: (OFString *)group
		   ofItemAtURL: (OFURL *)URL
		  attributeKey: (OFFileAttributeKey)attributeKey
		    attributes: (OFFileAttributes)attributes OF_DIRECT
{
#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER
	OFString *path = URL.fileSystemRepresentation;
	uid_t uid = -1;
	gid_t gid = -1;
	of_string_encoding_t encoding;
	OFStringEncoding encoding;

	if (owner == nil && group == nil)
		@throw [OFInvalidArgumentException exception];

	encoding = [OFLocale encoding];

# ifdef OF_HAVE_THREADS
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
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







-
-
+


-
+

-
+














-
-
+
+

-
+



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






-
+
-
-
+
-







		     failedAttribute: attributeKey
			       errNo: errno];
#else
	OF_UNRECOGNIZED_SELECTOR
#endif
}

- (void)setAttributes: (of_file_attributes_t)attributes
	  ofItemAtURL: (OFURL *)URL
- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL
{
	void *pool = objc_autoreleasePoolPush();
	OFEnumerator OF_GENERIC(of_file_attribute_key_t) *keyEnumerator;
	OFEnumerator OF_GENERIC(OFFileAttributeKey) *keyEnumerator;
	OFEnumerator *objectEnumerator;
	of_file_attribute_key_t key;
	OFFileAttributeKey key;
	id object;
	OFDate *lastAccessDate, *modificationDate;

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

	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	keyEnumerator = [attributes keyEnumerator];
	objectEnumerator = [attributes objectEnumerator];

	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		if ([key isEqual: of_file_attribute_key_modification_date] ||
		    [key isEqual: of_file_attribute_key_last_access_date])
		if ([key isEqual: OFFileModificationDate] ||
		    [key isEqual: OFFileLastAccessDate])
			continue;
		else if ([key isEqual: of_file_attribute_key_posix_permissions])
		else if ([key isEqual: OFFilePOSIXPermissions])
			[self of_setPOSIXPermissions: object
					 ofItemAtURL: URL
					  attributes: attributes];
		else if ([key isEqual: of_file_attribute_key_owner])
			[self of_setOwner: object
				 andGroup: nil
			      ofItemAtURL: URL
			     attributeKey: key
			       attributes: attributes];
		else if ([key isEqual: of_file_attribute_key_group])
			[self of_setOwner: nil
				 andGroup: object
			      ofItemAtURL: URL
			     attributeKey: key
			       attributes: attributes];
		else if ([key isEqual: OFFileOwnerAccountName])
			[self of_setOwnerAccountName: object
			    andGroupOwnerAccountName: nil
					 ofItemAtURL: URL
					attributeKey: key
					  attributes: attributes];
		else if ([key isEqual: OFFileGroupOwnerAccountName])
			[self of_setOwnerAccountName: nil
			    andGroupOwnerAccountName: object
					 ofItemAtURL: URL
					attributeKey: key
					  attributes: attributes];
		else
			@throw [OFNotImplementedException
			    exceptionWithSelector: _cmd
					   object: self];
	}

	lastAccessDate = [attributes
	lastAccessDate = [attributes objectForKey: OFFileLastAccessDate];
	    objectForKey: of_file_attribute_key_last_access_date];
	modificationDate = [attributes
	modificationDate = [attributes objectForKey: OFFileModificationDate];
	    objectForKey: of_file_attribute_key_modification_date];

	if (lastAccessDate != nil || modificationDate != nil)
		[self of_setLastAccessDate: lastAccessDate
		       andModificationDate: modificationDate
			       ofItemAtURL: URL
				attributes: attributes];

1064
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
1052
1053
1054
1055
1056
1057
1058

1059
1060
1061
1062
1063
1064
1065
1066







-
+







				    exceptionWithObject: self
					requestedLength: 0
						  errNo: retrieveError()];
		} @finally {
			FindClose(handle);
		}
	} else {
		of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];
		WIN32_FIND_DATA fd;

		if ((handle = FindFirstFileA(
		    [path cStringWithEncoding: encoding], &fd)) ==
		    INVALID_HANDLE_VALUE)
			@throw [OFOpenItemFailedException
			    exceptionWithURL: URL
1104
1105
1106
1107
1108
1109
1110
1111

1112
1113
1114
1115
1116
1117
1118
1092
1093
1094
1095
1096
1097
1098

1099
1100
1101
1102
1103
1104
1105
1106







-
+







					requestedLength: 0
						  errNo: retrieveError()];
		} @finally {
			FindClose(handle);
		}
	}
#elif defined(OF_AMIGAOS)
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];
	BPTR lock;

	if ((lock = Lock([path cStringWithEncoding: encoding],
	    SHARED_LOCK)) == 0)
		@throw [OFOpenItemFailedException
		    exceptionWithURL: URL
				mode: nil
1174
1175
1176
1177
1178
1179
1180
1181

1182
1183
1184
1185
1186
1187
1188
1162
1163
1164
1165
1166
1167
1168

1169
1170
1171
1172
1173
1174
1175
1176







-
+







			    exceptionWithObject: self
				requestedLength: 0
					  errNo: retrieveError()];
	} @finally {
		UnLock(lock);
	}
#else
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];
	DIR *dir;
	if ((dir = opendir([path cStringWithEncoding: encoding])) == NULL)
		@throw [OFOpenItemFailedException exceptionWithURL: URL
							      mode: nil
							     errNo: errno];

# if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS)
1356
1357
1358
1359
1360
1361
1362
1363

1364
1365
1366
1367
1368
1369
1370
1344
1345
1346
1347
1348
1349
1350

1351
1352
1353
1354
1355
1356
1357
1358







-
+







	    ![destination.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	sourcePath = source.fileSystemRepresentation;
	destinationPath = destination.fileSystemRepresentation;

# ifndef OF_WINDOWS
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];

	if (link([sourcePath cStringWithEncoding: encoding],
	    [destinationPath cStringWithEncoding: encoding]) != 0)
		@throw [OFLinkFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: errno];
1397
1398
1399
1400
1401
1402
1403
1404

1405
1406
1407
1408
1409
1410
1411
1385
1386
1387
1388
1389
1390
1391

1392
1393
1394
1395
1396
1397
1398
1399







-
+








	if (![URL.scheme isEqual: _scheme])
		@throw [OFInvalidArgumentException exception];

	path = URL.fileSystemRepresentation;

# ifndef OF_WINDOWS
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];

	if (symlink([target cStringWithEncoding: encoding],
	    [path cStringWithEncoding: encoding]) != 0)
		@throw [OFCreateSymbolicLinkFailedException
		    exceptionWithURL: URL
			      target: target
			       errNo: errno];
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
1466
1467
1468
1469
1470
1471
1426
1427
1428
1429
1430
1431
1432

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







-
+


















-
+







		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: EEXIST];

	pool = objc_autoreleasePoolPush();

#ifdef OF_AMIGAOS
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];

	if (!Rename([source.fileSystemRepresentation
	    cStringWithEncoding: encoding],
	    [destination.fileSystemRepresentation
	    cStringWithEncoding: encoding]))
		@throw [OFMoveItemFailedException
		    exceptionWithSourceURL: source
			    destinationURL: destination
				     errNo: retrieveError()];
#else
	int status;

# ifdef OF_WINDOWS
	if ([OFSystemInfo isWindowsNT])
		status = _wrename(source.fileSystemRepresentation.UTF16String,
		    destination.fileSystemRepresentation.UTF16String);
	else {
# endif
		of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];

		status = rename([source.fileSystemRepresentation
		    cStringWithEncoding: encoding],
		    [destination.fileSystemRepresentation
		    cStringWithEncoding: encoding]);
# ifdef OF_WINDOWS
	}

Modified src/OFHTTPClient.m from [02e9faa541] to [4234996a26].

317
318
319
320
321
322
323
324

325
326
327
328
329
330
331
317
318
319
320
321
322
323

324
325
326
327
328
329
330
331







-
+







		if (connectionHeader != nil)
			keepAlive = [connectionHeader isEqual: @"close"];
		else
			keepAlive = true;
	} else {
		if (connectionHeader != nil)
			keepAlive = ([connectionHeader caseInsensitiveCompare:
			    @"keep-alive"] == OF_ORDERED_SAME);
			    @"keep-alive"] == OFOrderedSame);
		else
			keepAlive = false;
	}

	if (keepAlive) {
		response.of_keepAlive = true;

344
345
346
347
348
349
350
351

352
353

354
355
356
357
358

359
360

361
362
363
364
365
366
367
344
345
346
347
348
349
350

351
352

353
354
355
356
357

358
359

360
361
362
363
364
365
366
367







-
+

-
+




-
+

-
+







		OFString *newURLScheme;

		newURL = [OFURL URLWithString: location
				relativeToURL: URL];
		newURLScheme = newURL.scheme;

		if ([newURLScheme caseInsensitiveCompare: @"http"] !=
		    OF_ORDERED_SAME &&
		    OFOrderedSame &&
		    [newURLScheme caseInsensitiveCompare: @"https"] !=
		    OF_ORDERED_SAME)
		    OFOrderedSame)
			follow = false;

		if (!_client->_allowsInsecureRedirects &&
		    [URL.scheme caseInsensitiveCompare: @"https"] ==
		    OF_ORDERED_SAME &&
		    OFOrderedSame &&
		    [newURLScheme caseInsensitiveCompare: @"http"] ==
		    OF_ORDERED_SAME)
		    OFOrderedSame)
			follow = false;

		if (follow && [_client->_delegate respondsToSelector: @selector(
		    client:shouldFollowRedirect:statusCode:request:response:)])
			follow = [_client->_delegate client: _client
				       shouldFollowRedirect: newURL
						 statusCode: _status
456
457
458
459
460
461
462
463

464
465
466
467
468

469
470
471
472
473
474
475
456
457
458
459
460
461
462

463
464
465
466
467

468
469
470
471
472
473
474
475







-
+




-
+







		return false;
	}

	if (![line hasPrefix: @"HTTP/"] || line.length < 9 ||
	    [line characterAtIndex: 8] != ' ')
		@throw [OFInvalidServerReplyException exception];

	_version = [[line substringWithRange: of_range(5, 3)] copy];
	_version = [[line substringWithRange: OFMakeRange(5, 3)] copy];
	if (![_version isEqual: @"1.0"] && ![_version isEqual: @"1.1"])
		@throw [OFUnsupportedVersionException
		    exceptionWithVersion: _version];

	status = [line substringWithRange: of_range(9, 3)].longLongValue;
	status = [line substringWithRange: OFMakeRange(9, 3)].longLongValue;

	if (status < 0 || status > 599)
		@throw [OFInvalidServerReplyException exception];

	_status = (short)status;

	return true;
565
566
567
568
569
570
571
572

573
574
575
576
577
578
579
565
566
567
568
569
570
571

572
573
574
575
576
577
578
579







-
+







	}

	return ret;
}

- (OFString *)stream: (OFStream *)stream
      didWriteString: (OFString *)string
	    encoding: (of_string_encoding_t)encoding
	    encoding: (OFStringEncoding)encoding
	bytesWritten: (size_t)bytesWritten
	   exception: (id)exception
{
	OFDictionary OF_GENERIC(OFString *, OFString *) *headers;
	bool chunked;

	if (exception != nil) {
697
698
699
700
701
702
703
704

705
706
707
708
709
710
711
697
698
699
700
701
702
703

704
705
706
707
708
709
710
711







-
+







		OFTCPSocket *sock;
		uint16_t port;
		OFNumber *URLPort;

		[_client close];

		if ([URL.scheme caseInsensitiveCompare: @"https"] ==
		    OF_ORDERED_SAME) {
		    OFOrderedSame) {
			if (of_tls_socket_class == Nil)
				@throw [OFUnsupportedProtocolException
				    exceptionWithURL: URL];

			sock = [[[of_tls_socket_class alloc] init] autorelease];
			port = 443;
		} else {
993
994
995
996
997
998
999
1000

1001
1002
1003
1004
1005
1006
1007
1008

1009
1010
1011
1012
1013
1014
1015
993
994
995
996
997
998
999

1000
1001
1002
1003
1004
1005
1006
1007

1008
1009
1010
1011
1012
1013
1014
1015







-
+







-
+







			@throw [OFInvalidServerReplyException exception];
		}

		if (line == nil)
			return 0;

		pos = [line rangeOfString: @";"].location;
		if (pos != OF_NOT_FOUND)
		if (pos != OFNotFound)
			line = [line substringToIndex: pos];

		if (line.length < 1) {
			/*
			 * We have read the empty string because the socket is
			 * at end of stream.
			 */
			if (_socket.atEndOfStream && pos == OF_NOT_FOUND)
			if (_socket.atEndOfStream && pos == OFNotFound)
				@throw [OFTruncatedDataException exception];
			else
				@throw [OFInvalidServerReplyException
				    exception];
		}

		@try {
1236
1237
1238
1239
1240
1241
1242
1243
1244


1245
1246
1247
1248
1249
1250
1251
1236
1237
1238
1239
1240
1241
1242


1243
1244
1245
1246
1247
1248
1249
1250
1251







-
-
+
+







- (void)asyncPerformRequest: (OFHTTPRequest *)request
		  redirects: (unsigned int)redirects
{
	void *pool = objc_autoreleasePoolPush();
	OFURL *URL = request.URL;
	OFString *scheme = URL.scheme;

	if ([scheme caseInsensitiveCompare: @"http"] != OF_ORDERED_SAME &&
	    [scheme caseInsensitiveCompare: @"https"] != OF_ORDERED_SAME)
	if ([scheme caseInsensitiveCompare: @"http"] != OFOrderedSame &&
	    [scheme caseInsensitiveCompare: @"https"] != OFOrderedSame)
		@throw [OFUnsupportedProtocolException exceptionWithURL: URL];

	if (_inProgress)
		/* TODO: Find a better exception */
		@throw [OFAlreadyConnectedException exception];

	_inProgress = true;

Modified src/OFHTTPCookie.m from [f788425642] to [c34a9bfc99].

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







-
+







    (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;
	const OFUnichar *characters = string.characters;
	size_t length = string.length, last = 0;
	enum {
		STATE_PRE_NAME,
		STATE_NAME,
		STATE_EXPECT_VALUE,
		STATE_VALUE,
		STATE_QUOTED_VALUE,
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
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







-
+

















-
+













-
+







				last = i;
				i--;
			}
			break;
		case STATE_NAME:
			if (characters[i] == '=') {
				name = [string substringWithRange:
				    of_range(last, i - last)];
				    OFMakeRange(last, i - last)];
				state = STATE_EXPECT_VALUE;
			}
			break;
		case STATE_EXPECT_VALUE:
			if (characters[i] == '"') {
				state = STATE_QUOTED_VALUE;
				last = i + 1;
			} else {
				state = STATE_VALUE;
				last = i;
			}

			i--;
			break;
		case STATE_VALUE:
			if (characters[i] == ';' || characters[i] == ',') {
				value = [string substringWithRange:
				    of_range(last, i - last)];
				    OFMakeRange(last, i - last)];

				[ret addObject:
				    [OFHTTPCookie cookieWithName: name
							   value: value
							  domain: domain]];

				state = (characters[i] == ';'
				    ? STATE_PRE_ATTR_NAME : STATE_PRE_NAME);
			}
			break;
		case STATE_QUOTED_VALUE:
			if (characters[i] == '"') {
				value = [string substringWithRange:
				    of_range(last, i - last)];
				    OFMakeRange(last, i - last)];
				[ret addObject:
				    [OFHTTPCookie cookieWithName: name
							   value: value
							  domain: domain]];

				state = STATE_POST_QUOTED_VALUE;
			}
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
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







-
+






-
+











-
+










-
+







				last = i;
				i--;
			}
			break;
		case STATE_ATTR_NAME:
			if (characters[i] == '=') {
				name = [string substringWithRange:
				    of_range(last, i - last)];
				    OFMakeRange(last, i - last)];

				state = STATE_ATTR_VALUE;
				last = i + 1;
			} else if (characters[i] == ';' ||
			    characters[i] == ',') {
				name = [string substringWithRange:
				    of_range(last, i - last)];
				    OFMakeRange(last, i - last)];

				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)];
				    OFMakeRange(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 &&
				    OFOrderedSame && value.length == 3 &&
				    ([value isEqual: @"Mon"] ||
				    [value isEqual: @"Tue"] ||
				    [value isEqual: @"Wed"] ||
				    [value isEqual: @"Thu"] ||
				    [value isEqual: @"Fri"] ||
				    [value isEqual: @"Sat"] ||
				    [value isEqual: @"Sun"]))
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
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







-
+













-
+






-
+







		break;
	case STATE_NAME:
	case STATE_QUOTED_VALUE:
		@throw [OFInvalidFormatException exception];
		break;
	case STATE_VALUE:
		value = [string substringWithRange:
		    of_range(last, length - last)];
		    OFMakeRange(last, length - last)];
		[ret addObject: [OFHTTPCookie cookieWithName: name
						       value: value
						      domain: domain]];
		break;
	/* We end up here if the cookie is just foo= */
	case STATE_EXPECT_VALUE:
		[ret addObject: [OFHTTPCookie cookieWithName: name
						       value: @""
						      domain: domain]];
		break;
	case STATE_ATTR_NAME:
		if (last != length) {
			name = [string substringWithRange:
			    of_range(last, length - last)];
			    OFMakeRange(last, length - last)];

			handleAttribute(ret.lastObject, name, nil);
		}
		break;
	case STATE_ATTR_VALUE:
		value = [string substringWithRange:
		    of_range(last, length - last)];
		    OFMakeRange(last, length - last)];

		handleAttribute(ret.lastObject, name, value);

		break;
	}

	objc_autoreleasePoolPop(pool);

Modified src/OFHTTPCookieManager.m from [a7b81a9286] to [5134a266a2].

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
73







-
+







	OFString *cookieDomain, *URLHost;
	size_t i;

	if (![cookie.path hasPrefix: @"/"])
		cookie.path = @"/";

	if (cookie.secure &&
	    [URL.scheme caseInsensitiveCompare: @"https"] != OF_ORDERED_SAME) {
	    [URL.scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) {
		objc_autoreleasePoolPop(pool);
		return;
	}

	cookieDomain = cookie.domain.lowercaseString;
	cookie.domain = cookieDomain;

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







-
+







		bool match;

		expires = cookie.expires;
		if (expires != nil && expires.timeIntervalSinceNow <= 0)
			continue;

		if (cookie.secure && [URL.scheme caseInsensitiveCompare:
		    @"https"] != OF_ORDERED_SAME)
		    @"https"] != OFOrderedSame)
			continue;

		pool = objc_autoreleasePoolPush();

		cookieDomain = cookie.domain.lowercaseString;
		URLHost = URL.host.lowercaseString;
		if ([cookieDomain hasPrefix: @"."]) {

Modified src/OFHTTPRequest.h from [3c89198066] to [9c2534e693].

71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85







-
+







 */
@interface OFHTTPRequest: OFObject <OFCopying>
{
	OFURL *_URL;
	of_http_request_method_t _method;
	of_http_request_protocol_version_t _protocolVersion;
	OFDictionary OF_GENERIC(OFString *, OFString *) *_Nullable _headers;
	of_socket_address_t _remoteAddress;
	OFSocketAddress _remoteAddress;
	bool _hasRemoteAddress;
	OF_RESERVE_IVARS(OFHTTPRequest, 4)
}

/**
 * @brief The URL of the HTTP request.
 */
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
107
108
109
110
111
112
113

114

115
116
117
118
119
120
121







-
+
-







    OFDictionary OF_GENERIC(OFString *, OFString *) *headers;

/**
 * @brief The remote address from which the request originates.
 *
 * @note The setter creates a copy of the remote address.
 */
@property OF_NULLABLE_PROPERTY (nonatomic)
@property OF_NULLABLE_PROPERTY (nonatomic) const OFSocketAddress *remoteAddress;
    const of_socket_address_t *remoteAddress;

/**
 * @brief Creates a new OFHTTPRequest.
 *
 * @return A new, autoreleased OFHTTPRequest
 */
+ (instancetype)request;

Modified src/OFHTTPRequest.m from [c73164e676] to [46acd12d86].

119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134

135
136
137
138
139
140
141
119
120
121
122
123
124
125

126
127
128
129
130
131
132
133

134
135
136
137
138
139
140
141







-
+







-
+







{
	[_URL release];
	[_headers release];

	[super dealloc];
}

- (void)setRemoteAddress: (const of_socket_address_t *)remoteAddress
- (void)setRemoteAddress: (const OFSocketAddress *)remoteAddress
{
	_hasRemoteAddress = (remoteAddress != NULL);

	if (_hasRemoteAddress)
		_remoteAddress = *remoteAddress;
}

- (const of_socket_address_t *)remoteAddress
- (const OFSocketAddress *)remoteAddress
{
	if (_hasRemoteAddress)
		return &_remoteAddress;

	return NULL;
}

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







-
+

















-
+







	    request->_protocolVersion.major != _protocolVersion.major ||
	    request->_protocolVersion.minor != _protocolVersion.minor ||
	    ![request->_URL isEqual: _URL] ||
	    ![request->_headers isEqual: _headers])
		return false;

	if (request.remoteAddress != self.remoteAddress &&
	    !of_socket_address_equal(request.remoteAddress, self.remoteAddress))
	    !OFSocketAddressEqual(request.remoteAddress, self.remoteAddress))
		return false;

	return true;
}

- (unsigned long)hash
{
	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);
	if (_hasRemoteAddress)
		OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_remoteAddress));
		OF_HASH_ADD_HASH(hash, OFSocketAddressHash(&_remoteAddress));

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (void)setProtocolVersion: (of_http_request_protocol_version_t)protocolVersion
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271
256
257
258
259
260
261
262

263

264
265
266
267
268
269
270







-
+
-







	OFString *indentedHeaders, *remoteAddress, *ret;

	indentedHeaders = [_headers.description
	    stringByReplacingOccurrencesOfString: @"\n"
				      withString: @"\n\t"];

	if (_hasRemoteAddress)
		remoteAddress =
		remoteAddress = OFSocketAddressString(&_remoteAddress);
		    of_socket_address_ip_string(&_remoteAddress, NULL);
	else
		remoteAddress = nil;

	ret = [[OFString alloc] initWithFormat:
	    @"<%@:\n\tURL = %@\n"
	    @"\tMethod = %s\n"
	    @"\tHeaders = %@\n"

Modified src/OFHTTPResponse.h from [4cf17ed197] to [ab5c38416c].

62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76







-
+








/**
 * @brief Returns the reply as a string, trying to detect the encoding and
 *	  falling back to the specified encoding if not detectable.
 *
 * @return The reply as a string
 */
- (OFString *)stringWithEncoding: (of_string_encoding_t)encoding;
- (OFString *)stringWithEncoding: (OFStringEncoding)encoding;
@end

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief Returns a description string for the specified HTTP status code.

Modified src/OFHTTPResponse.m from [e267b58d94] to [b9c77a409c].

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







-
+














-
+







	case 505:
		return @"HTTP Version Not Supported";
	default:
		return @"(unknown)";
	}
}

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

	last = 0;
	for (size_t i = 0; i < length; i++) {
		switch (state) {
		case STATE_TYPE:
			if (UTF8String[i] == ';') {
				state = STATE_BEFORE_PARAM_NAME;
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
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







-
+













-
+

-
+







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

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

	@try {
		ret = of_string_parse_encoding(charset);
		ret = OFParseStringEncodingName(charset);
	} @catch (OFInvalidArgumentException *e) {
		ret = OF_STRING_ENCODING_AUTODETECT;
		ret = OFStringEncodingAutodetect;
	}

	return ret;
}

@implementation OFHTTPResponse
@synthesize statusCode = _statusCode, headers = _headers;
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
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







-
+


-
+





-
+



-
-
+
+







	return [OFString stringWithFormat: @"%hhu.%hhu",
					   _protocolVersion.major,
					   _protocolVersion.minor];
}

- (OFString *)string
{
	return [self stringWithEncoding: OF_STRING_ENCODING_AUTODETECT];
	return [self stringWithEncoding: OFStringEncodingAutodetect];
}

- (OFString *)stringWithEncoding: (of_string_encoding_t)encoding
- (OFString *)stringWithEncoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFString *contentType, *contentLengthString, *ret;
	OFData *data;

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

	if (encoding == OF_STRING_ENCODING_AUTODETECT)
		encoding = OF_STRING_ENCODING_UTF_8;
	if (encoding == OFStringEncodingAutodetect)
		encoding = OFStringEncodingUTF8;

	data = [self readDataUntilEndOfStream];

	contentLengthString = [_headers objectForKey: @"Content-Length"];
	if (contentLengthString != nil) {
		unsigned long long contentLength =
		    contentLengthString.unsignedLongLongValue;

Modified src/OFHTTPServer.m from [bf72062f11] to [372c0e044a].

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







-
-
+
+














-
+










-
+







{
	OFString *method;
	OFMutableString *path;
	size_t pos;

	@try {
		OFString *version = [line
		    substringWithRange: of_range(line.length - 9, 9)];
		of_unichar_t tmp;
		    substringWithRange: OFMakeRange(line.length - 9, 9)];
		OFUnichar 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)
	if (pos == OFNotFound)
		return [self sendErrorAndClose: 400];

	method = [line substringToIndex: pos];
	@try {
		_method = of_http_request_method_from_string(method);
	} @catch (OFInvalidArgumentException *e) {
		return [self sendErrorAndClose: 405];
	}

	@try {
		of_range_t range = of_range(pos + 1, line.length - pos - 10);
		OFRange range = OFMakeRange(pos + 1, line.length - pos - 10);

		path = [[[line substringWithRange:
		    range] mutableCopy] autorelease];
	} @catch (OFOutOfRangeException *e) {
		return [self sendErrorAndClose: 400];
	}

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







-
+















-
+
-
-
+

-
+







		_state = SEND_RESPONSE;
		[self createResponse];

		return false;
	}

	pos = [line rangeOfString: @":"].location;
	if (pos == OF_NOT_FOUND)
	if (pos == OFNotFound)
		return [self sendErrorAndClose: 400];

	key = [line substringToIndex: pos];
	value = [line substringFromIndex: pos + 1];

	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
		pos = [value rangeOfString: @":"
		    rangeOfString: @":"
			  options: OF_STRING_SEARCH_BACKWARDS].location;
				   options: OFStringSearchBackwards].location;

		if (pos != OF_NOT_FOUND) {
		if (pos != OFNotFound) {
			[_host release];
			_host = [[value substringToIndex: pos] retain];

			@try {
				unsigned long long portTmp =
				    [value substringFromIndex: pos + 1]
				    .unsignedLongLongValue;
531
532
533
534
535
536
537
538

539
540
541
542
543
544
545
530
531
532
533
534
535
536

537
538
539
540
541
542
543
544







-
+








	URL = [OFMutableURL URL];
	URL.scheme = @"http";
	URL.host = _host;
	if (_port != 80)
		URL.port = [OFNumber numberWithUnsignedShort: _port];

	if ((pos = [_path rangeOfString: @"?"].location) != OF_NOT_FOUND) {
	if ((pos = [_path rangeOfString: @"?"].location) != OFNotFound) {
		OFString *path, *query;

		path = [_path substringToIndex: pos];
		query = [_path substringFromIndex: pos + 1];

		URL.URLEncodedPath = path;
		URL.URLEncodedQuery = query;
690
691
692
693
694
695
696
697

698
699
700
701
702
703
704
705

706
707
708
709
710
711
712
689
690
691
692
693
694
695

696
697
698
699
700
701
702
703

704
705
706
707
708
709
710
711







-
+







-
+







			@throw [OFInvalidFormatException exception];
		}

		if (line == nil)
			return 0;

		pos = [line rangeOfString: @";"].location;
		if (pos != OF_NOT_FOUND)
		if (pos != OFNotFound)
			line = [line substringToIndex: pos];

		if (line.length < 1) {
			/*
			 * We have read the empty string because the socket is
			 * at end of stream.
			 */
			if (_socket.atEndOfStream && pos == OF_NOT_FOUND)
			if (_socket.atEndOfStream && pos == OFNotFound)
				@throw [OFTruncatedDataException exception];
			else
				@throw [OFInvalidFormatException exception];
		}

		toRead = [line unsignedLongLongValueWithBase: 16];
		if (toRead > LLONG_MAX)

Modified src/OFHostAddressResolver.h from [6761889c77] to [5d4cf43da0].

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







-
+


-
+








-
+


-
+






@class OFMutableArray OF_GENERIC(ObjectType);
@class OFMutableData;
@class OFString;

@interface OFHostAddressResolver: OFObject <OFDNSResolverQueryDelegate>
{
	OFString *_host;
	of_socket_address_family_t _addressFamily;
	OFSocketAddressFamily _addressFamily;
	OFDNSResolver *_resolver;
	OFDNSResolverSettings *_settings;
	of_run_loop_mode_t _Nullable _runLoopMode;
	OFRunLoopMode _Nullable _runLoopMode;
	id <OFDNSResolverHostDelegate> _Nullable _delegate;
	bool _isFQDN;
	size_t _searchDomainIndex;
	unsigned int _numExpectedResponses;
	OFMutableData *_addresses;
}

- (instancetype)initWithHost: (OFString *)host
	       addressFamily: (of_socket_address_family_t)addressFamily
	       addressFamily: (OFSocketAddressFamily)addressFamily
		    resolver: (OFDNSResolver *)resolver
		    settings: (OFDNSResolverSettings *)settings
		 runLoopMode: (nullable of_run_loop_mode_t)runLoopMode
		 runLoopMode: (nullable OFRunLoopMode)runLoopMode
		    delegate: (nullable id <OFDNSResolverHostDelegate>)delegate;
- (void)asyncResolve;
- (OFData *)resolve;
@end

OF_ASSUME_NONNULL_END

Modified src/OFHostAddressResolver.m from [4a261c10a0] to [d50e89fde3].

36
37
38
39
40
41
42
43
44


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


43
44
45
46
47
48
49
50
51







-
-
+
+







@public
	bool _done;
	OFData *_addresses;
	id _exception;
}
@end

static const of_run_loop_mode_t resolveRunLoopMode =
    @"of_host_address_resolver_resolve_mode";
static const OFRunLoopMode resolveRunLoopMode =
    @"OFHostAddressResolverResolveRunLoopMode";

static bool
isFQDN(OFString *host, unsigned int minNumberOfDotsInAbsoluteName)
{
	const char *UTF8String;
	size_t length;
	unsigned int dots;
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
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







-
+
-




-
-
+
+




-
-
+
+











-
+







			dots++;

	return (dots >= minNumberOfDotsInAbsoluteName);
}

static bool
addressForRecord(OF_KINDOF(OFDNSResourceRecord *) record,
    const of_socket_address_t **address,
    const OFSocketAddress **address, OFSocketAddressFamily addressFamily)
    of_socket_address_family_t addressFamily)
{
	switch ([record recordType]) {
#ifdef OF_HAVE_IPV6
	case OF_DNS_RECORD_TYPE_AAAA:
		if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_IPV6 &&
		    addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY)
		if (addressFamily != OFSocketAddressFamilyIPv6 &&
		    addressFamily != OFSocketAddressFamilyAny)
			return false;
		break;
#endif
	case OF_DNS_RECORD_TYPE_A:
		if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_IPV4 &&
		    addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY)
		if (addressFamily != OFSocketAddressFamilyIPv4 &&
		    addressFamily != OFSocketAddressFamilyAny)
			return false;
		break;
	default:
		return false;
	}

	*address = [record address];
	return true;
}

static void
callDelegateInMode(of_run_loop_mode_t runLoopMode,
callDelegateInMode(OFRunLoopMode runLoopMode,
    id <OFDNSResolverHostDelegate> delegate, OFDNSResolver *resolver,
    OFString *host, OFData *addresses, id exception)
{
	SEL selector = @selector(resolver:didResolveHost:addresses:exception:);

	if ([delegate respondsToSelector: selector]) {
		OFTimer *timer = [OFTimer
110
111
112
113
114
115
116
117

118
119
120

121
122
123
124
125
126
127
109
110
111
112
113
114
115

116
117
118

119
120
121
122
123
124
125
126







-
+


-
+







		[[OFRunLoop currentRunLoop] addTimer: timer
					     forMode: runLoopMode];
	}
}

@implementation OFHostAddressResolver: OFObject
- (instancetype)initWithHost: (OFString *)host
	       addressFamily: (of_socket_address_family_t)addressFamily
	       addressFamily: (OFSocketAddressFamily)addressFamily
		    resolver: (OFDNSResolver *)resolver
		    settings: (OFDNSResolverSettings *)settings
		 runLoopMode: (of_run_loop_mode_t)runLoopMode
		 runLoopMode: (OFRunLoopMode)runLoopMode
		    delegate: (id <OFDNSResolverHostDelegate>)delegate
{
	self = [super init];

	@try {
		_host = [host copy];
		_addressFamily = addressFamily;
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
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







-
-
+
+











-
-
+
+








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

#ifdef OF_HAVE_IPV6
	if (_addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV6 ||
	    _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) {
	if (_addressFamily == OFSocketAddressFamilyIPv6 ||
	    _addressFamily == OFSocketAddressFamilyAny) {
		OFDNSQuery *query = [OFDNSQuery
		    queryWithDomainName: domainName
			       DNSClass: OF_DNS_CLASS_IN
			     recordType: OF_DNS_RECORD_TYPE_AAAA];
		_numExpectedResponses++;
		[_resolver asyncPerformQuery: query
				 runLoopMode: _runLoopMode
				    delegate: self];
	}
#endif

	if (_addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV4 ||
	    _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) {
	if (_addressFamily == OFSocketAddressFamilyIPv4 ||
	    _addressFamily == OFSocketAddressFamilyAny) {
		OFDNSQuery *query = [OFDNSQuery
		    queryWithDomainName: domainName
			       DNSClass: OF_DNS_CLASS_IN
			     recordType: OF_DNS_RECORD_TYPE_A];
		_numExpectedResponses++;
		[_resolver asyncPerformQuery: query
				 runLoopMode: _runLoopMode
203
204
205
206
207
208
209
210

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

209
210
211
212
213
214
215
216







-
+







		_searchDomainIndex++;
		[self sendQueries];
		return;
	}

	for (OF_KINDOF(OFDNSResourceRecord *) record in
	    [response.answerRecords objectForKey: query.domainName]) {
		const of_socket_address_t *address = NULL;
		const OFSocketAddress *address = NULL;
		OFDNSQuery *CNAMEQuery;

		if ([record DNSClass] != OF_DNS_CLASS_IN)
			continue;

		if (addressForRecord(record, &address, _addressFamily)) {
			[_addresses addItem: address];
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
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







-
+
-




-
+
















-
+



-
+


-
+





-
+








- (void)asyncResolve
{
	void *pool = objc_autoreleasePoolPush();
	OFArray OF_GENERIC(OFString *) *aliases;

	@try {
		of_socket_address_t address =
		OFSocketAddress address = OFSocketAddressParseIP(_host, 0);
		    of_socket_address_parse_ip(_host, 0);
		OFData *addresses = nil;
		id exception = nil;

		if (_addressFamily == address.family ||
		    _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY)
		    _addressFamily == OFSocketAddressFamilyAny)
			addresses = [OFData dataWithItems: &address
						    count: 1
						 itemSize: sizeof(address)];
		else
			exception = [OFInvalidArgumentException exception];

		callDelegateInMode(_runLoopMode, _delegate, _resolver, _host,
		    addresses, exception);

		objc_autoreleasePoolPop(pool);
		return;
	} @catch (OFInvalidFormatException *e) {
	}

	if ((aliases = [_settings->_staticHosts objectForKey: _host]) != nil) {
		OFMutableData *addresses = [OFMutableData
		    dataWithItemSize: sizeof(of_socket_address_t)];
		    dataWithItemSize: sizeof(OFSocketAddress)];
		id exception = nil;

		for (OFString *alias in aliases) {
			of_socket_address_t address;
			OFSocketAddress address;

			@try {
				address = of_socket_address_parse_ip(alias, 0);
				address = OFSocketAddressParseIP(alias, 0);
			} @catch (OFInvalidFormatException *e) {
				continue;
			}

			if (_addressFamily != address.family &&
			    _addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY)
			    _addressFamily != OFSocketAddressFamilyAny)
				continue;

			[addresses addItem: &address];
		}

		[addresses makeImmutable];

326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338







-
+








		objc_autoreleasePoolPop(pool);
		return;
	}

	_isFQDN = isFQDN(_host, _settings->_minNumberOfDotsInAbsoluteName);
	_addresses = [[OFMutableData alloc]
	    initWithItemSize: sizeof(of_socket_address_t)];
	    initWithItemSize: sizeof(OFSocketAddress)];

	[self sendQueries];

	objc_autoreleasePoolPop(pool);
}

- (OFData *)resolve

Modified src/OFINICategory+Private.h from [c5a381e443] to [6b052bbd06].

21
22
23
24
25
26
27
28

29
30
31
32
21
22
23
24
25
26
27

28
29
30
31
32







-
+




@class OFStream;

OF_DIRECT_MEMBERS
@interface OFINICategory ()
- (instancetype)of_initWithName: (OFString *)name OF_METHOD_FAMILY(init);
- (void)of_parseLine: (OFString *)line;
- (bool)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding
		encoding: (OFStringEncoding)encoding
		   first: (bool)first;
@end

OF_ASSUME_NONNULL_END

Modified src/OFINICategory.m from [3853ee5e40] to [d8e2a6f10b].

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







-
+







unescapeString(OFString *string)
{
	OFMutableString *mutableString;

	if (![string hasPrefix: @"\""] || ![string hasSuffix: @"\""])
		return string;

	string = [string substringWithRange: of_range(1, string.length - 2)];
	string = [string substringWithRange: OFMakeRange(1, string.length - 2)];
	mutableString = [[string mutableCopy] autorelease];

	[mutableString replaceOccurrencesOfString: @"\\f" withString: @"\f"];
	[mutableString replaceOccurrencesOfString: @"\\r" withString: @"\r"];
	[mutableString replaceOccurrencesOfString: @"\\n" withString: @"\n"];
	[mutableString replaceOccurrencesOfString: @"\\\"" withString: @"\""];
	[mutableString replaceOccurrencesOfString: @"\\\\" withString: @"\\"];
152
153
154
155
156
157
158
159

160
161
162
163
164
165
166
152
153
154
155
156
157
158

159
160
161
162
163
164
165
166







-
+







{
	if (![line hasPrefix: @";"]) {
		OFINICategoryPair *pair =
		    [[[OFINICategoryPair alloc] init] autorelease];
		OFString *key, *value;
		size_t pos;

		if ((pos = [line rangeOfString: @"="].location) == OF_NOT_FOUND)
		if ((pos = [line rangeOfString: @"="].location) == OFNotFound)
			@throw [OFInvalidFormatException exception];

		key = unescapeString([line substringToIndex: pos]
		    .stringByDeletingEnclosingWhitespaces);
		value = unescapeString([line substringFromIndex: pos + 1]
		    .stringByDeletingEnclosingWhitespaces);

464
465
466
467
468
469
470
471

472
473
474
475
476
477
478
464
465
466
467
468
469
470

471
472
473
474
475
476
477
478







-
+







		}
	}

	objc_autoreleasePoolPop(pool);
}

- (bool)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding
		encoding: (OFStringEncoding)encoding
		   first: (bool)first
{
	if (_lines.count == 0)
		return false;

	if (first)
		[stream writeFormat: @"[%@]\r\n", _name];

Modified src/OFINIFile.h from [bd06a8855c] to [8b191bee9f].

52
53
54
55
56
57
58
59

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

59
60
61
62
63
64
65
66







-
+







 *
 * @param path The path to the file whose contents the OFINIFile should contain
 * @param encoding The encoding of the specified file
 *
 * @return A new, autoreleased OFINIFile with the contents of the specified file
 */
+ (instancetype)fileWithPath: (OFString *)path
		    encoding: (of_string_encoding_t)encoding;
		    encoding: (OFStringEncoding)encoding;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated OFINIFile with the contents of the
 *	  specified file.
 *
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90







-
+







 *
 * @param path The path to the file whose contents the OFINIFile should contain
 * @param encoding The encoding of the specified file
 *
 * @return An initialized OFINIFile with the contents of the specified file
 */
- (instancetype)initWithPath: (OFString *)path
		    encoding: (of_string_encoding_t)encoding
		    encoding: (OFStringEncoding)encoding
    OF_DESIGNATED_INITIALIZER;

/**
 * @brief Returns an @ref OFINICategory for the category with the specified
 *	  name.
 *
 * @param name The name of the category for which an @ref OFINICategory should
104
105
106
107
108
109
110
111

112
113
114
104
105
106
107
108
109
110

111
112
113
114







-
+



/**
 * @brief Writes the contents of the OFINIFile to a file in the specified
 *	  encoding.
 *
 * @param path The path of the file to write to
 * @param encoding The encoding to use
 */
- (void)writeToFile: (OFString *)path encoding: (of_string_encoding_t)encoding;
- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding;
@end

OF_ASSUME_NONNULL_END

Modified src/OFINIFile.m from [2183d90e0a] to [0891d21917].

25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39







-
+







#import "OFINICategory+Private.h"

#import "OFInvalidFormatException.h"
#import "OFOpenItemFailedException.h"

OF_DIRECT_MEMBERS
@interface OFINIFile ()
- (void)of_parseFile: (OFString *)path encoding: (of_string_encoding_t)encoding;
- (void)of_parseFile: (OFString *)path encoding: (OFStringEncoding)encoding;
@end

static bool
isWhitespaceLine(OFString *line)
{
	const char *cString = line.UTF8String;
	size_t length = line.UTF8StringLength;
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
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







-
+












-
+



-
+








+ (instancetype)fileWithPath: (OFString *)path
{
	return [[[self alloc] initWithPath: path] autorelease];
}

+ (instancetype)fileWithPath: (OFString *)path
		    encoding: (of_string_encoding_t)encoding
		    encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithPath: path
				  encoding: encoding] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithPath: (OFString *)path
{
	return [self initWithPath: path encoding: OF_STRING_ENCODING_UTF_8];
	return [self initWithPath: path encoding: OFStringEncodingUTF8];
}

- (instancetype)initWithPath: (OFString *)path
		    encoding: (of_string_encoding_t)encoding
		    encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		_categories = [[OFMutableArray alloc] init];

		[self of_parseFile: path encoding: encoding];
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121







-
+







	[_categories addObject: category];

	objc_autoreleasePoolPop(pool);

	return category;
}

- (void)of_parseFile: (OFString *)path encoding: (of_string_encoding_t)encoding
- (void)of_parseFile: (OFString *)path encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFFile *file;
	OFINICategory *category = nil;
	OFString *line;

	@try {
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
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







-
+
















-
+


-
+







		if ([line hasPrefix: @"["]) {
			OFString *categoryName;

			if (![line hasSuffix: @"]"])
				@throw [OFInvalidFormatException exception];

			categoryName = [line substringWithRange:
			    of_range(1, line.length - 2)];
			    OFMakeRange(1, line.length - 2)];
			category = [[[OFINICategory alloc]
			    of_initWithName: categoryName] autorelease];
			[_categories addObject: category];
		} else {
			if (category == nil)
				@throw [OFInvalidFormatException exception];

			[category of_parseLine: line];
		}
	}

	objc_autoreleasePoolPop(pool);
}

- (void)writeToFile: (OFString *)path
{
	[self writeToFile: path encoding: OF_STRING_ENCODING_UTF_8];
	[self writeToFile: path encoding: OFStringEncodingUTF8];
}

- (void)writeToFile: (OFString *)path encoding: (of_string_encoding_t)encoding
- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFFile *file = [OFFile fileWithPath: path mode: @"w"];
	bool first = true;

	for (OFINICategory *category in _categories)
		if ([category of_writeToStream: file

Modified src/OFINIFileSettings.m from [a5f326cd7a] to [b35044d2f1].

53
54
55
56
57
58
59
60

61
62

63
64
65
66
67
68
69
53
54
55
56
57
58
59

60
61

62
63
64
65
66
67
68
69







-
+

-
+







}

- (void)of_getCategory: (OFString **)category
		andKey: (OFString **)key
	       forPath: (OFString *)path OF_DIRECT
{
	size_t pos = [path rangeOfString: @"."
				 options: OF_STRING_SEARCH_BACKWARDS].location;
				 options: OFStringSearchBackwards].location;

	if (pos == OF_NOT_FOUND) {
	if (pos == OFNotFound) {
		*category = @"";
		*key = path;
		return;
	}

	*category = [path substringToIndex: pos];
	*key = [path substringFromIndex: pos + 1];

Modified src/OFIPSocketAsyncConnector.h from [a61a99efb6] to [185e130707].

16
17
18
19
20
21
22
23

24
25

26
27
28
29
30
31
32
16
17
18
19
20
21
22

23
24

25
26
27
28
29
30
31
32







-
+

-
+







#import "OFDNSResolver.h"
#import "OFRunLoop.h"
#import "OFRunLoop+Private.h"

OF_ASSUME_NONNULL_BEGIN

@protocol OFIPSocketAsyncConnecting
- (bool)of_createSocketForAddress: (const of_socket_address_t *)address
- (bool)of_createSocketForAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo;
- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address
- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo;
- (void)of_closeSocket;
@end

@interface OFIPSocketAsyncConnector: OFObject <OFRunLoopConnectDelegate,
    OFDNSResolverHostDelegate>
{
42
43
44
45
46
47
48
49
50


51
52
53
42
43
44
45
46
47
48


49
50
51
52
53







-
-
+
+




- (instancetype)initWithSocket: (id)sock
			  host: (OFString *)host
			  port: (uint16_t)port
		      delegate: (nullable id)delegate
			 block: (nullable id)block;
- (void)didConnect;
- (void)tryNextAddressWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode;
- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode;
@end

OF_ASSUME_NONNULL_END

Modified src/OFIPSocketAsyncConnector.m from [09c7bbbcdf] to [853854160a].

65
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
65
66
67
68
69
70
71


72
73
74
75
76
77
78
79







-
-
+







{
	if (_exception == nil)
		[_socket setCanBlock: true];

#ifdef OF_HAVE_BLOCKS
	if (_block != NULL) {
		if ([_socket isKindOfClass: [OFTCPSocket class]])
			((of_tcp_socket_async_connect_block_t)_block)(
			    _exception);
			((OFTCPSocketAsyncConnectBlock)_block)(_exception);
		else
			OF_ENSURE(0);
	} else {
#endif
		if ([_delegate respondsToSelector:
		    @selector(socket:didConnectToHost:port:exception:)])
			[_delegate socket: _socket
129
130
131
132
133
134
135
136

137
138

139
140
141
142

143
144
145
146
147
148
149
128
129
130
131
132
133
134

135
136

137
138
139
140

141
142
143
144
145
146
147
148







-
+

-
+



-
+







{
	return [OFConnectionFailedException exceptionWithHost: _host
							 port: _port
						       socket: _socket
							errNo: errNo];
}

- (void)tryNextAddressWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode
{
	of_socket_address_t address = *(const of_socket_address_t *)
	OFSocketAddress address = *(const OFSocketAddress *)
	    [_socketAddresses itemAtIndex: _socketAddressesIndex++];
	int errNo;

	of_socket_address_set_port(&address, _port);
	OFSocketAddressSetPort(&address, _port);

	if (![_socket of_createSocketForAddress: &address errNo: &errNo]) {
		if (_socketAddressesIndex >= _socketAddresses.count) {
			_exception = [[OFConnectionFailedException alloc]
			    initWithHost: _host
				    port: _port
				  socket: _socket
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
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







-
+


-
-
+













-
+





	_socketAddresses = [addresses copy];

	[self tryNextAddressWithRunLoopMode:
	    [OFRunLoop currentRunLoop].currentMode];
}

- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode
{
	@try {
		of_socket_address_t address =
		    of_socket_address_parse_ip(_host, _port);
		OFSocketAddress address = OFSocketAddressParseIP(_host, _port);

		_socketAddresses = [[OFData alloc]
		    initWithItems: &address
			    count: 1
			 itemSize: sizeof(address)];

		[self tryNextAddressWithRunLoopMode: runLoopMode];
		return;
	} @catch (OFInvalidFormatException *e) {
	}

	[[OFThread DNSResolver]
	    asyncResolveAddressesForHost: _host
			   addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY
			   addressFamily: OFSocketAddressFamilyAny
			     runLoopMode: runLoopMode
				delegate: self];
}
@end

Modified src/OFIPXSocket.h from [3a07b6e6f2] to [716204a756].

28
29
30
31
32
33
34
35
36
37
38
39





40
41
42
43
44
45
46
28
29
30
31
32
33
34





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







-
-
-
-
-
+
+
+
+
+







@end

/**
 * @class OFIPXSocket OFIPXSocket.h ObjFW/OFIPXSocket.h
 *
 * @brief A class which provides methods to create and use IPX sockets.
 *
 * Addresses are of type @ref of_socket_address_t. You can use
 * @ref of_socket_address_ipx to create an address or
 * @ref of_socket_address_get_ipx_network to get the IPX network,
 * @ref of_socket_address_get_ipx_node to get the IPX node and
 * @ref of_socket_address_get_port to get the port (sometimes also called
 * Addresses are of type @ref OFSocketAddress. You can use
 * @ref OFSocketAddressMakeIPX to create an address or
 * @ref OFSocketAddressIPXNetwork to get the IPX network,
 * @ref OFSocketAddressIpxNode to get the IPX node and
 * @ref OFSocketAddressPort to get the port (sometimes also called
 * socket number).
 *
 * @warning Even though the OFCopying protocol is implemented, it does *not*
 *	    return an independent copy of the socket, but instead retains it.
 *	    This is so that the socket can be used as a key for a dictionary,
 *	    so context can be associated with a socket. Using a socket in more
 *	    than one thread at the same time is not thread-safe, even if copy
68
69
70
71
72
73
74
75
76

77
78
79
68
69
70
71
72
73
74


75
76
77
78







-
-
+



 *	  specified packet type.
 *
 * @param port The port (sometimes called socket number) to bind to. 0 means to
 *	       pick one and return it.
 * @param packetType The packet type to use on the socket
 * @return The address on which this socket can be reached
 */
- (of_socket_address_t)bindToPort: (uint16_t)port
		       packetType: (uint8_t)packetType;
- (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType;
@end

OF_ASSUME_NONNULL_END

Modified src/OFIPXSocket.m from [8d511b567a] to [0cad159968].

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







-
-
+


-
+








-
+








#import "socket.h"
#import "socket_helpers.h"

@implementation OFIPXSocket
@dynamic delegate;

- (of_socket_address_t)bindToPort: (uint16_t)port
		       packetType: (uint8_t)packetType
- (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };
	of_socket_address_t address;
	OFSocketAddress address;
	int protocol = 0;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	address = of_socket_address_ipx(zeroNode, 0, port);
	address = OFSocketAddressMakeIPX(zeroNode, 0, port);

#ifdef OF_WINDOWS
	protocol = NSPROTO_IPX + packetType;
#else
	_packetType = address.sockaddr.ipx.sipx_type = packetType;
#endif

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







-
+







		@throw [OFBindFailedException exceptionWithPort: port
						     packetType: packetType
							 socket: self
							  errNo: errNo];
	}

	memset(&address, 0, sizeof(address));
	address.family = OF_SOCKET_ADDRESS_FAMILY_IPX;
	address.family = OFSocketAddressFamilyIPX;
	address.length = (socklen_t)sizeof(address.sockaddr);

	if (of_getsockname(_socket, &address.sockaddr.sockaddr,
	    &address.length) != 0) {
		int errNo = of_socket_errno();

		closesocket(_socket);
109
110
111
112
113
114
115
116

117
118

119
120
121
122
123

124
125
126
127
128
129
108
109
110
111
112
113
114

115
116

117
118
119
120
121

122
123
124
125
126
127
128







-
+

-
+




-
+







	return address;
}

#ifndef OF_WINDOWS
- (void)sendBuffer: (const void *)buffer
	    length: (size_t)length
	  receiver: (const of_socket_address_t *)receiver
	  receiver: (const OFSocketAddress *)receiver
{
	of_socket_address_t fixedReceiver;
	OFSocketAddress fixedReceiver;

	memcpy(&fixedReceiver, receiver, sizeof(fixedReceiver));

	/* If it's not IPX, no fix-up needed - it will fail anyway. */
	if (fixedReceiver.family == OF_SOCKET_ADDRESS_FAMILY_IPX)
	if (fixedReceiver.family == OFSocketAddressFamilyIPX)
		fixedReceiver.sockaddr.ipx.sipx_type = _packetType;

	[super sendBuffer: buffer length: length receiver: &fixedReceiver];
}
#endif
@end

Modified src/OFInvertedCharacterSet.h from [6a080d4b74] to [c74c805b51].

16
17
18
19
20
21
22
23

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

23
24
25
26
27
28
29







-
+






#import "OFCharacterSet.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFInvertedCharacterSet: OFCharacterSet
{
	OFCharacterSet *_characterSet;
	bool (*_characterIsMember)(id, SEL, of_unichar_t);
	bool (*_characterIsMember)(id, SEL, OFUnichar);
}

- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet;
@end

OF_ASSUME_NONNULL_END

Modified src/OFInvertedCharacterSet.m from [ea0333ca6e] to [e08da05e4c].

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







-
+

















-
+











- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet
{
	self = [super init];

	@try {
		_characterSet = [characterSet retain];
		_characterIsMember = (bool (*)(id, SEL, of_unichar_t))
		_characterIsMember = (bool (*)(id, SEL, OFUnichar))
		    [_characterSet methodForSelector:
		    @selector(characterIsMember:)];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_characterSet release];

	[super dealloc];
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	return !_characterIsMember(_characterSet, @selector(characterIsMember:),
	    character);
}

- (OFCharacterSet *)invertedSet
{
	return [[_characterSet retain] autorelease];
}
@end

Modified src/OFKernelEventObserver.h from [9a570d3d9f] to [96edbc82e4].

124
125
126
127
128
129
130
131

132
133
134
135
136
137
138
124
125
126
127
128
129
130

131
132
133
134
135
136
137
138







-
+







	id <OFKernelEventObserverDelegate> _Nullable _delegate;
#if defined(OF_AMIGAOS)
	struct Task *_waitingTask;
	ULONG _cancelSignal;
#elif defined(OF_HAVE_PIPE)
	int _cancelFD[2];
#else
	of_socket_t _cancelFD[2];
	OFSocketHandle _cancelFD[2];
	struct sockaddr_in _cancelAddr;
#endif
#ifdef OF_AMIGAOS
	ULONG _execSignalMask;
#endif
	OF_RESERVE_IVARS(OFKernelEventObserver, 4)
}
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
209
210
211
212
213
214
215

216
217
218
219
220
221
222
223







-
+








/**
 * @brief Observes all objects until an event happens on an object or the
 *	  timeout is reached.
 *
 * @param timeInterval The time to wait for an event, in seconds
 */
- (void)observeForTimeInterval: (of_time_interval_t)timeInterval;
- (void)observeForTimeInterval: (OFTimeInterval)timeInterval;

/**
 * @brief Observes all objects until an event happens on an object or the
 *	  specified date is reached.
 *
 * @param date The until which to observe
 */

Modified src/OFKernelEventObserver.m from [9d77b8881b] to [4e64aadcfc].

241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255







-
+







}

- (void)observe
{
	[self observeForTimeInterval: -1];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
- (void)observeForTimeInterval: (OFTimeInterval)timeInterval
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)observeUntilDate: (OFDate *)date
{
	[self observeForTimeInterval: date.timeIntervalSinceNow];

Modified src/OFKqueueKernelEventObserver.m from [8d97fca7a9] to [a1444efdc0].

149
150
151
152
153
154
155
156

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

156
157
158
159
160
161
162
163







-
+







	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: errno];

	[super removeObjectForWriting: object];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
- (void)observeForTimeInterval: (OFTimeInterval)timeInterval
{
	struct timespec timeout;
	struct kevent eventList[EVENTLIST_SIZE];
	int events;

	if ([self of_processReadBuffers])
		return;

Modified src/OFLHAArchive.h from [89478b5360] to [8b3e09cc61].

32
33
34
35
36
37
38
39

40
41
42
43
44
45
46

47
48
49
50
51
52
53
32
33
34
35
36
37
38

39
40
41
42
43
44
45

46
47
48
49
50
51
52
53







-
+






-
+







{
	OFStream *_stream;
	enum {
		OF_LHA_ARCHIVE_MODE_READ,
		OF_LHA_ARCHIVE_MODE_WRITE,
		OF_LHA_ARCHIVE_MODE_APPEND
	} _mode;
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
	OFStream *_Nullable _lastReturnedStream;
}

/**
 * @brief The encoding to use for the archive. Defaults to ISO 8859-1.
 */
@property (nonatomic) of_string_encoding_t encoding;
@property (nonatomic) OFStringEncoding encoding;

/**
 * @brief A stream for reading the current entry.
 *
 * @note This is only available in read mode.
 *
 * @note The returned stream conforms to @ref OFReadyForReadingObserving if the

Modified src/OFLHAArchive.m from [7c9dae9bb4] to [0005d98cda].

51
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
51
52
53
54
55
56
57

58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74







-
+








-
+







- (void)of_skip;
@end

OF_DIRECT_MEMBERS
@interface OFLHAArchiveFileWriteStream: OFStream <OFReadyForWritingObserving>
{
	OFMutableLHAArchiveEntry *_entry;
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
	OFSeekableStream *_stream;
	of_offset_t _headerOffset;
	uint32_t _bytesWritten;
	uint16_t _CRC16;
}

- (instancetype)of_initWithStream: (OFSeekableStream *)stream
			    entry: (OFLHAArchiveEntry *)entry
			 encoding: (of_string_encoding_t)encoding;
			 encoding: (OFStringEncoding)encoding;
@end

@implementation OFLHAArchive
@synthesize encoding = _encoding;

+ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode
{
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122







-
+







		    ![_stream isKindOfClass: [OFSeekableStream class]])
			@throw [OFInvalidArgumentException exception];

		if (_mode == OF_LHA_ARCHIVE_MODE_APPEND)
			[(OFSeekableStream *)_stream seekToOffset: 0
							   whence: SEEK_END];

		_encoding = OF_STRING_ENCODING_ISO_8859_1;
		_encoding = OFStringEncodingISO8859_1;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
430
431
432
433
434
435
436

437
438
439
440
441
442
443
444







-
+







	[super close];
}
@end

@implementation OFLHAArchiveFileWriteStream
- (instancetype)of_initWithStream: (OFSeekableStream *)stream
			    entry: (OFLHAArchiveEntry *)entry
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		_entry = [entry mutableCopy];
		_encoding = encoding;

Modified src/OFLHAArchiveEntry+Private.h from [7ab4266d19] to [1e5b6ab947].

17
18
19
20
21
22
23
24

25
26
27

28
29
30
17
18
19
20
21
22
23

24
25
26

27
28
29
30







-
+


-
+




OF_ASSUME_NONNULL_BEGIN

OF_DIRECT_MEMBERS
@interface OFLHAArchiveEntry ()
- (instancetype)of_initWithHeader: (char [_Nonnull 21])header
			   stream: (OFStream *)stream
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
    OF_METHOD_FAMILY(init);
- (void)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding;
		encoding: (OFStringEncoding)encoding;
@end

OF_ASSUME_NONNULL_END

Modified src/OFLHAArchiveEntry.m from [d68323165e] to [35e510f89b].

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







-
+












-
+








	return [OFDate dateWithLocalDateString: dateString
					format: @"%Y-%m-%d %H:%M:%S"];
}

static void
parseFileNameExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	[entry->_fileName release];
	entry->_fileName = nil;

	entry->_fileName = [[OFString alloc]
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: [extension count] - 1];
}

static void
parseDirectoryNameExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableData *data = [[extension mutableCopy] autorelease];
	char *items = data.mutableItems;
	size_t count = data.count;
	OFMutableString *directoryName;

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







-
+












-
+

















-
+







	entry->_directoryName = [directoryName copy];

	objc_autoreleasePoolPop(pool);
}

static void
parseCommentExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	[entry->_fileComment release];
	entry->_fileComment = nil;

	entry->_fileComment = [[OFString alloc]
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: extension.count - 1];
}

static void
parsePermissionsExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	uint16_t mode;

	if (extension.count != 3)
		@throw [OFInvalidFormatException exception];

	memcpy(&mode, (char *)extension.items + 1, 2);
	mode = OF_BSWAP16_IF_BE(mode);

	[entry->_mode release];
	entry->_mode = nil;

	entry->_mode = [[OFNumber alloc] initWithUnsignedShort: mode];
}

static void
parseGIDUIDExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	uint16_t UID, GID;

	if (extension.count != 5)
		@throw [OFInvalidFormatException exception];

	memcpy(&GID, (char *)extension.items + 1, 2);
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
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







-
+












-
+












-
+


















-
+

-
+








	entry->_GID = [[OFNumber alloc] initWithUnsignedShort: GID];
	entry->_UID = [[OFNumber alloc] initWithUnsignedShort: UID];
}

static void
parseGroupExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	[entry->_group release];
	entry->_group = nil;

	entry->_group = [[OFString alloc]
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: extension.count - 1];
}

static void
parseOwnerExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	[entry->_owner release];
	entry->_owner = nil;

	entry->_owner = [[OFString alloc]
	    initWithCString: (char *)extension.items + 1
		   encoding: encoding
		     length: extension.count - 1];
}

static void
parseModificationDateExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	uint32_t modificationDate;

	if (extension.count != 5)
		@throw [OFInvalidFormatException exception];

	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];
}

static bool
parseExtension(OFLHAArchiveEntry *entry, OFData *extension,
    of_string_encoding_t encoding, bool allowFileName)
    OFStringEncoding encoding, bool allowFileName)
{
	void (*function)(OFLHAArchiveEntry *, OFData *, of_string_encoding_t) =
	void (*function)(OFLHAArchiveEntry *, OFData *, OFStringEncoding) =
	    NULL;

	switch (*(char *)[extension itemAtIndex: 0]) {
	case 0x01:
		if (allowFileName)
			function = parseFileNameExtension;
		break;
238
239
240
241
242
243
244
245

246
247
248
249
250
251
252
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252







-
+








	function(entry, extension, encoding);
	return true;
}

static void
readExtensions(OFLHAArchiveEntry *entry, OFStream *stream,
    of_string_encoding_t encoding, bool allowFileName)
    OFStringEncoding encoding, bool allowFileName)
{
	uint16_t size;

	while ((size = [stream readLittleEndianInt16]) > 0) {
		OFData *extension;

		if (size < 2)
263
264
265
266
267
268
269
270

271
272
273
274
275
276
277
278
263
264
265
266
267
268
269

270

271
272
273
274
275
276
277







-
+
-








			entry->_compressedSize -= size;
		}
	}
}

static void
getFileNameAndDirectoryName(OFLHAArchiveEntry *entry,
getFileNameAndDirectoryName(OFLHAArchiveEntry *entry, OFStringEncoding encoding,
    of_string_encoding_t encoding,
    const char **fileName, size_t *fileNameLength,
    const char **directoryName, size_t *directoryNameLength)
{
	OFMutableData *data;
	char *cString;
	size_t length;
	size_t pos;
329
330
331
332
333
334
335
336

337
338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
328
329
330
331
332
333
334

335
336
337
338
339
340
341
342
343

344
345
346
347
348
349
350
351







-
+








-
+







	}

	return self;
}

- (instancetype)of_initWithHeader: (char [21])header
			   stream: (OFStream *)stream
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		uint32_t date;

		_compressionMethod = [[OFString alloc]
		    initWithCString: header + 2
			   encoding: OF_STRING_ENCODING_ASCII
			   encoding: OFStringEncodingASCII
			     length: 5];

		memcpy(&_compressedSize, header + 7, 4);
		_compressedSize = OF_BSWAP32_IF_BE(_compressedSize);

		memcpy(&_uncompressedSize, header + 11, 4);
		_uncompressedSize = OF_BSWAP32_IF_BE(_uncompressedSize);
551
552
553
554
555
556
557
558

559
560
561
562
563
564
565
566
567
568
569

570
571
572
573
574
575
576
577
578
579
580
581
582
583

584
585
586
587
588
589
590
550
551
552
553
554
555
556

557
558
559
560
561
562
563
564
565
566
567

568
569
570
571
572
573
574
575
576
577
578
579
580
581

582
583
584
585
586
587
588
589







-
+










-
+













-
+








- (OFArray OF_GENERIC(OFData *) *)extensions
{
	return _extensions;
}

- (void)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding
		encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableData *data = [OFMutableData dataWithCapacity: 24];
	const char *fileName, *directoryName;
	size_t fileNameLength, directoryNameLength;
	uint16_t tmp16;
	uint32_t tmp32;
	size_t headerSize;

	if ([_compressionMethod cStringLengthWithEncoding:
	    OF_STRING_ENCODING_ASCII] != 5)
	    OFStringEncodingASCII] != 5)
		@throw [OFInvalidArgumentException exception];

	getFileNameAndDirectoryName(self, encoding, &fileName, &fileNameLength,
	    &directoryName, &directoryNameLength);

	if (fileNameLength > UINT16_MAX - 3 ||
	    directoryNameLength > UINT16_MAX - 3)
		@throw [OFOutOfRangeException exception];

	/* Length. Filled in after we're done. */
	[data increaseCountBy: 2];

	[data addItems: [_compressionMethod
			    cStringWithEncoding: OF_STRING_ENCODING_ASCII]
			    cStringWithEncoding: OFStringEncodingASCII]
		 count: 5];

	tmp32 = OF_BSWAP32_IF_BE(_compressedSize);
	[data addItems: &tmp32 count: sizeof(tmp32)];

	tmp32 = OF_BSWAP32_IF_BE(_uncompressedSize);
	[data addItems: &tmp32 count: sizeof(tmp32)];

Modified src/OFList.h from [36d06c646e] to [0c075514d1].

16
17
18
19
20
21
22
23

24
25

26
27

28
29
30


31
32

33
34

35
36

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


54
55

56
57
58
59
60
61
62

63
64
65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99
100

101
102

103
104
105
106
107
108

109
110

111
112

113
114
115
116
117
118
119
120



121
122

123
124
125


126
127
128
129
130
131

132
133

134
135

136
137
138


139
140
141
142
143

144
145

146
147
148
149
150
151
152
16
17
18
19
20
21
22

23
24

25
26

27
28


29
30
31

32
33

34
35

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


52
53
54

55
56
57
58
59
60
61

62

63
64
65
66
67
68
69
70
71
72
73
74

75

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

96
97

98
99

100
101
102
103
104
105

106
107

108
109

110
111
112
113
114
115



116
117
118
119

120
121


122
123
124
125
126
127
128

129
130

131
132

133
134


135
136
137
138
139
140

141
142

143
144
145
146
147
148
149
150







-
+

-
+

-
+

-
-
+
+

-
+

-
+

-
+















-
-
+
+

-
+






-
+
-












-
+
-




















-
+

-
+

-
+





-
+

-
+

-
+





-
-
-
+
+
+

-
+

-
-
+
+





-
+

-
+

-
+

-
-
+
+




-
+

-
+







#import "OFObject.h"
#import "OFCollection.h"
#import "OFEnumerator.h"
#import "OFSerialization.h"

OF_ASSUME_NONNULL_BEGIN

typedef struct of_list_object_t of_list_object_t;
typedef struct OFListItem OFListItem;
/**
 * @struct of_list_object_t OFList.h ObjFW/OFList.h
 * @struct OFListItem OFList.h ObjFW/OFList.h
 *
 * @brief A list object.
 * @brief A list item.
 *
 * A struct that contains a pointer to the next list object, the previous list
 * object and the object.
 * A struct that contains a pointer to the next list item, the previous list
 * item and the object.
 */
struct of_list_object_t {
struct OFListItem {
	/** A pointer to the next list object in the list */
	of_list_object_t *_Nullable next;
	OFListItem *_Nullable next;
	/** A pointer to the previous list object in the list */
	of_list_object_t *_Nullable previous;
	OFListItem *_Nullable previous;
	/** The object for the list object */
	id __unsafe_unretained object;
};

/**
 * @class OFList OFList.h ObjFW/OFList.h
 *
 * @brief A class which provides easy to use double-linked lists.
 */
@interface OFList OF_GENERIC(ObjectType): OFObject <OFCopying, OFCollection,
    OFSerialization>
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# define ObjectType id
#endif
{
	of_list_object_t *_Nullable _firstListObject;
	of_list_object_t *_Nullable _lastListObject;
	OFListItem *_Nullable _firstListItem;
	OFListItem *_Nullable _lastListItem;
	size_t _count;
	unsigned long  _mutations;
	unsigned long _mutations;
	OF_RESERVE_IVARS(OFList, 4)
}

/**
 * @brief The first list object of the list.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem *firstListItem;
    of_list_object_t *firstListObject;

/**
 * @brief The first object of the list or `nil`.
 *
 * @warning The returned object is *not* retained and autoreleased for
 *	    performance reasons!
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) ObjectType firstObject;

/**
 * @brief The last list object of the list.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem *lastListItem;
    of_list_object_t *lastListObject;

/**
 * @brief The last object of the list or `nil`.
 *
 * @warning The returned object is *not* retained and autoreleased for
 *	    performance reasons!
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) ObjectType lastObject;

/**
 * @brief Creates a new OFList.
 *
 * @return A new autoreleased OFList
 */
+ (instancetype)list;

/**
 * @brief Appends an object to the list.
 *
 * @param object The object to append
 * @return An of_list_object_t, needed to identify the object inside the list.
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its of_list_object_t.
 *	   its OFListItem.
 */
- (of_list_object_t *)appendObject: (ObjectType)object;
- (OFListItem *)appendObject: (ObjectType)object;

/**
 * @brief Prepends an object to the list.
 *
 * @param object The object to prepend
 * @return An of_list_object_t, needed to identify the object inside the list.
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its of_list_object_t.
 *	   its OFListItem.
 */
- (of_list_object_t *)prependObject: (ObjectType)object;
- (OFListItem *)prependObject: (ObjectType)object;

/**
 * @brief Inserts an object before another list object.
 *
 * @param object The object to insert
 * @param listObject The of_list_object_t of the object before which it should
 *	  be inserted
 * @return An of_list_object_t, needed to identify the object inside the list.
 * @param listItem The OFListItem of the object before which it should be
 *		   inserted
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its of_list_object_t.
 *	   its OFListItem.
 */
- (of_list_object_t *)insertObject: (ObjectType)object
		  beforeListObject: (of_list_object_t *)listObject;
- (OFListItem *)insertObject: (ObjectType)object
	      beforeListItem: (OFListItem *)listItem;

/**
 * @brief Inserts an object after another list object.
 *
 * @param object The object to insert
 * @param listObject The of_list_object_t of the object after which it should be
 * @param listItem The OFListItem of the object after which it should be
 *	  inserted
 * @return An of_list_object_t, needed to identify the object inside the list.
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its of_list_object_t.
 *	   its OFListItem.
 */
- (of_list_object_t *)insertObject: (ObjectType)object
		   afterListObject: (of_list_object_t *)listObject;
- (OFListItem *)insertObject: (ObjectType)object
	       afterListItem: (OFListItem *)listItem;

/**
 * @brief Removes the object with the specified list object from the list.
 *
 * @param listObject The list object returned by append / prepend
 * @param listItem The list object returned by append / prepend
 */
- (void)removeListObject: (of_list_object_t *)listObject;
- (void)removeListItem: (OFListItem *)listItem;

/**
 * @brief Checks whether the list contains an object equal to the specified
 *	  object.
 *
 * @param object The object which is checked for being in the list
 * @return A boolean whether the list contains the specified object

Modified src/OFList.m from [734046ca66] to [ce0d3e5241].

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







-
+









-
+
-







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

OF_DIRECT_MEMBERS
@interface OFListEnumerator: OFEnumerator
{
	OFList *_list;
	of_list_object_t *_Nullable _current;
	OFListItem *_Nullable _current;
	unsigned long _mutations;
	unsigned long *_Nullable _mutationsPtr;
}

- (instancetype)initWithList: (OFList *)list
	    mutationsPointer: (unsigned long *)mutationsPtr;
@end

@implementation OFList
@synthesize firstListObject = _firstListObject;
@synthesize firstListItem = _firstListItem, lastListItem = _lastListItem;
@synthesize lastListObject = _lastListObject;

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

- (instancetype)initWithSerialization: (OFXMLElement *)element
75
76
77
78
79
80
81
82

83
84
85

86
87
88
89
90
91
92
93
94

95
96

97
98
99
100
101




102
103
104


105
106

107
108
109


110
111
112
113
114

115
116
117

118
119

120
121
122
123
124



125
126
127


128
129
130
131



132
133
134
135
136

137
138
139
140


141
142

143
144
145
146
147



148
149
150


151
152

153
154
155


156
157
158
159
160

161
162
163
164


165
166

167
168
169
170
171



172
173
174


175
176

177
178
179


180
181
182
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
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
74
75
76
77
78
79
80

81
82


83
84
85
86
87
88
89
90
91

92
93

94
95




96
97
98
99
100


101
102
103

104
105


106
107
108
109
110
111

112
113
114

115
116

117
118




119
120
121
122


123
124
125



126
127
128
129
130
131
132

133
134
135


136
137
138

139
140




141
142
143
144


145
146
147

148
149


150
151
152
153
154
155

156
157
158


159
160
161

162
163




164
165
166
167


168
169
170

171
172


173
174
175
176
177
178

179
180
181

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







-
+

-
-
+








-
+

-
+

-
-
-
-
+
+
+
+

-
-
+
+

-
+

-
-
+
+




-
+


-
+

-
+

-
-
-
-
+
+
+

-
-
+
+

-
-
-
+
+
+




-
+


-
-
+
+

-
+

-
-
-
-
+
+
+

-
-
+
+

-
+

-
-
+
+




-
+


-
-
+
+

-
+

-
-
-
-
+
+
+

-
-
+
+

-
+

-
-
+
+




-
+


-
+

-
-
-
-
+
+
+
+

-
-
-
-
+
+
+
+




-
-
+
+




-
+




-
+










-
+












-
+
















-
-
+











-
-
+








-
+



-
-
+





-
+





-
+

-
+



-
+

-
-
-
-
+
+
+
+

-
-
+
+

-
+



-
+






-
+










-
+

















-
+







	}

	return self;
}

- (void)dealloc
{
	of_list_object_t *next;
	OFListItem *next;

	for (of_list_object_t *iter = _firstListObject;
	    iter != NULL; iter = next) {
	for (OFListItem *iter = _firstListItem; iter != NULL; iter = next) {
		[iter->object release];
		next = iter->next;
		free(iter);
	}

	[super dealloc];
}

- (of_list_object_t *)appendObject: (id)object
- (OFListItem *)appendObject: (id)object
{
	of_list_object_t *listObject;
	OFListItem *listItem;

	listObject = of_alloc(1, sizeof(of_list_object_t));
	listObject->object = [object retain];
	listObject->next = NULL;
	listObject->previous = _lastListObject;
	listItem = of_alloc(1, sizeof(OFListItem));
	listItem->object = [object retain];
	listItem->next = NULL;
	listItem->previous = _lastListItem;

	if (_lastListObject != NULL)
		_lastListObject->next = listObject;
	if (_lastListItem != NULL)
		_lastListItem->next = listItem;

	_lastListObject = listObject;
	_lastListItem = listItem;

	if (_firstListObject == NULL)
		_firstListObject = listObject;
	if (_firstListItem == NULL)
		_firstListItem = listItem;

	_count++;
	_mutations++;

	return listObject;
	return listItem;
}

- (of_list_object_t *)prependObject: (id)object
- (OFListItem *)prependObject: (id)object
{
	of_list_object_t *listObject;
	OFListItem *listItem = of_alloc(1, sizeof(OFListItem));

	listObject = of_alloc(1, sizeof(of_list_object_t));
	listObject->object = [object retain];
	listObject->next = _firstListObject;
	listObject->previous = NULL;
	listItem->object = [object retain];
	listItem->next = _firstListItem;
	listItem->previous = NULL;

	if (_firstListObject != NULL)
		_firstListObject->previous = listObject;
	if (_firstListItem != NULL)
		_firstListItem->previous = listItem;

	_firstListObject = listObject;
	if (_lastListObject == NULL)
		_lastListObject = listObject;
	_firstListItem = listItem;
	if (_lastListItem == NULL)
		_lastListItem = listItem;

	_count++;
	_mutations++;

	return listObject;
	return listItem;
}

- (of_list_object_t *)insertObject: (id)object
		  beforeListObject: (of_list_object_t *)listObject
- (OFListItem *)insertObject: (id)object
	      beforeListItem: (OFListItem *)listItem
{
	of_list_object_t *newListObject;
	OFListItem *newListItem = of_alloc(1, sizeof(OFListItem));

	newListObject = of_alloc(1, sizeof(of_list_object_t));
	newListObject->object = [object retain];
	newListObject->next = listObject;
	newListObject->previous = listObject->previous;
	newListItem->object = [object retain];
	newListItem->next = listItem;
	newListItem->previous = listItem->previous;

	if (listObject->previous != NULL)
		listObject->previous->next = newListObject;
	if (listItem->previous != NULL)
		listItem->previous->next = newListItem;

	listObject->previous = newListObject;
	listItem->previous = newListItem;

	if (listObject == _firstListObject)
		_firstListObject = newListObject;
	if (listItem == _firstListItem)
		_firstListItem = newListItem;

	_count++;
	_mutations++;

	return newListObject;
	return newListItem;
}

- (of_list_object_t *)insertObject: (id)object
		   afterListObject: (of_list_object_t *)listObject
- (OFListItem *)insertObject: (id)object
	       afterListItem: (OFListItem *)listItem
{
	of_list_object_t *newListObject;
	OFListItem *newListItem = of_alloc(1, sizeof(OFListItem));

	newListObject = of_alloc(1, sizeof(of_list_object_t));
	newListObject->object = [object retain];
	newListObject->next = listObject->next;
	newListObject->previous = listObject;
	newListItem->object = [object retain];
	newListItem->next = listItem->next;
	newListItem->previous = listItem;

	if (listObject->next != NULL)
		listObject->next->previous = newListObject;
	if (listItem->next != NULL)
		listItem->next->previous = newListItem;

	listObject->next = newListObject;
	listItem->next = newListItem;

	if (listObject == _lastListObject)
		_lastListObject = newListObject;
	if (listItem == _lastListItem)
		_lastListItem = newListItem;

	_count++;
	_mutations++;

	return newListObject;
	return newListItem;
}

- (void)removeListObject: (of_list_object_t *)listObject
- (void)removeListItem: (OFListItem *)listItem
{
	if (listObject->previous != NULL)
		listObject->previous->next = listObject->next;
	if (listObject->next != NULL)
		listObject->next->previous = listObject->previous;
	if (listItem->previous != NULL)
		listItem->previous->next = listItem->next;
	if (listItem->next != NULL)
		listItem->next->previous = listItem->previous;

	if (_firstListObject == listObject)
		_firstListObject = listObject->next;
	if (_lastListObject == listObject)
		_lastListObject = listObject->previous;
	if (_firstListItem == listItem)
		_firstListItem = listItem->next;
	if (_lastListItem == listItem)
		_lastListItem = listItem->previous;

	_count--;
	_mutations++;

	[listObject->object release];
	free(listObject);
	[listItem->object release];
	free(listItem);
}

- (id)firstObject
{
	return (_firstListObject != NULL ? _firstListObject->object : nil);
	return (_firstListItem != NULL ? _firstListItem->object : nil);
}

- (id)lastObject
{
	return (_lastListObject != NULL ? _lastListObject->object : nil);
	return (_lastListItem != NULL ? _lastListItem->object : nil);
}

- (size_t)count
{
	return _count;
}

- (bool)isEqual: (id)object
{
	OFList *list;
	of_list_object_t *iter, *iter2;
	OFListItem *iter, *iter2;

	if (object == self)
		return true;

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

	list = object;

	if (list.count != _count)
		return false;

	for (iter = _firstListObject, iter2 = list.firstListObject;
	for (iter = _firstListItem, iter2 = list.firstListItem;
	    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);

	return true;
}

- (bool)containsObject: (id)object
{
	if (_count == 0)
		return false;

	for (of_list_object_t *iter = _firstListObject;
	    iter != NULL; iter = iter->next)
	for (OFListItem *iter = _firstListItem; iter != NULL; iter = iter->next)
		if ([iter->object isEqual: object])
			return true;

	return false;
}

- (bool)containsObjectIdenticalTo: (id)object
{
	if (_count == 0)
		return false;

	for (of_list_object_t *iter = _firstListObject;
	    iter != NULL; iter = iter->next)
	for (OFListItem *iter = _firstListItem; iter != NULL; iter = iter->next)
		if (iter->object == object)
			return true;

	return false;
}

- (void)removeAllObjects
{
	of_list_object_t *next;
	OFListItem *next;

	_mutations++;

	for (of_list_object_t *iter = _firstListObject;
	    iter != NULL; iter = next) {
	for (OFListItem *iter = _firstListItem; iter != NULL; iter = next) {
		[iter->object release];
		next = iter->next;
		free(iter);
	}

	_firstListObject = _lastListObject = NULL;
	_firstListItem = _lastListItem = NULL;
}

- (id)copy
{
	OFList *copy = [[[self class] alloc] init];
	of_list_object_t *listObject, *previous;
	OFListItem *listItem, *previous;

	listObject = NULL;
	listItem = NULL;
	previous = NULL;

	@try {
		for (of_list_object_t *iter = _firstListObject;
		for (OFListItem *iter = _firstListItem;
		    iter != NULL; iter = iter->next) {
			listObject = of_alloc(1, sizeof(of_list_object_t));
			listObject->object = [iter->object retain];
			listObject->next = NULL;
			listObject->previous = previous;
			listItem = of_alloc(1, sizeof(OFListItem));
			listItem->object = [iter->object retain];
			listItem->next = NULL;
			listItem->previous = previous;

			if (copy->_firstListObject == NULL)
				copy->_firstListObject = listObject;
			if (copy->_firstListItem == NULL)
				copy->_firstListItem = listItem;
			if (previous != NULL)
				previous->next = listObject;
				previous->next = listItem;

			copy->_count++;

			previous = listObject;
			previous = listItem;
		}
	} @catch (id e) {
		[copy release];
		@throw e;
	}

	copy->_lastListObject = listObject;
	copy->_lastListItem = listItem;

	return copy;
}

- (unsigned long)hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	for (of_list_object_t *iter = _firstListObject;
	for (OFListItem *iter = _firstListItem;
	    iter != NULL; iter = iter->next)
		OF_HASH_ADD_HASH(hash, [iter->object hash]);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString *)description
{
	OFMutableString *ret;

	if (_count == 0)
		return @"[]";

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

	for (of_list_object_t *iter = _firstListObject;
	for (OFListItem *iter = _firstListItem;
	    iter != NULL; iter = iter->next) {
		void *pool = objc_autoreleasePoolPush();

		[ret appendString: [iter->object description]];

		if (iter->next != NULL)
			[ret appendString: @",\n"];
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391

392
393

394
395
396
397
398
399

400
401
402
403
404

405
406
407
408


409
410
411

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431

432
433
434
435
436
437
438
360
361
362
363
364
365
366

367
368
369
370
371
372
373
374
375
376
377
378

379
380
381
382

383
384

385
386
387
388
389
390

391
392
393
394
395

396
397
398


399
400
401
402

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422

423
424
425
426
427
428
429
430







-
+











-
+



-
+

-
+





-
+




-
+


-
-
+
+


-
+



















-
+








- (OFXMLElement *)XMLElementBySerializing
{
	OFXMLElement *element =
	    [OFXMLElement elementWithName: self.className
				namespace: OF_SERIALIZATION_NS];

	for (of_list_object_t *iter = _firstListObject;
	for (OFListItem *iter = _firstListItem;
	    iter != NULL; iter = iter->next) {
		void *pool = objc_autoreleasePoolPush();

		[element addChild: [iter->object XMLElementBySerializing]];

		objc_autoreleasePoolPop(pool);
	}

	return element;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	of_list_object_t *listObject;
	OFListItem *listItem;

	memcpy(&listObject, state->extra, sizeof(listObject));
	memcpy(&listItem, state->extra, sizeof(listItem));

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

	if (state->state == 0) {
		listObject = _firstListObject;
		listItem = _firstListItem;
		state->state = 1;
	}

	for (int i = 0; i < count; i++) {
		if (listObject == NULL)
		if (listItem == NULL)
			return i;

		objects[i] = listObject->object;
		listObject = listObject->next;
		objects[i] = listItem->object;
		listItem = listItem->next;
	}

	memcpy(state->extra, &listObject, sizeof(listObject));
	memcpy(state->extra, &listItem, sizeof(listItem));

	return count;
}

- (OFEnumerator *)objectEnumerator
{
	return [[[OFListEnumerator alloc] initWithList: self
				      mutationsPointer: &_mutations]
	    autorelease];
}
@end

@implementation OFListEnumerator
- (instancetype)initWithList: (OFList *)list
	    mutationsPointer: (unsigned long *)mutationsPtr
{
	self = [super init];

	_list = [list retain];
	_current = _list.firstListObject;
	_current = _list.firstListItem;
	_mutations = *mutationsPtr;
	_mutationsPtr = mutationsPtr;

	return self;
}

- (void)dealloc

Modified src/OFLocale.h from [88c5c97127] to [323b529f40].

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







-
+









-
+







 *
 * @brief A class for querying the locale and retrieving localized strings.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFLocale: OFObject
{
	OFString *_Nullable _language, *_Nullable _territory;
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
	OFString *_decimalPoint;
	OFMutableArray OF_GENERIC(OFDictionary OF_GENERIC(OFString *, id) *)
	    *_localizedStrings;
}

#ifdef OF_HAVE_CLASS_PROPERTIES
@property (class, readonly, nullable, nonatomic) OFLocale *currentLocale;
@property (class, readonly, nullable, nonatomic) OFString *language;
@property (class, readonly, nullable, nonatomic) OFString *territory;
@property (class, readonly, nonatomic) of_string_encoding_t encoding;
@property (class, readonly, nonatomic) OFStringEncoding encoding;
@property (class, readonly, nullable, nonatomic) OFString *decimalPoint;
#endif

/**
 * @brief The language of the locale for messages.
 *
 * If the language is unknown, it is `nil`.
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







-
+







 * @brief The native 8-bit string encoding of the locale for messages.
 *
 * This is useful to encode strings correctly for passing them to operating
 * system calls.
 *
 * If the native 8-bit encoding is unknown, UTF-8 is assumed.
 */
@property (readonly, nonatomic) of_string_encoding_t encoding;
@property (readonly, nonatomic) OFStringEncoding encoding;

/**
 * @brief The decimal point of the system's locale.
 */
@property (readonly, nonatomic) OFString *decimalPoint;

/**
123
124
125
126
127
128
129
130

131
132
133
134
135
136
137
123
124
125
126
127
128
129

130
131
132
133
134
135
136
137







-
+







 * This is useful to encode strings correctly for passing them to operating
 * system calls.
 *
 * If the native 8-bit encoding is unknown, UTF-8 is assumed.
 *
 * @return The native 8-bit string encoding for the locale
 */
+ (of_string_encoding_t)encoding;
+ (OFStringEncoding)encoding;

/**
 * @brief Returns the decimal point of the system's locale.
 *
 * @return The decimal point of the system's locale
 */
+ (nullable OFString *)decimalPoint;

Modified src/OFLocale.m from [43f4209e77] to [d90d567f44].

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







-
+






-
+












-
+







#endif

static OFLocale *currentLocale = nil;
static OFDictionary *operatorPrecedences = nil;

#ifndef OF_AMIGAOS
static void
parseLocale(char *locale, of_string_encoding_t *encoding,
parseLocale(char *locale, OFStringEncoding *encoding,
    OFString **language, OFString **territory)
{
	if ((locale = of_strdup(locale)) == NULL)
		return;

	@try {
		const of_string_encoding_t enc = OF_STRING_ENCODING_ASCII;
		OFStringEncoding enc = OFStringEncodingASCII;
		char *tmp;

		/* We don't care for extras behind the @ */
		if ((tmp = strrchr(locale, '@')) != NULL)
			*tmp = '\0';

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

			@try {
				if (encoding != NULL)
					*encoding = of_string_parse_encoding(
					*encoding = OFParseStringEncodingName(
					    [OFString stringWithCString: tmp
							       encoding: enc]);
			} @catch (OFInvalidArgumentException *e) {
			}
		}

		/* Territory */
104
105
106
107
108
109
110
111

112
113

114
115
116
117
118
119
120
104
105
106
107
108
109
110

111
112

113
114
115
116
117
118
119
120







-
+

-
+







	[condition replaceOccurrencesOfString: @")" withString: @" )"];

	/* Substitute variables and convert to RPN first */
	tokens = [OFMutableArray array];
	operators = [OFMutableArray array];
	for (OFString *token in [condition
	    componentsSeparatedByString: @" "
				options: OF_STRING_SKIP_EMPTY]) {
				options: OFStringSkipEmptyComponents]) {
		unsigned precedence;
		of_unichar_t c;
		OFUnichar c;

		if ([token isEqual: @"("]) {
			[operators addObject: @"("];
			continue;
		}

		if ([token isEqual: @")"]) {
193
194
195
196
197
198
199
200

201
202
203

204
205
206

207
208
209

210
211
212
213
214
215
216
193
194
195
196
197
198
199

200
201
202

203
204
205

206
207
208

209
210
211
212
213
214
215
216







-
+


-
+


-
+


-
+







				var = [OFNumber numberWithBool:
				    [first isEqual: second]];
			else if ([token isEqual: @"!="])
				var = [OFNumber numberWithBool:
				    ![first isEqual: second]];
			else if ([token isEqual: @"<"])
				var = [OFNumber numberWithBool: [first
				    compare: second] == OF_ORDERED_ASCENDING];
				    compare: second] == OFOrderedAscending];
			else if ([token isEqual: @"<="])
				var = [OFNumber numberWithBool: [first
				    compare: second] != OF_ORDERED_DESCENDING];
				    compare: second] != OFOrderedDescending];
			else if ([token isEqual: @">"])
				var = [OFNumber numberWithBool: [first
				    compare: second] == OF_ORDERED_DESCENDING];
				    compare: second] == OFOrderedDescending];
			else if ([token isEqual: @">="])
				var = [OFNumber numberWithBool: [first
				    compare: second] != OF_ORDERED_ASCENDING];
				    compare: second] != OFOrderedAscending];
			else if ([token isEqual: @"+"])
				var = [OFNumber numberWithDouble:
				    [first doubleValue] + [second doubleValue]];
			else if ([token isEqual: @"%"])
				var = [OFNumber numberWithLongLong:
				    [first longLongValue] %
				    [second longLongValue]];
347
348
349
350
351
352
353
354

355
356
357
358
359
360
361
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361







-
+







}

+ (OFString *)territory
{
	return currentLocale.territory;
}

+ (of_string_encoding_t)encoding
+ (OFStringEncoding)encoding
{
	return currentLocale.encoding;
}

+ (OFString *)decimalPoint
{
	return currentLocale.decimalPoint;
376
377
378
379
380
381
382
383

384
385
386
387
388
389
390
376
377
378
379
380
381
382

383
384
385
386
387
388
389
390







-
+







#ifndef OF_AMIGAOS
		char *locale, *messagesLocale = NULL;

		if (currentLocale != nil)
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_encoding = OF_STRING_ENCODING_UTF_8;
		_encoding = OFStringEncodingUTF8;
		_decimalPoint = @".";
		_localizedStrings = [[OFMutableArray alloc] init];

		if ((locale = setlocale(LC_ALL, "")) != NULL)
			_decimalPoint = [[OFString alloc]
			    initWithCString: localeconv()->decimal_point
				   encoding: _encoding];
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
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







-
+


-
+



-
+


-
+







# if defined(OF_MORPHOS)
		if (GetVar("CODEPAGE", buffer, sizeof(buffer), 0) > 0) {
# elif defined(OF_AMIGAOS4)
		if (GetVar("Charset", buffer, sizeof(buffer), 0) > 0) {
# else
		if (0) {
# endif
			of_string_encoding_t ASCII = OF_STRING_ENCODING_ASCII;
			OFStringEncoding ASCII = OFStringEncodingASCII;

			@try {
				_encoding = of_string_parse_encoding(
				_encoding = OFStringEncodingForName(
				    [OFString stringWithCString: buffer
						       encoding: ASCII]);
			} @catch (OFInvalidArgumentException *e) {
				_encoding = OF_STRING_ENCODING_ISO_8859_1;
				_encoding = OFStringEncodingISO8859_1;
			}
		} else
			_encoding = OF_STRING_ENCODING_ISO_8859_1;
			_encoding = OFStringEncodingISO8859_1;

		/*
		 * Get it via localeconv() instead of from the Locale struct,
		 * to make sure we and printf etc. have the same expectations.
		 */
		_decimalPoint = [[OFString alloc]
		    initWithCString: localeconv()->decimal_point

Modified src/OFMapTable.h from [428b0aea8c] to [843bd062c2].

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







-
+









-
+







 * @brief A block for enumerating an OFMapTable.
 *
 * @param key The current key
 * @param object The current object
 * @param stop A pointer to a variable that can be set to true to stop the
 *	       enumeration
 */
typedef void (^of_map_table_enumeration_block_t)(void *_Nullable key,
typedef void (^OFMapTableEnumerationBlock)(void *_Nullable key,
    void *_Nullable object, bool *stop);

/**
 * @brief A block for replacing objects in an OFMapTable.
 *
 * @param key The key of the object to replace
 * @param object The object to replace
 * @return The object to replace the object with
 */
typedef void *_Nullable (^of_map_table_replace_block_t)(void *_Nullable key,
typedef void *_Nullable (^OFMapTableReplaceBlock)(void *_Nullable key,
    void *_Nullable object);
#endif

@class OFMapTableEnumerator;

/**
 * @class OFMapTable OFMapTable.h ObjFW/OFMapTable.h
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228

229
230
231
232
233
234
235
213
214
215
216
217
218
219

220

221
222
223
224
225
226

227
228
229
230
231
232
233
234







-
+
-






-
+








#ifdef OF_HAVE_BLOCKS
/**
 * @brief Executes a block for each key / object pair.
 *
 * @param block The block to execute for each key / object pair.
 */
- (void)enumerateKeysAndObjectsUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock: (OFMapTableEnumerationBlock)block;
    (of_map_table_enumeration_block_t)block;

/**
 * @brief Replaces each object with the object returned by the block.
 *
 * @param block The block which returns a new object for each object
 */
- (void)replaceObjectsUsingBlock: (of_map_table_replace_block_t)block;
- (void)replaceObjectsUsingBlock: (OFMapTableReplaceBlock)block;
#endif
@end

/**
 * @class OFMapTableEnumerator OFMapTable.h ObjFW/OFMapTable.h
 *
 * @brief A class which provides methods to enumerate through an OFMapTable's

Modified src/OFMapTable.m from [8788cb21e4] to [69ee51ce08].

572
573
574
575
576
577
578
579

580
581
582
583
584
585
586
572
573
574
575
576
577
578

579
580
581
582
583
584
585
586







-
+







	return [[[OFMapTableObjectEnumerator alloc]
	    of_initWithMapTable: self
			buckets: _buckets
		       capacity: _capacity
	       mutationsPointer: &_mutations] autorelease];
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	unsigned long j = state->state;
	int i;

	for (i = 0; i < count; i++) {
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
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







-
+
-














-
+







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

	return i;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndObjectsUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock: (OFMapTableEnumerationBlock)block
    (of_map_table_enumeration_block_t)block
{
	bool stop = false;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < _capacity && !stop; i++) {
		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];

		if (_buckets[i] != NULL && _buckets[i] != &deleted)
			block(_buckets[i]->key, _buckets[i]->object, &stop);
	}
}

- (void)replaceObjectsUsingBlock: (of_map_table_replace_block_t)block
- (void)replaceObjectsUsingBlock: (OFMapTableReplaceBlock)block
{
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < _capacity; i++) {
		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];

Modified src/OFMapTableDictionary.m from [992c305595] to [b911edeffb].

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







-
+









-
+
-







- (OFEnumerator *)objectEnumerator
{
	return [[[OFMapTableEnumeratorWrapper alloc]
	    initWithEnumerator: [_mapTable objectEnumerator]
			object: self] autorelease];
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	return [_mapTable countByEnumeratingWithState: state
					      objects: objects
						count: count];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndObjectsUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock: (OFDictionaryEnumerationBlock)block
    (of_dictionary_enumeration_block_t)block
{
	@try {
		[_mapTable enumerateKeysAndObjectsUsingBlock:
		    ^ (void *key, void *object, bool *stop) {
			block(key, object, stop);
		}];
	} @catch (OFEnumerationMutationException *e) {

Modified src/OFMapTableSet.m from [c0e93f6d5b] to [8d95facb2a].

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







-
+









-
+













- (OFEnumerator *)objectEnumerator
{
	return [[[OFMapTableEnumeratorWrapper alloc]
	    initWithEnumerator: [_mapTable keyEnumerator]
			object: self] autorelease];
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	return [_mapTable countByEnumeratingWithState: state
					      objects: objects
						count: count];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block
- (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block
{
	@try {
		[_mapTable enumerateKeysAndObjectsUsingBlock:
		    ^ (void *key, void *object, bool *stop) {
			block(key, stop);
		}];
	} @catch (OFEnumerationMutationException *e) {
		@throw [OFEnumerationMutationException
		    exceptionWithObject: self];
	}
}
#endif
@end

Modified src/OFMutableAdjacentArray.m from [7c769150fe] to [93f56cbca2].

219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233







-
+








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

	[_array removeAllItems];
}

- (void)removeObjectsInRange: (of_range_t)range
- (void)removeObjectsInRange: (OFRange)range
{
	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)
289
290
291
292
293
294
295
296

297
298
299
300
301
302
303
289
290
291
292
293
294
295

296
297
298
299
300
301
302
303







-
+







	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
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count_
{
	size_t count = _array.count;

	if (count > INT_MAX) {
		/*
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
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







-
+















-
+







{
	return [[[OFArrayEnumerator alloc]
	    initWithArray: self
	     mutationsPtr: &_mutations] autorelease];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block
{
	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
- (void)replaceObjectsUsingBlock: (OFArrayReplaceBlock)block
{
	id *objects = _array.mutableItems;
	size_t count = _array.count;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < count; i++) {
		id new;

Modified src/OFMutableArray.h from [16603a1ba8] to [a684ec1cde].

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







-
+







/**
 * @brief A block for replacing values in an OFMutableArray.
 *
 * @param object The object to replace
 * @param index The index of the object to replace
 * @return The object to replace the object with
 */
typedef id _Nonnull (^of_array_replace_block_t)(id object, size_t index);
typedef id _Nonnull (^OFArrayReplaceBlock)(id object, size_t index);
#endif

/**
 * @class OFMutableArray OFArray.h ObjFW/OFArray.h
 *
 * @brief An abstract class for storing, adding and removing objects in an
 *	  array.
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
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







-
+

















-
+




















-
+
-
-
-
-

-
+






-
+
-
-
-
-

-
+
+







- (void)removeObjectAtIndex: (size_t)index;

/**
 * @brief Removes the object in the specified range.
 *
 * @param range The range of the objects to remove
 */
- (void)removeObjectsInRange: (of_range_t)range;
- (void)removeObjectsInRange: (OFRange)range;

/**
 * @brief Removes the last object.
 */
- (void)removeLastObject;

/**
 * @brief Removes all objects.
 */
- (void)removeAllObjects;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Replaces each object with the object returned by the block.
 *
 * @param block The block which returns a new object for each object
 */
- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block;
- (void)replaceObjectsUsingBlock: (OFArrayReplaceBlock)block;
#endif

/**
 * @brief Exchange the objects at the specified indices.
 *
 * @param index1 The index of the first object to exchange
 * @param index2 The index of the second object to exchange
 */
- (void)exchangeObjectAtIndex: (size_t)index1 withObjectAtIndex: (size_t)index2;

/**
 * @brief Sorts the array in ascending order.
 */
- (void)sort;

/**
 * @brief Sorts the array using the specified selector and options.
 *
 * @param selector The selector to use to sort the array. It's signature
 *		   should be the same as that of -[compare:].
 * @param options The options to use when sorting the array.@n
 * @param options The options to use when sorting the array
 *		  Possible values are:
 *		  Value                      | Description
 *		  ---------------------------|-------------------------
 *		  `OF_ARRAY_SORT_DESCENDING` | Sort in descending order
 */
- (void)sortUsingSelector: (SEL)selector options: (int)options;
- (void)sortUsingSelector: (SEL)selector options: (OFArraySortOptions)options;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Sorts the array using the specified comparator and options.
 *
 * @param comparator The comparator to use to sort the array
 * @param options The options to use when sorting the array.@n
 * @param options The options to use when sorting the array
 *		  Possible values are:
 *		  Value                      | Description
 *		  ---------------------------|-------------------------
 *		  `OF_ARRAY_SORT_DESCENDING` | Sort in descending order
 */
- (void)sortUsingComparator: (of_comparator_t)comparator options: (int)options;
- (void)sortUsingComparator: (OFComparator)comparator
		    options: (OFArraySortOptions)options;
#endif

/**
 * @brief Reverts the order of the objects in the array.
 */
- (void)reverse;

Modified src/OFMutableArray.m from [2a2941cb17] to [680aac7358].

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







-
+


-
-
+
+







-
+

-
+

-
-
-
+
+
+

-
-
+
+







static struct {
	Class isa;
} placeholder;

@interface OFMutableArrayPlaceholder: OFMutableArray
@end

static of_comparison_result_t
static OFComparisonResult
compare(id left, id right, SEL selector)
{
	of_comparison_result_t (*comparator)(id, SEL, id) =
	    (of_comparison_result_t (*)(id, SEL, id))
	OFComparisonResult (*comparator)(id, SEL, id) =
	    (OFComparisonResult (*)(id, SEL, id))
	    [left methodForSelector: selector];

	return comparator(left, selector, right);
}

static void
quicksort(OFMutableArray *array, size_t left, size_t right, SEL selector,
    int options)
    OFArraySortOptions options)
{
	of_comparison_result_t ascending, descending;
	OFComparisonResult ascending, descending;

	if (options & OF_ARRAY_SORT_DESCENDING) {
		ascending = OF_ORDERED_DESCENDING;
		descending = OF_ORDERED_ASCENDING;
	if (options & OFArraySortDescending) {
		ascending = OFOrderedDescending;
		descending = OFOrderedAscending;
	} else {
		ascending = OF_ORDERED_ASCENDING;
		descending = OF_ORDERED_DESCENDING;
		ascending = OFOrderedAscending;
		descending = OFOrderedDescending;
	}

	while (left < right) {
		size_t i = left;
		size_t j = right - 1;
		id pivot = [array objectAtIndex: right];

88
89
90
91
92
93
94
95

96
97

98
99
100
101



102
103
104


105
106
107
108
109
110
111
88
89
90
91
92
93
94

95
96

97
98



99
100
101
102


103
104
105
106
107
108
109
110
111







-
+

-
+

-
-
-
+
+
+

-
-
+
+







		left = i + 1;
	}
}

#ifdef OF_HAVE_BLOCKS
static void
quicksortWithBlock(OFMutableArray *array, size_t left, size_t right,
    of_comparator_t comparator, int options)
    OFComparator comparator, OFArraySortOptions options)
{
	of_comparison_result_t ascending, descending;
	OFComparisonResult ascending, descending;

	if (options & OF_ARRAY_SORT_DESCENDING) {
		ascending = OF_ORDERED_DESCENDING;
		descending = OF_ORDERED_ASCENDING;
	if (options & OFArraySortDescending) {
		ascending = OFOrderedDescending;
		descending = OFOrderedAscending;
	} else {
		ascending = OF_ORDERED_ASCENDING;
		descending = OF_ORDERED_DESCENDING;
		ascending = OFOrderedAscending;
		descending = OFOrderedDescending;
	}

	while (left < right) {
		size_t i = left;
		size_t j = right - 1;
		id pivot = [array objectAtIndex: right];

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







-
+

















-
+



-
+







			[self removeObjectAtIndex: i];

			return;
		}
	}
}

- (void)removeObjectsInRange: (of_range_t)range
- (void)removeObjectsInRange: (OFRange)range
{
	for (size_t i = 0; i < range.length; i++)
		[self removeObjectAtIndex: range.location];
}

- (void)removeLastObject
{
	size_t count = self.count;

	if (count == 0)
		return;

	[self removeObjectAtIndex: count - 1];
}

- (void)removeAllObjects
{
	[self removeObjectsInRange: of_range(0, self.count)];
	[self removeObjectsInRange: OFMakeRange(0, self.count)];
}

#ifdef OF_HAVE_BLOCKS
- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block
- (void)replaceObjectsUsingBlock: (OFArrayReplaceBlock)block
{
	[self enumerateObjectsUsingBlock: ^ (id object, size_t idx,
	    bool *stop) {
		id new = block(object, idx);

		if (new != object)
			[self replaceObjectAtIndex: idx withObject: new];
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
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







-
+










-
+
+








- (void)sort
{
	[self sortUsingSelector: @selector(compare:) options: 0];
}

- (void)sortUsingSelector: (SEL)selector
		  options: (int)options
		  options: (OFArraySortOptions)options
{
	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
- (void)sortUsingComparator: (OFComparator)comparator
		    options: (OFArraySortOptions)options
{
	size_t count = self.count;

	if (count == 0 || count == 1)
		return;

	quicksortWithBlock(self, 0, count - 1, comparator, options);

Modified src/OFMutableData.h from [7e3b1e1f63] to [8cc32bdba7].

186
187
188
189
190
191
192
193

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

193
194
195
196
197
198
199
200







-
+







- (void)removeItemAtIndex: (size_t)index;

/**
 * @brief Removes the specified amount of items at the specified index.
 *
 * @param range The range of items to remove
 */
- (void)removeItemsInRange: (of_range_t)range;
- (void)removeItemsInRange: (OFRange)range;

/**
 * @brief Removes the last item.
 */
- (void)removeLastItem;

/**

Modified src/OFMutableData.m from [01aa579278] to [641dd5b634].

160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
160
161
162
163
164
165
166

167
168
169
170
171
172
173
174







-
+







{
	if (_items == NULL || _count == 0)
		return NULL;

	return _items + (_count - 1) * _itemSize;
}

- (OFData *)subdataWithRange: (of_range_t)range
- (OFData *)subdataWithRange: (OFRange)range
{
	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _count)
		@throw [OFOutOfRangeException exception];

	return [OFData dataWithItems: _items + (range.location * _itemSize)
			       count: range.length
240
241
242
243
244
245
246
247

248
249
250

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

247
248
249

250
251
252
253
254
255
256
257







-
+


-
+








	memset(_items + _count * _itemSize, '\0', count * _itemSize);
	_count += count;
}

- (void)removeItemAtIndex: (size_t)idx
{
	[self removeItemsInRange: of_range(idx, 1)];
	[self removeItemsInRange: OFMakeRange(idx, 1)];
}

- (void)removeItemsInRange: (of_range_t)range
- (void)removeItemsInRange: (OFRange)range
{
	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _count)
		@throw [OFOutOfRangeException exception];

	memmove(_items + range.location * _itemSize,
	    _items + (range.location + range.length) * _itemSize,

Modified src/OFMutableDictionary.h from [d0bf1761a1] to [d2bbc1da30].

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







-
+







/**
 * @brief A block for replacing objects in an OFMutableDictionary.
 *
 * @param key The key of the object to replace
 * @param object The object to replace
 * @return The object to replace the object with
 */
typedef id _Nonnull (^of_dictionary_replace_block_t)(id key, id object);
typedef id _Nonnull (^OFDictionaryReplaceBlock)(id key, id object);
#endif

/**
 * @class OFMutableDictionary OFDictionary.h ObjFW/OFDictionary.h
 *
 * @brief An abstract class for storing and changing objects in a dictionary.
 *
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
123
124
125
126
127
128







-
+














#ifdef OF_HAVE_BLOCKS
/**
 * @brief Replaces each object with the object returned by the block.
 *
 * @param block The block which returns a new object for each object
 */
- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block;
- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block;
#endif

/**
 * @brief Converts the mutable dictionary to an immutable dictionary.
 */
- (void)makeImmutable;
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef KeyType
# undef ObjectType
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFMutableDictionary.m from [76370e25f8] to [e5de8c4c10].

197
198
199
200
201
202
203
204

205
206
207
208
209
210
211
197
198
199
200
201
202
203

204
205
206
207
208
209
210
211







-
+







	    (object = [objectEnumerator nextObject]) != nil)
		[self setObject: object forKey: key];

	objc_autoreleasePoolPop(pool);
}

#ifdef OF_HAVE_BLOCKS
- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block
- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block
{
	[self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object,
	    bool *stop) {
		id new = block(key, object);

		if (new != object) {
			[self setObject: block(key, object) forKey: key];

Modified src/OFMutableMapTableDictionary.m from [b27a83ce2f] to [1009eb93ce].

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







-
+








- (void)removeAllObjects
{
	[_mapTable removeAllObjects];
}

#ifdef OF_HAVE_BLOCKS
- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block
- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block
{
	@try {
		[_mapTable replaceObjectsUsingBlock:
		    ^ void *(void *key, void *object) {
			return block(key, object);
		}];
	} @catch (OFEnumerationMutationException *e) {

Modified src/OFMutableString.h from [ae1870f5f2] to [9719f9d256].

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







-
+














-
+
-







@interface OFMutableString: OFString
/**
 * @brief Sets the character at the specified index.
 *
 * @param character The character to set
 * @param index The index where to set the character
 */
- (void)setCharacter: (of_unichar_t)character atIndex: (size_t)index;
- (void)setCharacter: (OFUnichar)character atIndex: (size_t)index;

/**
 * @brief Appends another OFString to the OFMutableString.
 *
 * @param string An OFString to append
 */
- (void)appendString: (OFString *)string;

/**
 * @brief Appends the specified characters to the OFMutableString.
 *
 * @param characters An array of characters to append
 * @param length The length of the array of characters
 */
- (void)appendCharacters: (const of_unichar_t *)characters
- (void)appendCharacters: (const OFUnichar *)characters length: (size_t)length;
		  length: (size_t)length;

/**
 * @brief Appends a UTF-8 encoded C string to the OFMutableString.
 *
 * @param UTF8String A UTF-8 encoded C string to append
 */
- (void)appendUTF8String: (const char *)UTF8String;
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
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







-
+










-
+






-
-
+
+









-
-
+
+







/**
 * @brief Appends a C string with the specified encoding to the OFMutableString.
 *
 * @param cString A C string to append
 * @param encoding The encoding of the C string
 */
- (void)appendCString: (const char *)cString
	     encoding: (of_string_encoding_t)encoding;
	     encoding: (OFStringEncoding)encoding;

/**
 * @brief Appends a C string with the specified encoding and length to the
 *	  OFMutableString.
 *
 * @param cString A C string to append
 * @param encoding The encoding of the C string
 * @param cStringLength The length of the UTF-8 encoded C string
 */
- (void)appendCString: (const char *)cString
	     encoding: (of_string_encoding_t)encoding
	     encoding: (OFStringEncoding)encoding
	       length: (size_t)cStringLength;

/**
 * @brief Appends a formatted string to the OFMutableString.
 *
 * See `printf` for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A format string which generates the string to append
 */
- (void)appendFormat: (OFConstantString *)format, ...;

/**
 * @brief Appends a formatted string to the OFMutableString.
 *
 * See printf for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A format string which generates the string to append
 * @param arguments The arguments used in the format string
 */
- (void)appendFormat: (OFConstantString *)format arguments: (va_list)arguments;

/**
152
153
154
155
156
157
158
159

160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165

166
167
168
169
170
171
172
173







-
+







-
+







- (void)insertString: (OFString *)string atIndex: (size_t)index;

/**
 * @brief Deletes the characters at the specified range.
 *
 * @param range The range of the characters which should be removed
 */
- (void)deleteCharactersInRange: (of_range_t)range;
- (void)deleteCharactersInRange: (OFRange)range;

/**
 * @brief Replaces the characters at the specified range.
 *
 * @param range The range of the characters which should be replaced
 * @param replacement The string to the replace the characters with
 */
- (void)replaceCharactersInRange: (of_range_t)range
- (void)replaceCharactersInRange: (OFRange)range
		      withString: (OFString *)replacement;

/**
 * @brief Replaces all occurrences of a string with another string.
 *
 * @param string The string to replace
 * @param replacement The string with which it should be replaced
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
184
185
186
187
188
189
190

191
192
193
194
195
196
197
198







-
+







 * @param options Options modifying search behaviour
 *		  Possible values: None yet
 * @param range The range in which the string should be replaced
 */
- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
			   options: (int)options
			     range: (of_range_t)range;
			     range: (OFRange)range;

/**
 * @brief Deletes all whitespaces at the beginning of the string.
 */
- (void)deleteLeadingWhitespaces;

/**

Modified src/OFMutableString.m from [e8ac978dc5] to [440135bc21].

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







-
+






-
+












-
+






-
+




-
+






-
-
+
+





-
+

-
+






-
+




-
+






-
-
+
+





-
+

-
+







{
	return (id)[[OFMutableUTF8String alloc]
	    initWithUTF8String: UTF8String
			length: UTF8StringLength];
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
{
	return (id)[[OFMutableUTF8String alloc] initWithCString: cString
						       encoding: encoding];
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)cStringLength
{
	return (id)[[OFMutableUTF8String alloc] initWithCString: cString
						       encoding: encoding
							 length: cStringLength];
}

- (instancetype)initWithString: (OFString *)string
{
	return (id)[[OFMutableUTF8String alloc] initWithString: string];
}

- (instancetype)initWithCharacters: (const of_unichar_t *)characters
- (instancetype)initWithCharacters: (const OFUnichar *)characters
			    length: (size_t)length
{
	return (id)[[OFMutableUTF8String alloc] initWithCharacters: characters
							    length: length];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string
							      length: length];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
			  byteOrder: (of_byte_order_t)byteOrder
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string
							  byteOrder: byteOrder];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string
							     length: length
							  byteOrder: byteOrder];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string
							     length: length];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
			  byteOrder: (of_byte_order_t)byteOrder
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string
							  byteOrder: byteOrder];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string
							     length: length
							  byteOrder: byteOrder];
}

- (instancetype)initWithFormat: (OFConstantString *)format, ...
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
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







-
+













-
+







#ifdef OF_HAVE_FILES
- (instancetype)initWithContentsOfFile: (OFString *)path
{
	return (id)[[OFMutableUTF8String alloc] initWithContentsOfFile: path];
}

- (instancetype)initWithContentsOfFile: (OFString *)path
			      encoding: (of_string_encoding_t)encoding
			      encoding: (OFStringEncoding)encoding
{
	return (id)[[OFMutableUTF8String alloc]
	    initWithContentsOfFile: path
			  encoding: encoding];
}
#endif

- (instancetype)initWithContentsOfURL: (OFURL *)URL
{
	return (id)[[OFMutableUTF8String alloc] initWithContentsOfURL: URL];
}

- (instancetype)initWithContentsOfURL: (OFURL *)URL
			     encoding: (of_string_encoding_t)encoding
			     encoding: (OFStringEncoding)encoding
{
	return (id)[[OFMutableUTF8String alloc]
	    initWithContentsOfURL: URL
			 encoding: encoding];
}

- (instancetype)initWithSerialization: (OFXMLElement *)element
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
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







-
-
+
+




-
+




-
+

-
+







	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 OFUnichar *const [])startTable
		     wordMiddleTable: (const OFUnichar *const [])middleTable
		  wordStartTableSize: (size_t)startTableSize
		 wordMiddleTableSize: (size_t)middleTableSize
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *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;
		const OFUnichar *const *table;
		size_t tableSize;
		of_unichar_t c = characters[i];
		OFUnichar c = characters[i];

		if (isStart) {
			table = startTable;
			tableSize = middleTableSize;
		} else {
			table = middleTable;
			tableSize = middleTableSize;
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
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







-
+






-
+











-
+




-
+








-
+







}
#else
static void
convert(OFMutableString *self, char (*startFunction)(char),
    char (*middleFunction)(char))
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *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];
		OFUnichar c = characters[i];

		if (c <= 0x7F)
			[self setCharacter: (int)function(c) atIndex: i];

		isStart = of_ascii_isspace(c);
	}

	objc_autoreleasePoolPop(pool);
}
#endif

- (void)setCharacter: (of_unichar_t)character atIndex: (size_t)idx
- (void)setCharacter: (OFUnichar)character atIndex: (size_t)idx
{
	void *pool = objc_autoreleasePoolPush();
	OFString *string =
	    [OFString stringWithCharacters: &character length: 1];
	[self replaceCharactersInRange: of_range(idx, 1) withString: string];
	[self replaceCharactersInRange: OFMakeRange(idx, 1) withString: string];
	objc_autoreleasePoolPop(pool);
}

- (void)appendString: (OFString *)string
{
	[self insertString: string atIndex: self.length];
}

- (void)appendCharacters: (const of_unichar_t *)characters
- (void)appendCharacters: (const OFUnichar *)characters
		  length: (size_t)length
{
	void *pool = objc_autoreleasePoolPush();
	[self appendString: [OFString stringWithCharacters: characters
						    length: length]];
	objc_autoreleasePoolPop(pool);
}
320
321
322
323
324
325
326
327

328
329
330
331
332
333
334
335
336

337
338
339
340
341
342
343
320
321
322
323
324
325
326

327
328
329
330
331
332
333
334
335

336
337
338
339
340
341
342
343







-
+








-
+







	void *pool = objc_autoreleasePoolPush();
	[self appendString: [OFString stringWithUTF8String: UTF8String
						    length: UTF8StringLength]];
	objc_autoreleasePoolPop(pool);
}

- (void)appendCString: (const char *)cString
	     encoding: (of_string_encoding_t)encoding
	     encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	[self appendString: [OFString stringWithCString: cString
					       encoding: encoding]];
	objc_autoreleasePoolPop(pool);
}

- (void)appendCString: (const char *)cString
	     encoding: (of_string_encoding_t)encoding
	     encoding: (OFStringEncoding)encoding
	       length: (size_t)cStringLength
{
	void *pool = objc_autoreleasePoolPush();
	[self appendString: [OFString stringWithCString: cString
					       encoding: encoding
						 length: cStringLength]];
	objc_autoreleasePoolPop(pool);
378
379
380
381
382
383
384
385

386
387
388
389
390
391
392
378
379
380
381
382
383
384

385
386
387
388
389
390
391
392







-
+







}

- (void)reverse
{
	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];
		OFUnichar tmp = [self characterAtIndex: j];
		[self setCharacter: [self characterAtIndex: i] atIndex: j];
		[self setCharacter: tmp atIndex: i];
	}
}

#ifdef OF_HAVE_UNICODE_TABLES
- (void)uppercase
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
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
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
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







-
+


-
+




-
+











-
+





-
+


-
-
+
+




















-
+


-
+



















-
+



-
+







-
+





-
+




















-
+







{
	convert(self, of_ascii_toupper, of_ascii_tolower);
}
#endif

- (void)insertString: (OFString *)string atIndex: (size_t)idx
{
	[self replaceCharactersInRange: of_range(idx, 0) withString: string];
	[self replaceCharactersInRange: OFMakeRange(idx, 0) withString: string];
}

- (void)deleteCharactersInRange: (of_range_t)range
- (void)deleteCharactersInRange: (OFRange)range
{
	[self replaceCharactersInRange: range withString: @""];
}

- (void)replaceCharactersInRange: (of_range_t)range
- (void)replaceCharactersInRange: (OFRange)range
		      withString: (OFString *)replacement
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
{
	[self replaceOccurrencesOfString: string
			      withString: replacement
				 options: 0
				   range: of_range(0, self.length)];
				   range: OFMakeRange(0, self.length)];
}

- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
			   options: (int)options
			     range: (of_range_t)range
			     range: (OFRange)range
{
	void *pool = objc_autoreleasePoolPush(), *pool2;
	const of_unichar_t *characters;
	const of_unichar_t *searchCharacters = string.characters;
	const OFUnichar *characters;
	const OFUnichar *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)
		@throw [OFOutOfRangeException exception];

	if (searchLength > range.length) {
		objc_autoreleasePoolPop(pool);
		return;
	}

	pool2 = objc_autoreleasePoolPush();
	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)
		    searchLength * sizeof(OFUnichar)) != 0)
			continue;

		[self replaceCharactersInRange: of_range(i, searchLength)
		[self replaceCharactersInRange: OFMakeRange(i, searchLength)
				    withString: replacement];

		range.length -= searchLength;
		range.length += replacementLength;

		i += replacementLength - 1;

		objc_autoreleasePoolPop(pool2);
		pool2 = objc_autoreleasePoolPush();

		characters = self.characters;
	}

	objc_autoreleasePoolPop(pool);
}

- (void)deleteLeadingWhitespaces
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *characters = self.characters;
	size_t i, length = self.length;

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

		if (!of_ascii_isspace(c))
			break;
	}

	objc_autoreleasePoolPop(pool);

	[self deleteCharactersInRange: of_range(0, i)];
	[self deleteCharactersInRange: OFMakeRange(0, i)];
}

- (void)deleteTrailingWhitespaces
{
	void *pool;
	const of_unichar_t *characters, *p;
	const OFUnichar *characters, *p;
	size_t length, d;

	length = self.length;

	if (length == 0)
		return;

	pool = objc_autoreleasePoolPush();
	characters = self.characters;

	d = 0;
	for (p = characters + length - 1; p >= characters; p--) {
		if (!of_ascii_isspace(*p))
			break;

		d++;
	}

	objc_autoreleasePoolPop(pool);

	[self deleteCharactersInRange: of_range(length - d, d)];
	[self deleteCharactersInRange: OFMakeRange(length - d, d)];
}

- (void)deleteEnclosingWhitespaces
{
	[self deleteLeadingWhitespaces];
	[self deleteTrailingWhitespaces];
}

Modified src/OFMutableTarArchiveEntry.h from [2d44acedbb] to [ec04d24178].

57
58
59
60
61
62
63
64

65
66

67
68
69
70
71
72
73
57
58
59
60
61
62
63

64
65

66
67
68
69
70
71
72
73







-
+

-
+







 * @brief The date of the last modification of the file.
 */
@property (readwrite, retain, nonatomic) OFDate *modificationDate;

/**
 * @brief The type of the archive entry.
 *
 * See @ref of_tar_archive_entry_type_t.
 * See @ref OFTarArchiveEntryType.
 */
@property (readwrite, nonatomic) of_tar_archive_entry_type_t type;
@property (readwrite, nonatomic) OFTarArchiveEntryType type;

/**
 * @brief The file name of the target (for a hard link or symbolic link).
 */
@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic)
    OFString *targetFileName;

Modified src/OFMutableTarArchiveEntry.m from [9a77a0f3e7] to [a864b37365].

62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76







-
+







- (void)setModificationDate: (OFDate *)modificationDate
{
	OFDate *old = _modificationDate;
	_modificationDate = [modificationDate retain];
	[old release];
}

- (void)setType: (of_tar_archive_entry_type_t)type
- (void)setType: (OFTarArchiveEntryType)type
{
	_type = type;
}

- (void)setTargetFileName: (OFString *)targetFileName
{
	OFString *old = _targetFileName;

Modified src/OFMutableURL.m from [66f15c46f8] to [6cfd3507ce].

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







-
+







- (void)setURLEncodedHost: (OFString *)URLEncodedHost
{
	OFString *old;

	if ([URLEncodedHost hasPrefix: @"["] &&
	    [URLEncodedHost hasSuffix: @"]"]) {
		if (!of_url_is_ipv6_host([URLEncodedHost substringWithRange:
		    of_range(1, URLEncodedHost.length - 2)]))
		    OFMakeRange(1, URLEncodedHost.length - 2)]))
			@throw [OFInvalidFormatException exception];
	} else if (URLEncodedHost != nil)
		of_url_verify_escaped(URLEncodedHost,
		    [OFCharacterSet URLHostAllowedCharacterSet]);

	old = _URLEncodedHost;
	_URLEncodedHost = [URLEncodedHost copy];
400
401
402
403
404
405
406
407

408
409
410
411
412
413
414
400
401
402
403
404
405
406

407
408
409
410
411
412
413
414







-
+







				done = false;
				break;
			}

			if ([current isEqual: @".."] && parent != nil &&
			    ![parent isEqual: @".."]) {
				[array removeObjectsInRange:
				    of_range(i - 1, 2)];
				    OFMakeRange(i - 1, 2)];

				done = false;
				break;
			}
		}
	}

Modified src/OFMutableUTF8String.m from [ae60bfdf29] to [bfc8f3ea93].

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







-
-
+
+



-
+







-
+







	if (freeWhenDone)
		free(UTF8String);

	return self;
}

#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 OFUnichar *const [])startTable
		     wordMiddleTable: (const OFUnichar *const [])middleTable
		  wordStartTableSize: (size_t)startTableSize
		 wordMiddleTableSize: (size_t)middleTableSize
{
	of_unichar_t *unicodeString;
	OFUnichar *unicodeString;
	size_t unicodeLen, newCStringLength;
	size_t i, j;
	char *newCString;
	bool isStart = true;

	if (!_s->isUTF8) {
		uint8_t t;
		const of_unichar_t *const *table;
		const OFUnichar *const *table;

		assert(startTableSize >= 1 && middleTableSize >= 1);

		_s->hashed = false;

		for (i = 0; i < _s->cStringLength; i++) {
			if (isStart)
95
96
97
98
99
100
101
102

103
104
105
106
107
108

109
110

111
112
113
114
115
116
117
95
96
97
98
99
100
101

102
103
104
105
106
107

108
109

110
111
112
113
114
115
116
117







-
+





-
+

-
+







				_s->cString[i] = t;
		}

		return;
	}

	unicodeLen = self.length;
	unicodeString = of_alloc(unicodeLen, sizeof(of_unichar_t));
	unicodeString = of_alloc(unicodeLen, sizeof(OFUnichar));

	i = j = 0;
	newCStringLength = 0;

	while (i < _s->cStringLength) {
		const of_unichar_t *const *table;
		const OFUnichar *const *table;
		size_t tableSize;
		of_unichar_t c;
		OFUnichar c;
		ssize_t cLen;

		if (isStart) {
			table = startTable;
			tableSize = middleTableSize;
		} else {
			table = middleTable;
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139
125
126
127
128
129
130
131

132
133
134
135
136
137
138
139







-
+







			free(unicodeString);
			@throw [OFInvalidEncodingException exception];
		}

		isStart = of_ascii_isspace(c);

		if (c >> 8 < tableSize) {
			of_unichar_t tc = table[c >> 8][c & 0xFF];
			OFUnichar tc = table[c >> 8][c & 0xFF];

			if (tc)
				c = tc;
		}
		unicodeString[j++] = c;

		if (c < 0x80)
185
186
187
188
189
190
191
192

193
194
195

196
197
198
199
200
201
202
185
186
187
188
189
190
191

192
193
194

195
196
197
198
199
200
201
202







-
+


-
+







	/*
	 * Even though cStringLength can change, length cannot, therefore no
	 * need to change it.
	 */
}
#endif

- (void)setCharacter: (of_unichar_t)character atIndex: (size_t)idx
- (void)setCharacter: (OFUnichar)character atIndex: (size_t)idx
{
	char buffer[4];
	of_unichar_t c;
	OFUnichar c;
	size_t lenNew;
	ssize_t lenOld;

	if (_s->isUTF8)
		idx = of_string_utf8_get_position(_s->cString, idx,
		    _s->cStringLength);

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







-
+







-
+


-
+







	_s->cStringLength += UTF8StringLength;
	_s->length += length;

	_s->cString[_s->cStringLength] = 0;
}

- (void)appendCString: (const char *)cString
	     encoding: (of_string_encoding_t)encoding
	     encoding: (OFStringEncoding)encoding
{
	[self appendCString: cString
		   encoding: encoding
		     length: strlen(cString)];
}

- (void)appendCString: (const char *)cString
	     encoding: (of_string_encoding_t)encoding
	     encoding: (OFStringEncoding)encoding
	       length: (size_t)cStringLength
{
	if (encoding == OF_STRING_ENCODING_UTF_8)
	if (encoding == OFStringEncodingUTF8)
		[self appendUTF8String: cString length: cStringLength];
	else {
		void *pool = objc_autoreleasePoolPush();

		[self appendString:
		    [OFString stringWithCString: cString
				       encoding: encoding
365
366
367
368
369
370
371
372

373
374
375
376
377
378
379
365
366
367
368
369
370
371

372
373
374
375
376
377
378
379







-
+







	    [string isKindOfClass: [OFMutableUTF8String class]]) {
		if (((OFMutableUTF8String *)string)->_s->isUTF8)
			_s->isUTF8 = true;
	} else
		_s->isUTF8 = true;
}

- (void)appendCharacters: (const of_unichar_t *)characters
- (void)appendCharacters: (const OFUnichar *)characters
		  length: (size_t)length
{
	char *tmp = of_alloc((length * 4) + 1, 1);

	@try {
		size_t j = 0;
		bool isUTF8 = false;
535
536
537
538
539
540
541
542

543
544
545
546
547
548
549
535
536
537
538
539
540
541

542
543
544
545
546
547
548
549







-
+







	    [string isKindOfClass: [OFMutableUTF8String class]]) {
		if (((OFMutableUTF8String *)string)->_s->isUTF8)
			_s->isUTF8 = true;
	} else
		_s->isUTF8 = true;
}

- (void)deleteCharactersInRange: (of_range_t)range
- (void)deleteCharactersInRange: (OFRange)range
{
	size_t start = range.location;
	size_t end = range.location + range.length;

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

564
565
566
567
568
569
570
571

572
573
574
575
576
577
578
564
565
566
567
568
569
570

571
572
573
574
575
576
577
578







-
+







	@try {
		_s->cString = of_realloc(_s->cString, _s->cStringLength + 1, 1);
	} @catch (OFOutOfMemoryException *e) {
		/* We don't really care, as we only made it smaller */
	}
}

- (void)replaceCharactersInRange: (of_range_t)range
- (void)replaceCharactersInRange: (OFRange)range
		      withString: (OFString *)replacement
{
	size_t start = range.location;
	size_t end = range.location + range.length;
	size_t newCStringLength, newLength;

	if (replacement == nil)
628
629
630
631
632
633
634
635

636
637
638
639
640
641
642
628
629
630
631
632
633
634

635
636
637
638
639
640
641
642







-
+







	} else
		_s->isUTF8 = true;
}

- (void)replaceOccurrencesOfString: (OFString *)string
			withString: (OFString *)replacement
			   options: (int)options
			     range: (of_range_t)range
			     range: (OFRange)range
{
	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;

Modified src/OFNumber.h from [4b9e5cee54] to [6fc4bc7a5d].

125
126
127
128
129
130
131
132
133
134
135




136
137
138
139
140
141
142
125
126
127
128
129
130
131




132
133
134
135
136
137
138
139
140
141
142







-
-
-
-
+
+
+
+







@property (readonly, nonatomic) OFString *stringValue;

#ifdef OF_HAVE_UNAVAILABLE
+ (instancetype)valueWithBytes: (const void *)bytes
		      objCType: (const char *)objCType OF_UNAVAILABLE;
+ (instancetype)valueWithPointer: (const void *)pointer OF_UNAVAILABLE;
+ (instancetype)valueWithNonretainedObject: (id)object OF_UNAVAILABLE;
+ (instancetype)valueWithRange: (of_range_t)range OF_UNAVAILABLE;
+ (instancetype)valueWithPoint: (of_point_t)point OF_UNAVAILABLE;
+ (instancetype)valueWithDimension: (of_dimension_t)dimension OF_UNAVAILABLE;
+ (instancetype)valueWithRectangle: (of_rectangle_t)rectangle OF_UNAVAILABLE;
+ (instancetype)valueWithRange: (OFRange)range OF_UNAVAILABLE;
+ (instancetype)valueWithPoint: (OFPoint)point OF_UNAVAILABLE;
+ (instancetype)valueWithSize: (OFSize)size OF_UNAVAILABLE;
+ (instancetype)valueWithRect: (OFRect)rect OF_UNAVAILABLE;
#endif

/**
 * @brief Creates a new OFNumber with the specified `bool`.
 *
 * @param value The `bool` value which the OFNumber should contain
 * @return A new autoreleased OFNumber
358
359
360
361
362
363
364
365

366
367
368
369
370
371
372
373
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372
373







-
+









/**
 * @brief Compares the number to another number.
 *
 * @param number The number to compare the number to
 * @return The result of the comparison
 */
- (of_comparison_result_t)compare: (OFNumber *)number;
- (OFComparisonResult)compare: (OFNumber *)number;
@end

OF_ASSUME_NONNULL_END

#if !defined(NSINTEGER_DEFINED) && !__has_feature(modules)
/* Required for number literals to work */
@compatibility_alias NSNumber OFNumber;
#endif

Modified src/OFNumber.m from [965d322b8e] to [abbcb2ae39].

938
939
940
941
942
943
944
945

946
947
948
949
950
951
952
953
954
955

956
957

958
959

960
961
962
963
964
965

966
967

968
969

970
971
972
973
974
975

976
977

978
979

980
981
982
983
984
985
986
938
939
940
941
942
943
944

945
946
947
948
949
950
951
952
953
954

955
956

957
958

959
960
961
962
963
964

965
966

967
968

969
970
971
972
973
974

975
976

977
978

979
980
981
982
983
984
985
986







-
+









-
+

-
+

-
+





-
+

-
+

-
+





-
+

-
+

-
+








	if (isSigned(self) || isSigned(number))
		return (number.longLongValue == self.longLongValue);

	return (number.unsignedLongLongValue == self.unsignedLongLongValue);
}

- (of_comparison_result_t)compare: (OFNumber *)number
- (OFComparisonResult)compare: (OFNumber *)number
{
	if (![number isKindOfClass: [OFNumber class]])
		@throw [OFInvalidArgumentException exception];

	if (isFloat(self) || isFloat(number)) {
		double double1 = self.doubleValue;
		double double2 = number.doubleValue;

		if (double1 > double2)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		if (double1 < double2)
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;

		return OF_ORDERED_SAME;
		return OFOrderedSame;
	} else if (isSigned(self) || isSigned(number)) {
		long long int1 = self.longLongValue;
		long long int2 = number.longLongValue;

		if (int1 > int2)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		if (int1 < int2)
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;

		return OF_ORDERED_SAME;
		return OFOrderedSame;
	} else {
		unsigned long long uint1 = self.unsignedLongLongValue;
		unsigned long long uint2 = number.unsignedLongLongValue;

		if (uint1 > uint2)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		if (uint1 < uint2)
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;

		return OF_ORDERED_SAME;
		return OFOrderedSame;
	}
}

- (unsigned long)hash
{
	uint32_t hash;

Modified src/OFObject.h from [846f3a0425] to [972f5ad44c].

50
51
52
53
54
55
56
57

58
59

60
61

62
63
64


65
66
67
68
69
70
71
72
73
74
75

76
77
78
79
80
81

82
83

84


85
86






87
88
89

90
91
92
93

94
95
96
97
98
99

100
101
102

103
104
105
106

107
108
109


110
111

112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141

142
143
144
145

146
147
148
149
150
151

152
153
154

155
156
157
158

159
160
161


162
163

164
165
166
167
168
169
170
171
172
173
174
175
176

177
178
179
180
181
182
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
282
283
284


285
286
287
288
289
290
291
50
51
52
53
54
55
56

57
58

59
60

61
62


63
64
65
66
67
68
69
70
71
72
73


74
75
76
77
78
79

80
81

82
83
84
85


86
87
88
89
90
91
92
93

94
95
96
97

98
99
100
101
102
103

104
105
106

107
108
109
110

111
112


113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145

146
147
148
149

150
151
152
153
154
155

156
157
158

159
160
161
162

163
164


165
166
167

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

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

282
283
284

285
286
287
288
289
290
291
292
293
294
295
296
297
298







-
+

-
+

-
+

-
-
+
+









-
-
+





-
+

-
+

+
+
-
-
+
+
+
+
+
+


-
+



-
+





-
+


-
+



-
+

-
-
+
+

-
+












-
+













-
+


-
+



-
+





-
+


-
+



-
+

-
-
+
+

-
+












-
+











-
+

-
+

-
-
+
+

-
+


-
+


-
+

-
-
-
+
+
+

-
-
+
+

-
+

-
+



-
+

-
-
-
+
+
+


-
+

-
+


-
+






-
+



-
+

-
+

-
+

-
+


-
+





-
+

-
-
+
+

-
-
-
+
+
+


-
+





-
-
+
+



-
+

-
+


-
+




+
+







OF_ASSUME_NONNULL_BEGIN

/** @file */

/**
 * @brief A result of a comparison.
 */
typedef enum {
typedef enum OFComparisonResult {
	/** The left object is smaller than the right */
	OF_ORDERED_ASCENDING = -1,
	OFOrderedAscending = -1,
	/** Both objects are equal */
	OF_ORDERED_SAME = 0,
	OFOrderedSame = 0,
	/** The left object is bigger than the right */
	OF_ORDERED_DESCENDING = 1
} of_comparison_result_t;
	OFOrderedDescending = 1
} OFComparisonResult;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief A comparator to compare two objects.
 *
 * @param left The left object
 * @param right The right object
 * @return The order of the objects
 */
typedef of_comparison_result_t (^of_comparator_t)(id _Nonnull left,
    id _Nonnull right);
typedef OFComparisonResult (^OFComparator)(id _Nonnull left, id _Nonnull right);
#endif

/**
 * @brief An enum for storing endianess.
 */
typedef enum {
typedef enum OFByteOrder {
	/** Most significant byte first (big endian) */
	OF_BYTE_ORDER_BIG_ENDIAN,
	OFByteOrderBigEndian,
	/** Least significant byte first (little endian) */
	OFByteOrderLittleEndian,
	/** Native byte order of the system */
	OF_BYTE_ORDER_LITTLE_ENDIAN
} of_byte_order_t;
#ifdef OF_BIG_ENDIAN
	OFByteOrderNative = OFByteOrderBigEndian
#else
	OFByteOrderNative = OFByteOrderLittleEndian
#endif
} OFByteOrder;

/**
 * @struct of_range_t OFObject.h ObjFW/OFObject.h
 * @struct OFRange OFObject.h ObjFW/OFObject.h
 *
 * @brief A range.
 */
struct OF_BOXABLE of_range_t {
struct OF_BOXABLE OFRange {
	/** The start of the range */
	size_t location;
	/** The length of the range */
	size_t length;
};
typedef struct of_range_t of_range_t;
typedef struct OFRange OFRange;

/**
 * @brief Creates a new of_range_t.
 * @brief Creates a new OFRange.
 *
 * @param start The starting index of the range
 * @param length The length of the range
 * @return An of_range with the specified start and length
 * @return An OFRangeith the specified start and length
 */
static OF_INLINE of_range_t OF_CONST_FUNC
of_range(size_t start, size_t length)
static OF_INLINE OFRange OF_CONST_FUNC
OFMakeRange(size_t start, size_t length)
{
	of_range_t range = { start, length };
	OFRange range = { start, length };

	return range;
}

/**
 * @brief Returns whether the two ranges are equal.
 *
 * @param range1 The first range for the comparison
 * @param range2 The second range for the comparison
 * @return Whether the two ranges are equal
 */
static OF_INLINE bool
of_range_equal(of_range_t range1, of_range_t range2)
OFEqualRanges(OFRange range1, OFRange range2)
{
	if (range1.location != range2.location)
		return false;

	if (range1.length != range2.length)
		return false;

	return true;
}

/**
 * @brief A time interval in seconds.
 */
typedef double of_time_interval_t;
typedef double OFTimeInterval;

/**
 * @struct of_point_t OFObject.h ObjFW/OFObject.h
 * @struct OFPoint OFObject.h ObjFW/OFObject.h
 *
 * @brief A point.
 */
struct OF_BOXABLE of_point_t {
struct OF_BOXABLE OFPoint {
	/** The x coordinate of the point */
	float x;
	/** The y coordinate of the point */
	float y;
};
typedef struct of_point_t of_point_t;
typedef struct OFPoint OFPoint;

/**
 * @brief Creates a new of_point_t.
 * @brief Creates a new OFPoint.
 *
 * @param x The x coordinate of the point
 * @param y The x coordinate of the point
 * @return An of_point_t with the specified coordinates
 * @return An OFPoint with the specified coordinates
 */
static OF_INLINE of_point_t OF_CONST_FUNC
of_point(float x, float y)
static OF_INLINE OFPoint OF_CONST_FUNC
OFMakePoint(float x, float y)
{
	of_point_t point = { x, y };
	OFPoint point = { x, y };

	return point;
}

/**
 * @brief Returns whether the two points are equal.
 *
 * @param point1 The first point for the comparison
 * @param point2 The second point for the comparison
 * @return Whether the two points are equal
 */
static OF_INLINE bool
of_point_equal(of_point_t point1, of_point_t point2)
OFEqualPoints(OFPoint point1, OFPoint point2)
{
	if (point1.x != point2.x)
		return false;

	if (point1.y != point2.y)
		return false;

	return true;
}

/**
 * @struct of_dimension_t OFObject.h ObjFW/OFObject.h
 * @struct OFSize OFObject.h ObjFW/OFObject.h
 *
 * @brief A dimension.
 * @brief A size.
 */
struct OF_BOXABLE of_dimension_t {
	/** The width of the dimension */
struct OF_BOXABLE OFSize {
	/** The width of the size */
	float width;
	/** The height of the dimension */
	/** The height of the size */
	float height;
};
typedef struct of_dimension_t of_dimension_t;
typedef struct OFSize OFSize;

/**
 * @brief Creates a new of_dimension_t.
 * @brief Creates a new OFSize.
 *
 * @param width The width of the dimension
 * @param height The height of the dimension
 * @return An of_dimension_t with the specified width and height
 * @param width The width of the size
 * @param height The height of the size
 * @return An OFSize with the specified width and height
 */
static OF_INLINE of_dimension_t OF_CONST_FUNC
of_dimension(float width, float height)
static OF_INLINE OFSize OF_CONST_FUNC
OFMakeSize(float width, float height)
{
	of_dimension_t dimension = { width, height };
	OFSize size = { width, height };

	return dimension;
	return size;
}

/**
 * @brief Returns whether the two dimensions are equal.
 * @brief Returns whether the two sizes are equal.
 *
 * @param dimension1 The first dimension for the comparison
 * @param dimension2 The second dimension for the comparison
 * @return Whether the two dimensions are equal
 * @param size1 The first size for the comparison
 * @param size2 The second size for the comparison
 * @return Whether the two sizes are equal
 */
static OF_INLINE bool
of_dimension_equal(of_dimension_t dimension1, of_dimension_t dimension2)
OFEqualSizes(OFSize size1, OFSize size2)
{
	if (dimension1.width != dimension2.width)
	if (size1.width != size2.width)
		return false;

	if (dimension1.height != dimension2.height)
	if (size1.height != size2.height)
		return false;

	return true;
}

/**
 * @struct of_rectangle_t OFObject.h ObjFW/OFObject.h
 * @struct OFRect OFObject.h ObjFW/OFObject.h
 *
 * @brief A rectangle.
 */
struct OF_BOXABLE of_rectangle_t {
struct OF_BOXABLE OFRect {
	/** The point from where the rectangle originates */
	of_point_t origin;
	OFPoint origin;
	/** The size of the rectangle */
	of_dimension_t size;
	OFSize size;
};
typedef struct of_rectangle_t of_rectangle_t;
typedef struct OFRect OFRect;

/**
 * @brief Creates a new of_rectangle_t.
 * @brief Creates a new OFRect.
 *
 * @param x The x coordinate of the top left corner of the rectangle
 * @param y The y coordinate of the top left corner of the rectangle
 * @param width The width of the rectangle
 * @param height The height of the rectangle
 * @return An of_rectangle_t with the specified origin and size
 * @return An OFRect with the specified origin and size
 */
static OF_INLINE of_rectangle_t OF_CONST_FUNC
of_rectangle(float x, float y, float width, float height)
static OF_INLINE OFRect OF_CONST_FUNC
OFMakeRect(float x, float y, float width, float height)
{
	of_rectangle_t rectangle = {
		of_point(x, y),
		of_dimension(width, height)
	OFRect rect = {
		OFMakePoint(x, y),
		OFMakeSize(width, height)
	};

	return rectangle;
	return rect;
}

/**
 * @brief Returns whether the two rectangles are equal.
 *
 * @param rectangle1 The first rectangle for the comparison
 * @param rectangle2 The second rectangle for the comparison
 * @param rect1 The first rectangle for the comparison
 * @param rect2 The second rectangle for the comparison
 * @return Whether the two rectangles are equal
 */
static OF_INLINE bool
of_rectangle_equal(of_rectangle_t rectangle1, of_rectangle_t rectangle2)
OFEqualRects(OFRect rect1, OFRect rect2)
{
	if (!of_point_equal(rectangle1.origin, rectangle2.origin))
	if (!OFEqualPoints(rect1.origin, rect2.origin))
		return false;

	if (!of_dimension_equal(rectangle1.size, rectangle2.size))
	if (!OFEqualSizes(rect1.size, rect2.size))
		return false;

	return true;
}

static const size_t OFNotFound = SIZE_MAX;

#ifdef __OBJC__
@class OFMethodSignature;
@class OFString;
@class OFThread;

/**
814
815
816
817
818
819
820
821

822
823
824
825
826
827
828
829
830
831
832
833
834

835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850

851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

870
871
872
873
874
875
876
821
822
823
824
825
826
827

828
829
830
831
832
833
834
835
836
837
838
839
840

841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856

857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875

876
877
878
879
880
881
882
883







-
+












-
+















-
+


















-
+








/**
 * @brief Performs the specified selector after the specified delay.
 *
 * @param selector The selector to perform
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector afterDelay: (of_time_interval_t)delay;
- (void)performSelector: (SEL)selector afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector with the specified object after the
 *	  specified delay.
 *
 * @param selector The selector to perform
 * @param object The object that is passed to the method specified by the
 *		 selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	     withObject: (nullable id)object
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector with the specified objects after the
 *	  specified delay.
 *
 * @param selector The selector to perform
 * @param object1 The first object that is passed to the method specified by the
 *		  selector
 * @param object2 The second object that is passed to the method specified by
 *		  the selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	     withObject: (nullable id)object1
	     withObject: (nullable id)object2
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector with the specified objects after the
 *	  specified delay.
 *
 * @param selector The selector to perform
 * @param object1 The first object that is passed to the method specified by the
 *		  selector
 * @param object2 The second object that is passed to the method specified by
 *		  the selector
 * @param object3 The third object that is passed to the method specified by the
 *		  selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	     withObject: (nullable id)object1
	     withObject: (nullable id)object2
	     withObject: (nullable id)object3
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector with the specified objects after the
 *	  specified delay.
 *
 * @param selector The selector to perform
 * @param object1 The first object that is passed to the method specified by the
884
885
886
887
888
889
890
891

892
893
894
895
896
897
898
891
892
893
894
895
896
897

898
899
900
901
902
903
904
905







-
+







 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	     withObject: (nullable id)object1
	     withObject: (nullable id)object2
	     withObject: (nullable id)object3
	     withObject: (nullable id)object4
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

# ifdef OF_HAVE_THREADS
/**
 * @brief Performs the specified selector on the specified thread.
 *
 * @param selector The selector to perform
 * @param thread The thread on which to perform the selector
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
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
1140







-
+














-
+

















-
+




















-
+







 *
 * @param selector The selector to perform
 * @param thread The thread on which to perform the selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector on the specified thread with the
 *	  specified object after the specified delay.
 *
 * @param selector The selector to perform
 * @param thread The thread on which to perform the selector
 * @param object The object that is passed to the method specified by the
 *		 selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (nullable id)object
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector on the specified thread with the
 *	  specified objects after the specified delay.
 *
 * @param selector The selector to perform
 * @param thread The thread on which to perform the selector
 * @param object1 The first object that is passed to the method specified by the
 *		  selector
 * @param object2 The second object that is passed to the method specified by
 *		  the selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (nullable id)object1
	     withObject: (nullable id)object2
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector on the specified thread with the
 *	  specified objects after the specified delay.
 *
 * @param selector The selector to perform
 * @param thread The thread on which to perform the selector
 * @param object1 The first object that is passed to the method specified by the
 *		  selector
 * @param object2 The second object that is passed to the method specified by
 *		  the selector
 * @param object3 The third object that is passed to the method specified by the
 *		  selector
 * @param delay The delay after which the selector will be performed
 */
- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (nullable id)object1
	     withObject: (nullable id)object2
	     withObject: (nullable id)object3
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;

/**
 * @brief Performs the specified selector on the specified thread with the
 *	  specified objects after the specified delay.
 *
 * @param selector The selector to perform
 * @param thread The thread on which to perform the selector
1143
1144
1145
1146
1147
1148
1149
1150

1151
1152
1153
1154
1155
1156
1157
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160
1161
1162
1163
1164







-
+







 */
- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     withObject: (nullable id)object1
	     withObject: (nullable id)object2
	     withObject: (nullable id)object3
	     withObject: (nullable id)object4
	     afterDelay: (of_time_interval_t)delay;
	     afterDelay: (OFTimeInterval)delay;
# endif

/**
 * @brief This method is called when @ref resolveClassMethod: or
 *	  @ref resolveInstanceMethod: returned false. It should return a target
 *	  to which the message should be forwarded.
 *
1223
1224
1225
1226
1227
1228
1229
1230

1231
1232
1233
1234
1235
1236
1237
1230
1231
1232
1233
1234
1235
1236

1237
1238
1239
1240
1241
1242
1243
1244







-
+







@protocol OFComparing
/**
 * @brief Compares the object to another object.
 *
 * @param object An object to compare the object to
 * @return The result of the comparison
 */
- (of_comparison_result_t)compare: (id <OFComparing>)object;
- (OFComparisonResult)compare: (id <OFComparing>)object;
@end
#endif

#ifdef __cplusplus
extern "C" {
#endif
/**

Modified src/OFObject.m from [ab465686e4] to [8df21bda9c].

237
238
239
240
241
242
243
244

245
246
247
248
249
250
251
237
238
239
240
241
242
243

244
245
246
247
248
249
250
251







-
+








#if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__)
static void
uncaughtExceptionHandler(id exception)
{
	OFString *description = [exception description];
	OFArray *backtrace = nil;
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];

	fprintf(stderr, "\nRuntime error: Unhandled exception:\n%s\n",
	    [description cStringWithEncoding: encoding]);

	if ([exception respondsToSelector: @selector(backtrace)])
		backtrace = [exception backtrace];

403
404
405
406
407
408
409
410

411
412
413
414
415
416
417
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417







-
+







{
	return self;
}

+ (OFString *)className
{
	return [OFString stringWithCString: class_getName(self)
				  encoding: OF_STRING_ENCODING_ASCII];
				  encoding: OFStringEncodingASCII];
}

+ (bool)isSubclassOfClass: (Class)class
{
	for (Class iter = self; iter != Nil; iter = class_getSuperclass(iter))
		if (iter == class)
			return true;
558
559
560
561
562
563
564
565

566
567
568
569
570
571
572
558
559
560
561
562
563
564

565
566
567
568
569
570
571
572







-
+







{
	return class_getSuperclass(object_getClass(self));
}

- (OFString *)className
{
	return [OFString stringWithCString: object_getClassName(self)
				  encoding: OF_STRING_ENCODING_ASCII];
				  encoding: OFStringEncodingASCII];
}

- (bool)isKindOfClass: (Class)class
{
	for (Class iter = object_getClass(self); iter != Nil;
	    iter = class_getSuperclass(iter))
		if (iter == class)
661
662
663
664
665
666
667
668

669
670
671
672
673
674
675
676
677
678
679
680
681
682

683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698

699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716

717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736

737
738
739
740
741
742
743
661
662
663
664
665
666
667

668
669
670
671
672
673
674
675
676
677
678
679
680
681

682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697

698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715

716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735

736
737
738
739
740
741
742
743







-
+













-
+















-
+

















-
+



















-
+







	id (*imp)(id, SEL, id, id, id, id) =
	    (id (*)(id, SEL, id, id, id, id))objc_msgSend;
#endif

	return imp(self, selector, object1, object2, object3, object4);
}

- (void)performSelector: (SEL)selector afterDelay: (of_time_interval_t)delay
- (void)performSelector: (SEL)selector afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[OFTimer scheduledTimerWithTimeInterval: delay
					 target: self
				       selector: selector
					repeats: false];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	     withObject: (id)object
	     afterDelay: (of_time_interval_t)delay
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[OFTimer scheduledTimerWithTimeInterval: delay
					 target: self
				       selector: selector
					 object: object
					repeats: false];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	     withObject: (id)object1
	     withObject: (id)object2
	     afterDelay: (of_time_interval_t)delay
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[OFTimer scheduledTimerWithTimeInterval: delay
					 target: self
				       selector: selector
					 object: object1
					 object: object2
					repeats: false];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	     withObject: (id)object1
	     withObject: (id)object2
	     withObject: (id)object3
	     afterDelay: (of_time_interval_t)delay
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[OFTimer scheduledTimerWithTimeInterval: delay
					 target: self
				       selector: selector
					 object: object1
					 object: object2
					 object: object3
					repeats: false];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	     withObject: (id)object1
	     withObject: (id)object2
	     withObject: (id)object3
	     withObject: (id)object4
	     afterDelay: (of_time_interval_t)delay
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[OFTimer scheduledTimerWithTimeInterval: delay
					 target: self
				       selector: selector
					 object: object1
953
954
955
956
957
958
959
960

961
962
963
964
965
966
967
968
969
970
971
972
973
974
975

976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992

993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011

1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032

1033
1034
1035
1036
1037
1038
1039
953
954
955
956
957
958
959

960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991

992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010

1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
1039







-
+














-
+
















-
+


















-
+




















-
+







		[timer waitUntilDone];

	objc_autoreleasePoolPop(pool);
}

- (void)performSelector: (SEL)selector
	       onThread: (OFThread *)thread
	     afterDelay: (of_time_interval_t)delay
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[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
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[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
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[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
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[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
	     afterDelay: (OFTimeInterval)delay
{
	void *pool = objc_autoreleasePoolPush();

	[thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay
							  target: self
							selector: selector
							  object: object1

Modified src/OFOptionsParser.h from [110ad440c1] to [84a06358b9].

17
18
19
20
21
22
23
24

25
26
27
28

29
30

31
32
33
34
35
36
37
17
18
19
20
21
22
23

24
25
26
27

28
29

30
31
32
33
34
35
36
37







-
+



-
+

-
+







#import "OFString.h"

@class OFMapTable;

OF_ASSUME_NONNULL_BEGIN

/**
 * @struct of_options_parser_option_t OFOptionsParser.h ObjFW/OFOptionsParser.h
 * @struct OFOptionsParserOption OFOptionsParser.h ObjFW/OFOptionsParser.h
 *
 * @brief An option which can be parsed by an @ref OFOptionsParser.
 */
struct of_options_parser_option_t {
struct OFOptionsParserOption {
	/** The short version (e.g. `-v`) of the option or `\0` for none. */
	of_unichar_t shortOption;
	OFUnichar shortOption;

	/**
	 * The long version (e.g. `--verbose`) of the option or `nil` for none.
	 */
	OFString *__unsafe_unretained _Nullable longOption;

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







-
+









-
+



-
+












-
+








	/**
	 * An optional pointer to an `OFString *` that is set to the
	 * argument specified for the option or `nil` for no argument.
	 */
	OFString *__autoreleasing _Nullable *_Nullable argumentPtr;
};
typedef struct of_options_parser_option_t of_options_parser_option_t;
typedef struct OFOptionsParserOption OFOptionsParserOption;

/**
 * @class OFOptionsParser OFOptionsParser.h ObjFW/OFOptionsParser.h
 *
 * @brief A class for parsing the program options specified on the command line.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFOptionsParser: OFObject
{
	of_options_parser_option_t *_options;
	OFOptionsParserOption *_options;
	OFMapTable *_longOptions;
	OFArray OF_GENERIC(OFString *) *_arguments;
	size_t _index, _subIndex;
	of_unichar_t _lastOption;
	OFUnichar _lastOption;
	OFString *_Nullable _lastLongOption, *_Nullable _argument;
	bool _done;
}

/**
 * @brief The last parsed option.
 *
 * If @ref nextOption returned `?` or `:`, this returns the option which was
 * unknown or for which the argument was missing.@n
 * If this returns `-`, the last option is only available as a long option (see
 * lastLongOption).
 */
@property (readonly, nonatomic) of_unichar_t lastOption;
@property (readonly, nonatomic) OFUnichar lastOption;

/**
 * @brief The long option for the last parsed option, or `nil` if the last
 *	  parsed option was not passed as a long option by the user.
 *
 * In case @ref nextOption returned `?`, this contains the unknown long
 * option.@n
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
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







-
+





-
+







-
+





-
+




















-
+



 */
@property (readonly, nonatomic)
    OFArray OF_GENERIC(OFString *) *remainingArguments;

/**
 * @brief Creates a new OFOptionsParser which accepts the specified options.
 *
 * @param options An array of @ref of_options_parser_option_t specifying all
 * @param options An array of @ref OFOptionsParserOption specifying all
 *		  accepted options, terminated with an option whose short
 *		  option is `\0` and long option is `nil`.
 *
 * @return A new, autoreleased OFOptionsParser
 */
+ (instancetype)parserWithOptions: (const of_options_parser_option_t *)options;
+ (instancetype)parserWithOptions: (const OFOptionsParserOption *)options;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated OFOptionsParser so that it accepts
 *	  the specified options.
 *
 * @param options An array of @ref of_options_parser_option_t specifying all
 * @param options An array of @ref OFOptionsParserOption specifying all
 *		  accepted options, terminated with an option whose short
 *		  option is `\0` and long option is `nil`.
 *
 * @return An initialized OFOptionsParser
 */
- (instancetype)initWithOptions: (const of_options_parser_option_t *)options
- (instancetype)initWithOptions: (const OFOptionsParserOption *)options
    OF_DESIGNATED_INITIALIZER;

/**
 * @brief Returns the next option.
 *
 * If the option is only available as a long option, `-` is returned.
 * Otherwise, the short option is returned, even if it was specified as a long
 * option.@n
 * If an unknown option is specified, `?` is returned.@n
 * If the argument for the option is missing, `:` is returned.@n
 * If there is an argument for the option even though it takes none, `=` is
 * returned.@n
 * If all options have been parsed, `\0` is returned.
 *
 * @note You need to call @ref nextOption repeatedly until it returns `\0` to
 *	 make sure all options have been parsed, even if you only rely on the
 *	 optional pointers specified and don't do any parsing yourself.
 *
 * @return The next option
 */
- (of_unichar_t)nextOption;
- (OFUnichar)nextOption;
@end

OF_ASSUME_NONNULL_END

Modified src/OFOptionsParser.m from [9cfc874f7b] to [f1ad10653b].

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







-
+









-
+





-
-
+
+







	return [(OFString *)object1 isEqual: (OFString *)object2];
}

@implementation OFOptionsParser
@synthesize lastOption = _lastOption, lastLongOption = _lastLongOption;
@synthesize argument = _argument;

+ (instancetype)parserWithOptions: (const of_options_parser_option_t *)options
+ (instancetype)parserWithOptions: (const OFOptionsParserOption *)options
{
	return [[[self alloc] initWithOptions: options] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithOptions: (const of_options_parser_option_t *)options
- (instancetype)initWithOptions: (const OFOptionsParserOption *)options
{
	self = [super init];

	@try {
		size_t count = 0;
		const of_options_parser_option_t *iter;
		of_options_parser_option_t *iter2;
		const OFOptionsParserOption *iter;
		OFOptionsParserOption *iter2;
		const of_map_table_functions_t keyFunctions = {
			.hash = stringHash,
			.equal = stringEqual
		};
		const of_map_table_functions_t objectFunctions = { NULL };

		/* Count, sanity check, initialize pointers */
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
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







-
+













-
+

-
+








	return self;
}

- (void)dealloc
{
	if (_options != NULL)
		for (of_options_parser_option_t *iter = _options;
		for (OFOptionsParserOption *iter = _options;
		    iter->shortOption != '\0' || iter->longOption != nil;
		    iter++)
			[iter->longOption release];

	free(_options);
	[_longOptions release];

	[_arguments release];
	[_argument release];

	[super dealloc];
}

- (of_unichar_t)nextOption
- (OFUnichar)nextOption
{
	of_options_parser_option_t *iter;
	OFOptionsParserOption *iter;
	OFString *argument;

	if (_done || _index >= _arguments.count)
		return '\0';

	[_lastLongOption release];
	[_argument release];
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
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







-
+





-
+






-
+







			_index++;
			return '\0';
		}

		if ([argument hasPrefix: @"--"]) {
			void *pool = objc_autoreleasePoolPush();
			size_t pos;
			of_options_parser_option_t *option;
			OFOptionsParserOption *option;

			_lastOption = '-';
			_index++;

			if ((pos = [argument rangeOfString: @"="].location) !=
			    OF_NOT_FOUND)
			    OFNotFound)
				_argument = [[argument
				    substringFromIndex: pos + 1] copy];
			else
				pos = argument.length;

			_lastLongOption = [[argument substringWithRange:
			    of_range(2, pos - 2)] copy];
			    OFMakeRange(2, pos - 2)] copy];

			objc_autoreleasePoolPop(pool);

			option = [_longOptions objectForKey: _lastLongOption];
			if (option == NULL)
				return '?';

267
268
269
270
271
272
273
274

275
276
267
268
269
270
271
272
273

274
275
276







-
+



	return '?';
}

- (OFArray *)remainingArguments
{
	return [_arguments objectsInRange:
	    of_range(_index, _arguments.count - _index)];
	    OFMakeRange(_index, _arguments.count - _index)];
}
@end

Modified src/OFPointValue.h from [8f405bc77c] to [4a1e3a3976].

15
16
17
18
19
20
21
22

23
24
25

26
27
28
15
16
17
18
19
20
21

22
23
24

25
26
27
28







-
+


-
+




#import "OFValue.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFPointValue: OFValue
{
	of_point_t _point;
	OFPoint _point;
}

- (instancetype)initWithPoint: (of_point_t)point;
- (instancetype)initWithPoint: (OFPoint)point;
@end

OF_ASSUME_NONNULL_END

Modified src/OFPointValue.m from [637e52428d] to [4e64632cbc].

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







-
+










-
+













-
+


#import "OFString.h"

#import "OFOutOfRangeException.h"

@implementation OFPointValue
@synthesize pointValue = _point;

- (instancetype)initWithPoint: (of_point_t)point
- (instancetype)initWithPoint: (OFPoint)point
{
	self = [super init];

	_point = point;

	return self;
}

- (const char *)objCType
{
	return @encode(of_point_t);
	return @encode(OFPoint);
}

- (void)getValue: (void *)value size: (size_t)size
{
	if (size != sizeof(_point))
		@throw [OFOutOfRangeException exception];

	memcpy(value, &_point, sizeof(_point));
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFValue: of_point_t { %f, %f }>", _point.x, _point.y];
	    @"<OFValue: OFPoint { %f, %f }>", _point.x, _point.y];
}
@end

Modified src/OFPollKernelEventObserver.m from [f68dab1660] to [62bef4adc4].

158
159
160
161
162
163
164
165

166
167
168
169
170
171
172
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172







-
+







- (void)removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	removeObject(self, object, object.fileDescriptorForWriting, POLLOUT);

	[super removeObjectForWriting: object];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
- (void)observeForTimeInterval: (OFTimeInterval)timeInterval
{
	void *pool;
	struct pollfd *FDs;
	int events;
	size_t nFDs;

	if ([self of_processReadBuffers])

Modified src/OFRangeCharacterSet.h from [146f282cd5] to [36adda48b7].

15
16
17
18
19
20
21
22

23
24
25
26
15
16
17
18
19
20
21

22
23
24
25
26







-
+





#import "OFCharacterSet.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFRangeCharacterSet: OFCharacterSet
{
	of_range_t _range;
	OFRange _range;
}
@end

OF_ASSUME_NONNULL_END

Modified src/OFRangeCharacterSet.m from [e174e57848] to [171e0115ac].

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







-
+
















-
+






@implementation OFRangeCharacterSet
- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithRange: (of_range_t)range
- (instancetype)initWithRange: (OFRange)range
{
	self = [super init];

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

		_range = range;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	return (character >= _range.location &&
	    character < _range.location + _range.length);
}
@end

Modified src/OFRangeValue.h from [d625b84e6d] to [364a68b940].

15
16
17
18
19
20
21
22

23
24
25

26
27
28
15
16
17
18
19
20
21

22
23
24

25
26
27
28







-
+


-
+




#import "OFValue.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFRangeValue: OFValue
{
	of_range_t _range;
	OFRange _range;
}

- (instancetype)initWithRange: (of_range_t)range;
- (instancetype)initWithRange: (OFRange)range;
@end

OF_ASSUME_NONNULL_END

Modified src/OFRangeValue.m from [4b2520185b] to [d1e5de9d18].

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







-
+










-
+













-
+



#import "OFString.h"

#import "OFOutOfRangeException.h"

@implementation OFRangeValue
@synthesize rangeValue = _range;

- (instancetype)initWithRange: (of_range_t)range
- (instancetype)initWithRange: (OFRange)range
{
	self = [super init];

	_range = range;

	return self;
}

- (const char *)objCType
{
	return @encode(of_range_t);
	return @encode(OFRange);
}

- (void)getValue: (void *)value size: (size_t)size
{
	if (size != sizeof(_range))
		@throw [OFOutOfRangeException exception];

	memcpy(value, &_range, sizeof(_range));
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFValue: of_range_t { %zu, %zu }>",
	    @"<OFValue: OFRange { %zu, %zu }>",
	    _range.location, _range.length];
}
@end

Added src/OFRectValue.h version [57204033f6].





























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFValue.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFRectValue: OFValue
{
	OFRect _rect;
}

- (instancetype)initWithRect: (OFRect)rect;
@end

OF_ASSUME_NONNULL_END

Added src/OFRectValue.m version [15e6c7cc85].























































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFRectValue.h"
#import "OFMethodSignature.h"
#import "OFString.h"

#import "OFOutOfRangeException.h"

@implementation OFRectValue
@synthesize rectValue = _rect;

- (instancetype)initWithRect: (OFRect)rect
{
	self = [super init];

	_rect = rect;

	return self;
}

- (const char *)objCType
{
	return @encode(OFRect);
}

- (void)getValue: (void *)value size: (size_t)size
{
	if (size != sizeof(_rect))
		@throw [OFOutOfRangeException exception];

	memcpy(value, &_rect, sizeof(_rect));
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFValue: OFRect { %f, %f, %f, %f }>",
	    _rect.origin.x, _rect.origin.y,
	    _rect.size.width, _rect.size.height];
}
@end

Deleted src/OFRectangleValue.h version [6cb58bb467].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28




























-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFValue.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFRectangleValue: OFValue
{
	of_rectangle_t _rectangle;
}

- (instancetype)initWithRectangle: (of_rectangle_t)rectangle;
@end

OF_ASSUME_NONNULL_END

Deleted src/OFRectangleValue.m version [7e7907dbd9].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54






















































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFRectangleValue.h"
#import "OFMethodSignature.h"
#import "OFString.h"

#import "OFOutOfRangeException.h"

@implementation OFRectangleValue
@synthesize rectangleValue = _rectangle;

- (instancetype)initWithRectangle: (of_rectangle_t)rectangle
{
	self = [super init];

	_rectangle = rectangle;

	return self;
}

- (const char *)objCType
{
	return @encode(of_rectangle_t);
}

- (void)getValue: (void *)value size: (size_t)size
{
	if (size != sizeof(_rectangle))
		@throw [OFOutOfRangeException exception];

	memcpy(value, &_rectangle, sizeof(_rectangle));
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFValue: of_rectangle_t { %f, %f, %f, %f }>",
	    _rectangle.origin.x, _rectangle.origin.y,
	    _rectangle.size.width, _rectangle.size.height];
}
@end

Modified src/OFRunLoop+Private.h from [b6fd0f0eaf] to [b73b1c9760].

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







-
+

-
+






-
+

-
+




-
-
+
+

-
+
-
-





-
+

-
+
-





-
-
+
+

-
+
-
-




-
+



-
+





-
+

-
+




-
-
+
+

-
+






-
+

-
+





-
+

-
+


-
+
-

-
+



@interface OFRunLoop ()
+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop;
#ifdef OF_HAVE_SOCKETS
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			    mode: (of_run_loop_mode_t)mode
			    mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			   block: (nullable of_stream_async_read_block_t)block
			   block: (nullable OFStreamAsyncReadBlock)block
# endif
			delegate: (nullable id <OFStreamDelegate>)delegate;
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
		     exactLength: (size_t)length
			    mode: (of_run_loop_mode_t)mode
			    mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			   block: (nullable of_stream_async_read_block_t)block
			   block: (nullable OFStreamAsyncReadBlock)block
# endif
			delegate: (nullable id <OFStreamDelegate>)delegate;
+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
					  stream
			    encoding: (of_string_encoding_t)encoding
				mode: (of_run_loop_mode_t)mode
			    encoding: (OFStringEncoding)encoding
				mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			       block: (nullable
			       block: (nullable OFStreamAsyncReadLineBlock)block
					  of_stream_async_read_line_block_t)
					  block
# endif
			    delegate: (nullable id <OFStreamDelegate>)delegate;
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			     data: (OFData *)data
			     mode: (of_run_loop_mode_t)mode
			     mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			    block: (nullable of_stream_async_write_data_block_t)
			    block: (nullable OFStreamAsyncWriteDataBlock)block
				       block
# endif
			 delegate: (nullable id <OFStreamDelegate>)delegate;
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			   string: (OFString *)string
			 encoding: (of_string_encoding_t)encoding
			     mode: (of_run_loop_mode_t)mode
			 encoding: (OFStringEncoding)encoding
			     mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			    block: (nullable
			    block: (nullable OFStreamAsyncWriteStringBlock)block
				       of_stream_async_write_string_block_t)
				       block
# endif
			 delegate: (nullable id <OFStreamDelegate>)delegate;
# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
+ (void)of_addAsyncConnectForSocket: (id)socket
			       mode: (of_run_loop_mode_t)mode
			       mode: (OFRunLoopMode)mode
			   delegate: (id <OFRunLoopConnectDelegate>)delegate;
# endif
+ (void)of_addAsyncAcceptForSocket: (id)socket
			      mode: (of_run_loop_mode_t)mode
			      mode: (OFRunLoopMode)mode
			     block: (nullable id)block
			  delegate: (nullable id)delegate;
+ (void)of_addAsyncReceiveForDatagramSocket: (OFDatagramSocket *)socket
    buffer: (void *)buffer
    length: (size_t)length
      mode: (of_run_loop_mode_t)mode
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (nullable of_datagram_socket_async_receive_block_t)block
     block: (nullable OFDatagramSocketAsyncReceiveBlock)block
# endif
  delegate: (nullable id <OFDatagramSocketDelegate>) delegate;
+ (void)of_addAsyncSendForDatagramSocket: (OFDatagramSocket *)socket
      data: (OFData *)data
  receiver: (const of_socket_address_t *)receiver
      mode: (of_run_loop_mode_t)mode
  receiver: (const OFSocketAddress *)receiver
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (nullable of_datagram_socket_async_send_data_block_t)block
     block: (nullable OFDatagramSocketAsyncSendDataBlock)block
# endif
  delegate: (nullable id <OFDatagramSocketDelegate>)delegate;
+ (void)of_addAsyncReceiveForSequencedPacketSocket:
					       (OFSequencedPacketSocket *)socket
    buffer: (void *)buffer
    length: (size_t)length
      mode: (of_run_loop_mode_t)mode
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (nullable of_sequenced_packet_socket_async_receive_block_t)block
     block: (nullable OFSequencedPacketSocketAsyncReceiveBlock)block
# endif
  delegate: (nullable id <OFSequencedPacketSocketDelegate>) delegate;
+ (void)of_addAsyncSendForSequencedPacketSocket:
					       (OFSequencedPacketSocket *)socket
      data: (OFData *)data
      mode: (of_run_loop_mode_t)mode
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (nullable of_sequenced_packet_socket_async_send_data_block_t)block
     block: (nullable OFSequencedPacketSocketAsyncSendDataBlock)block
# endif
  delegate: (nullable id <OFSequencedPacketSocketDelegate>)delegate;
+ (void)of_cancelAsyncRequestsForObject: (id)object
+ (void)of_cancelAsyncRequestsForObject: (id)object mode: (OFRunLoopMode)mode;
				   mode: (of_run_loop_mode_t)mode;
#endif
- (void)of_removeTimer: (OFTimer *)timer forMode: (of_run_loop_mode_t)mode;
- (void)of_removeTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode;
@end

OF_ASSUME_NONNULL_END

Modified src/OFRunLoop.h from [3ab2b642cc] to [7f5e7accfd].

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







-
+







-
+
















-
+







-
+
-







@class OFMutableDictionary OF_GENERIC(KeyType, ObjectType);
@class OFTimer;
@class OFDate;

/**
 * @brief A mode for an OFRunLoop.
 */
typedef OFConstantString *of_run_loop_mode_t;
typedef OFConstantString *OFRunLoopMode;

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief The default mode for an OFRunLoop.
 */
extern const of_run_loop_mode_t of_run_loop_mode_default;
extern const OFRunLoopMode OFDefaultRunLoopMode;
#ifdef __cplusplus
}
#endif

/**
 * @class OFRunLoop OFRunLoop.h ObjFW/OFRunLoop.h
 *
 * @brief A class providing a run loop for the application and its processes.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFRunLoop: OFObject
{
	OFMutableDictionary *_states;
#ifdef OF_HAVE_THREADS
	OFMutex *_statesMutex;
#endif
	of_run_loop_mode_t _Nullable _currentMode;
	OFRunLoopMode _Nullable _currentMode;
	volatile bool _stop;
}

#ifdef OF_HAVE_CLASS_PROPERTIES
@property (class, readonly, nullable, nonatomic) OFRunLoop *mainRunLoop;
@property (class, readonly, nullable, nonatomic) OFRunLoop *currentRunLoop;
#endif
@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFRunLoopMode currentMode;
    of_run_loop_mode_t currentMode;

/**
 * @brief Returns the run loop for the main thread.
 *
 * @return The run loop for the main thread
 */
+ (nullable OFRunLoop *)mainRunLoop;
98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
97
98
99
100
101
102
103

104
105
106
107
108
109
110
111







-
+








/**
 * @brief Adds an OFTimer to the run loop for the specified mode.
 *
 * @param timer The timer to add
 * @param mode The run loop mode in which to run the timer
 */
- (void)addTimer: (OFTimer *)timer forMode: (of_run_loop_mode_t)mode;
- (void)addTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode;

#ifdef OF_AMIGAOS
/**
 * @brief Adds an Exec Signal to the run loop.
 *
 * If a signal is added multiple times, the specified methods will be performed
 * in the order added.
133
134
135
136
137
138
139
140

141
142
143
144
145
146
147
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146







-
+







 * @param mode The run loop mode in which to handle the signal
 * @param target The target to call when the signal was received
 * @param selector The selector to call on the target when the signal was
 *		   received. The selector must have one parameter for the ULONG
 *		   of the signal that was received.
 */
- (void)addExecSignal: (ULONG)signal
	      forMode: (of_run_loop_mode_t)mode
	      forMode: (OFRunLoopMode)mode
	       target: (id)target
	     selector: (SEL)selector;

/**
 * @brief Removes the specified Exec Signal with the specified target and
 *	  selector.
 *
159
160
161
162
163
164
165
166

167
168
169
170
171
172
173
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172







-
+







 *
 * @param signal The signal to remove
 * @param mode The run loop mode to which the signal was added
 * @param target The target which was specified when adding the signal
 * @param selector The selector which was specified when adding the signal
 */
- (void)removeExecSignal: (ULONG)signal
		 forMode: (of_run_loop_mode_t)mode
		 forMode: (OFRunLoopMode)mode
		  target: (id)target
		selector: (SEL)selector;
#endif

/**
 * @brief Starts the run loop.
 */
183
184
185
186
187
188
189
190
191

192
193
194
195
196
197
198
199
200
182
183
184
185
186
187
188


189
190
191
192
193
194
195
196
197
198







-
-
+









/**
 * @brief Run the run loop until an event or timer occurs or the specified
 *	  deadline is reached.
 *
 * @param mode The mode in which to run the run loop
 * @param deadline The date until which the run loop should run at the longest
 */
- (void)runMode: (of_run_loop_mode_t)mode
     beforeDate: (nullable OFDate *)deadline;
- (void)runMode: (OFRunLoopMode)mode beforeDate: (nullable OFDate *)deadline;

/**
 * @brief Stops the run loop. If there is still an operation being executed, it
 *	  is finished before the run loop stops.
 */
- (void)stop;
@end

OF_ASSUME_NONNULL_END

Modified src/OFRunLoop.m from [7f4271f15a] to [4440700fb9].

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







-
+







#import "OFSortedList.h"
#import "OFTimer.h"
#import "OFTimer+Private.h"
#import "OFDate.h"

#import "OFObserveFailedException.h"

const of_run_loop_mode_t of_run_loop_mode_default = @"of_run_loop_mode_default";
const OFRunLoopMode OFDefaultRunLoopMode = @"OFDefaultRunLoopMode";
static OFRunLoop *mainRunLoop = nil;

@interface OFRunLoopState: OFObject
#ifdef OF_HAVE_SOCKETS
    <OFKernelEventObserverDelegate>
#endif
{
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
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







-
+










-
+










-
+

-
+







-
+










-
+


-
+







- (bool)handleObject: (id)object;
@end

@interface OFRunLoopReadQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_stream_async_read_block_t _block;
	OFStreamAsyncReadBlock _block;
# endif
	void *_buffer;
	size_t _length;
}
@end

@interface OFRunLoopExactReadQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_stream_async_read_block_t _block;
	OFStreamAsyncReadBlock _block;
# endif
	void *_buffer;
	size_t _exactLength, _readLength;
}
@end

@interface OFRunLoopReadLineQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_stream_async_read_line_block_t _block;
	OFStreamAsyncReadLineBlock _block;
# endif
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
}
@end

@interface OFRunLoopWriteDataQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_stream_async_write_data_block_t _block;
	OFStreamAsyncWriteDataBlock _block;
# endif
	OFData *_data;
	size_t _writtenLength;
}
@end

@interface OFRunLoopWriteStringQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_stream_async_write_string_block_t _block;
	OFStreamAsyncWriteStringBlock _block;
# endif
	OFString *_string;
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
	size_t _writtenLength;
}
@end

# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
@interface OFRunLoopConnectQueueItem: OFRunLoopQueueItem
@end
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
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







-
+










-
+


-
+







-
+










-
+







}
@end

@interface OFRunLoopDatagramReceiveQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_datagram_socket_async_receive_block_t _block;
	OFDatagramSocketAsyncReceiveBlock _block;
# endif
	void *_buffer;
	size_t _length;
}
@end

@interface OFRunLoopDatagramSendQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_datagram_socket_async_send_data_block_t _block;
	OFDatagramSocketAsyncSendDataBlock _block;
# endif
	OFData *_data;
	of_socket_address_t _receiver;
	OFSocketAddress _receiver;
}
@end

@interface OFRunLoopPacketReceiveQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_sequenced_packet_socket_async_receive_block_t _block;
	OFSequencedPacketSocketAsyncReceiveBlock _block;
# endif
	void *_buffer;
	size_t _length;
}
@end

@interface OFRunLoopPacketSendQueueItem: OFRunLoopQueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_sequenced_packet_socket_async_send_data_block_t _block;
	OFSequencedPacketSocketAsyncSendDataBlock _block;
# endif
	OFData *_data;
}
@end
#endif

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







-
+






-
+






-
+

-
+







	OFList OF_GENERIC(OF_KINDOF(OFRunLoopReadQueueItem *)) *queue =
	    [[_readQueues objectForKey: object] retain];

	assert(queue != nil);

	@try {
		if (![queue.firstObject handleObject: object]) {
			of_list_object_t *listObject = queue.firstListObject;
			OFListItem *listItem = queue.firstListItem;

			/*
			 * The handler might have called -[cancelAsyncRequests]
			 * so that our queue is now empty, in which case we
			 * should do nothing.
			 */
			if (listObject != NULL) {
			if (listItem != 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];
				[[listItem->object retain] autorelease];

				[queue removeListObject: listObject];
				[queue removeListItem: listItem];

				if (queue.count == 0) {
					[_kernelEventObserver
					    removeObjectForReading: object];
					[_readQueues
					    removeObjectForKey: object];
				}
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
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







-
+






-
+






-
+

-
+







	 */
	OFList *queue = [[_writeQueues objectForKey: object] retain];

	assert(queue != nil);

	@try {
		if (![queue.firstObject handleObject: object]) {
			of_list_object_t *listObject = queue.firstListObject;
			OFListItem *listItem = queue.firstListItem;

			/*
			 * The handler might have called -[cancelAsyncRequests]
			 * so that our queue is now empty, in which case we
			 * should do nothing.
			 */
			if (listObject != NULL) {
			if (listItem != 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];
				[[listItem->object retain] autorelease];

				[queue removeListObject: listObject];
				[queue removeListItem: listItem];

				if (queue.count == 0) {
					[_kernelEventObserver
					    removeObjectForWriting: object];
					[_writeQueues
					    removeObjectForKey: object];
				}
750
751
752
753
754
755
756
757
758


759
760
761

762
763
764
765
766
767
768
769
750
751
752
753
754
755
756


757
758
759
760

761

762
763
764
765
766
767
768







-
-
+
+


-
+
-







		acceptedSocket = nil;
		exception = e;
	}

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL) {
		if ([object isKindOfClass: [OFStreamSocket class]])
			return ((of_stream_socket_async_accept_block_t)
			    _block)(acceptedSocket, exception);
			return ((OFStreamSocketAsyncAcceptBlock)_block)(
			    acceptedSocket, exception);
		else if ([object isKindOfClass:
		    [OFSequencedPacketSocket class]])
			return
			return ((OFSequencedPacketSocketAsyncAcceptBlock)
			    ((of_sequenced_packet_socket_async_accept_block_t)
			    _block)(acceptedSocket, exception);
		else
			OF_ENSURE(0);
	} else {
# endif
		if (![_delegate respondsToSelector:
		    @selector(socket:didAcceptSocket:exception:)])
787
788
789
790
791
792
793
794

795
796
797
798
799
800
801
786
787
788
789
790
791
792

793
794
795
796
797
798
799
800







-
+







# endif
@end

@implementation OFRunLoopDatagramReceiveQueueItem
- (bool)handleObject: (id)object
{
	size_t length;
	of_socket_address_t address;
	OFSocketAddress address;
	id exception = nil;

	@try {
		length = [object receiveIntoBuffer: _buffer
					    length: _length
					    sender: &address];
	} @catch (id e) {
1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
1012
1013
1014
1015
1016
1017
1018

1019
1020
1021
1022
1023
1024
1025
1026







-
+








+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop
{
	mainRunLoop = [runLoop retain];
}

static OFRunLoopState *
stateForMode(OFRunLoop *self, of_run_loop_mode_t mode, bool create)
stateForMode(OFRunLoop *self, OFRunLoopMode mode, bool create)
{
	OFRunLoopState *state;

#ifdef OF_HAVE_THREADS
	[self->_statesMutex lock];
	@try {
#endif
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
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
1220
1221
1222
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
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267

1268
1269

1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287

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
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
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
1220
1221
1222

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
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265

1266
1267

1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285

1286
1287

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







-
+

-
+



















-
+

-
+

















-
-
+
+

-
+

















-
+

-
+

















-
-
+
+

-
+

















-
+











-
+
















-
+

-
+

















-
-
+
+

-
+



















-
+

-
+

















-
+

-
+

















-
+
-







									\
	objc_autoreleasePoolPop(pool);

+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			    mode: (of_run_loop_mode_t)mode
			    mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			   block: (of_stream_async_read_block_t)block
			   block: (OFStreamAsyncReadBlock)block
# endif
			delegate: (id <OFStreamDelegate>)delegate
{
	NEW_READ(OFRunLoopReadQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_buffer = buffer;
	queueItem->_length = length;

	QUEUE_ITEM
}

+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
		     exactLength: (size_t)exactLength
			    mode: (of_run_loop_mode_t)mode
			    mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			   block: (of_stream_async_read_block_t)block
			   block: (OFStreamAsyncReadBlock)block
# endif
			delegate: (id <OFStreamDelegate>)delegate
{
	NEW_READ(OFRunLoopExactReadQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_buffer = buffer;
	queueItem->_exactLength = exactLength;

	QUEUE_ITEM
}

+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
					  stream
			    encoding: (of_string_encoding_t)encoding
				mode: (of_run_loop_mode_t)mode
			    encoding: (OFStringEncoding)encoding
				mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			       block: (of_stream_async_read_line_block_t)block
			       block: (OFStreamAsyncReadLineBlock)block
# endif
			    delegate: (id <OFStreamDelegate>)delegate
{
	NEW_READ(OFRunLoopReadLineQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_encoding = encoding;

	QUEUE_ITEM
}

+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			     data: (OFData *)data
			     mode: (of_run_loop_mode_t)mode
			     mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			    block: (of_stream_async_write_data_block_t)block
			    block: (OFStreamAsyncWriteDataBlock)block
# endif
			 delegate: (id <OFStreamDelegate>)delegate
{
	NEW_WRITE(OFRunLoopWriteDataQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_data = [data copy];

	QUEUE_ITEM
}

+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
				       stream
			   string: (OFString *)string
			 encoding: (of_string_encoding_t)encoding
			     mode: (of_run_loop_mode_t)mode
			 encoding: (OFStringEncoding)encoding
			     mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
			    block: (of_stream_async_write_string_block_t)block
			    block: (OFStreamAsyncWriteStringBlock)block
# endif
			 delegate: (id <OFStreamDelegate>)delegate
{
	NEW_WRITE(OFRunLoopWriteStringQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_string = [string copy];
	queueItem->_encoding = encoding;

	QUEUE_ITEM
}

# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
+ (void)of_addAsyncConnectForSocket: (id)sock
			       mode: (of_run_loop_mode_t)mode
			       mode: (OFRunLoopMode)mode
			   delegate: (id <OFRunLoopConnectDelegate>)delegate
{
	NEW_WRITE(OFRunLoopConnectQueueItem, sock, mode)

	queueItem->_delegate = [delegate retain];

	QUEUE_ITEM
}
# endif

+ (void)of_addAsyncAcceptForSocket: (id)sock
			      mode: (of_run_loop_mode_t)mode
			      mode: (OFRunLoopMode)mode
			     block: (id)block
			  delegate: (id)delegate
{
	NEW_READ(OFRunLoopAcceptQueueItem, sock, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif

	QUEUE_ITEM
}

+ (void)of_addAsyncReceiveForDatagramSocket: (OFDatagramSocket *)sock
    buffer: (void *)buffer
    length: (size_t)length
      mode: (of_run_loop_mode_t)mode
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (of_datagram_socket_async_receive_block_t)block
     block: (OFDatagramSocketAsyncReceiveBlock)block
# endif
  delegate: (id <OFDatagramSocketDelegate>)delegate
{
	NEW_READ(OFRunLoopDatagramReceiveQueueItem, sock, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_buffer = buffer;
	queueItem->_length = length;

	QUEUE_ITEM
}

+ (void)of_addAsyncSendForDatagramSocket: (OFDatagramSocket *)sock
      data: (OFData *)data
  receiver: (const of_socket_address_t *)receiver
      mode: (of_run_loop_mode_t)mode
  receiver: (const OFSocketAddress *)receiver
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (of_datagram_socket_async_send_data_block_t)block
     block: (OFDatagramSocketAsyncSendDataBlock)block
# endif
  delegate: (id <OFDatagramSocketDelegate>)delegate
{
	NEW_WRITE(OFRunLoopDatagramSendQueueItem, sock, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_data = [data copy];
	queueItem->_receiver = *receiver;

	QUEUE_ITEM
}

+ (void)of_addAsyncReceiveForSequencedPacketSocket: (OFSequencedPacketSocket *)
							sock
    buffer: (void *)buffer
    length: (size_t)length
      mode: (of_run_loop_mode_t)mode
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (of_sequenced_packet_socket_async_receive_block_t)block
     block: (OFSequencedPacketSocketAsyncReceiveBlock)block
# endif
  delegate: (id <OFSequencedPacketSocketDelegate>)delegate
{
	NEW_READ(OFRunLoopPacketReceiveQueueItem, sock, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_buffer = buffer;
	queueItem->_length = length;

	QUEUE_ITEM
}

+ (void)of_addAsyncSendForSequencedPacketSocket: (OFSequencedPacketSocket *)sock
      data: (OFData *)data
      mode: (of_run_loop_mode_t)mode
      mode: (OFRunLoopMode)mode
# ifdef OF_HAVE_BLOCKS
     block: (of_sequenced_packet_socket_async_send_data_block_t)block
     block: (OFSequencedPacketSocketAsyncSendDataBlock)block
# endif
  delegate: (id <OFSequencedPacketSocketDelegate>)delegate
{
	NEW_WRITE(OFRunLoopPacketSendQueueItem, sock, mode)

	queueItem->_delegate = [delegate retain];
# ifdef OF_HAVE_BLOCKS
	queueItem->_block = [block copy];
# endif
	queueItem->_data = [data copy];

	QUEUE_ITEM
}
# undef NEW_READ
# undef NEW_WRITE
# undef QUEUE_ITEM

+ (void)of_cancelAsyncRequestsForObject: (id)object
+ (void)of_cancelAsyncRequestsForObject: (id)object mode: (OFRunLoopMode)mode
				   mode: (of_run_loop_mode_t)mode
{
	void *pool = objc_autoreleasePoolPush();
	OFRunLoop *runLoop = [self currentRunLoop];
	OFRunLoopState *state = stateForMode(runLoop, mode, false);
	OFList *queue;

	if (state == nil)
1352
1353
1354
1355
1356
1357
1358
1359

1360
1361
1362
1363
1364
1365
1366
1367
1350
1351
1352
1353
1354
1355
1356

1357

1358
1359
1360
1361
1362
1363
1364







-
+
-







	@try {
		OFRunLoopState *state;

		_states = [[OFMutableDictionary alloc] init];

		state = [[OFRunLoopState alloc] init];
		@try {
			[_states setObject: state
			[_states setObject: state forKey: OFDefaultRunLoopMode];
				    forKey: of_run_loop_mode_default];
		} @finally {
			[state release];
		}

#ifdef OF_HAVE_THREADS
		_statesMutex = [[OFMutex alloc] init];
#endif
1381
1382
1383
1384
1385
1386
1387
1388

1389
1390
1391

1392
1393
1394
1395
1396
1397
1398
1378
1379
1380
1381
1382
1383
1384

1385
1386
1387

1388
1389
1390
1391
1392
1393
1394
1395







-
+


-
+







#endif

	[super dealloc];
}

- (void)addTimer: (OFTimer *)timer
{
	[self addTimer: timer forMode: of_run_loop_mode_default];
	[self addTimer: timer forMode: OFDefaultRunLoopMode];
}

- (void)addTimer: (OFTimer *)timer forMode: (of_run_loop_mode_t)mode
- (void)addTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode
{
	OFRunLoopState *state = stateForMode(self, mode, true);

#ifdef OF_HAVE_THREADS
	[state->_timersQueueMutex lock];
	@try {
#endif
1408
1409
1410
1411
1412
1413
1414
1415

1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429


1430
1431

1432
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
1405
1406
1407
1408
1409
1410
1411

1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422




1423
1424
1425

1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440

1441
1442
1443
1444
1445
1446

1447
1448
1449
1450
1451
1452
1453
1454







-
+










-
-
-
-
+
+

-
+














-
+





-
+







#if defined(OF_HAVE_SOCKETS)
	[state->_kernelEventObserver cancel];
#elif defined(OF_HAVE_THREADS)
	[state->_condition signal];
#endif
}

- (void)of_removeTimer: (OFTimer *)timer forMode: (of_run_loop_mode_t)mode
- (void)of_removeTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode
{
	OFRunLoopState *state = stateForMode(self, mode, false);

	if (state == nil)
		return;

#ifdef OF_HAVE_THREADS
	[state->_timersQueueMutex lock];
	@try {
#endif
		of_list_object_t *iter;

		for (iter = state->_timersQueue.firstListObject; iter != NULL;
		    iter = iter->next) {
		for (OFListItem *iter = state->_timersQueue.firstListItem;
		    iter != NULL; iter = iter->next) {
			if ([iter->object isEqual: timer]) {
				[state->_timersQueue removeListObject: iter];
				[state->_timersQueue removeListItem: iter];
				break;
			}
		}
#ifdef OF_HAVE_THREADS
	} @finally {
		[state->_timersQueueMutex unlock];
	}
#endif
}

#ifdef OF_AMIGAOS
- (void)addExecSignal: (ULONG)signal target: (id)target selector: (SEL)selector
{
	[self addExecSignal: signal
		    forMode: of_run_loop_mode_default
		    forMode: OFDefaultRunLoopMode
		     target: target
		   selector: selector];
}

- (void)addExecSignal: (ULONG)signal
	      forMode: (of_run_loop_mode_t)mode
	      forMode: (OFRunLoopMode)mode
	       target: (id)target
	     selector: (SEL)selector
{
	OFRunLoopState *state = stateForMode(self, mode, true);

# ifdef OF_HAVE_THREADS
	[state->_execSignalsMutex lock];
1482
1483
1484
1485
1486
1487
1488
1489

1490
1491
1492
1493
1494
1495

1496
1497
1498
1499
1500
1501
1502
1477
1478
1479
1480
1481
1482
1483

1484
1485
1486
1487
1488
1489

1490
1491
1492
1493
1494
1495
1496
1497







-
+





-
+







}

- (void)removeExecSignal: (ULONG)signal
		  target: (id)target
		selector: (SEL)selector
{
	[self removeExecSignal: signal
		       forMode: of_run_loop_mode_default
		       forMode: OFDefaultRunLoopMode
			target: target
		      selector: selector];
}

- (void)removeExecSignal: (ULONG)signal
		 forMode: (of_run_loop_mode_t)mode
		 forMode: (OFRunLoopMode)mode
		  target: (id)target
		selector: (SEL)selector
{
	OFRunLoopState *state = stateForMode(self, mode, false);

	if (state == nil)
		return;
1552
1553
1554
1555
1556
1557
1558
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
1547
1548
1549
1550
1551
1552
1553

1554
1555
1556

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







-
+


-
+


-
+



















-
-
+
+

-
+

-
+



-
+








- (void)runUntilDate: (OFDate *)deadline
{
	_stop = false;

	while (!_stop &&
	    (deadline == nil || deadline.timeIntervalSinceNow >= 0))
		[self runMode: of_run_loop_mode_default beforeDate: deadline];
		[self runMode: OFDefaultRunLoopMode beforeDate: deadline];
}

- (void)runMode: (of_run_loop_mode_t)mode beforeDate: (OFDate *)deadline
- (void)runMode: (OFRunLoopMode)mode beforeDate: (OFDate *)deadline
{
	void *pool = objc_autoreleasePoolPush();
	of_run_loop_mode_t previousMode = _currentMode;
	OFRunLoopMode previousMode = _currentMode;
	OFRunLoopState *state = stateForMode(self, mode, false);

	if (state == nil)
		return;

	_currentMode = mode;
	@try {
		OFDate *nextTimer;
#if defined(OF_AMIGAOS) && !defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS)
		ULONG signalMask;
#endif

		for (;;) {
			OFTimer *timer;

#ifdef OF_HAVE_THREADS
			[state->_timersQueueMutex lock];
			@try {
#endif
				of_list_object_t *listObject =
				    state->_timersQueue.firstListObject;
				OFListItem *listItem =
				    state->_timersQueue.firstListItem;

				if (listObject != NULL && [listObject->object
				if (listItem != NULL && [listItem->object
				    fireDate].timeIntervalSinceNow <= 0) {
					timer = [[listObject->object
					timer = [[listItem->object
					    retain] autorelease];

					[state->_timersQueue
					    removeListObject: listObject];
					    removeListItem: listItem];

					[timer of_setInRunLoop: nil mode: nil];
				} else
					break;
#ifdef OF_HAVE_THREADS
			} @finally {
				[state->_timersQueueMutex unlock];
1618
1619
1620
1621
1622
1623
1624
1625

1626
1627
1628
1629
1630
1631
1632
1613
1614
1615
1616
1617
1618
1619

1620
1621
1622
1623
1624
1625
1626
1627







-
+







		} @finally {
			[state->_timersQueueMutex unlock];
		}
#endif

		/* Watch for I/O events until the next timer is due */
		if (nextTimer != nil || deadline != nil) {
			of_time_interval_t timeout;
			OFTimeInterval timeout;

			if (nextTimer != nil && deadline == nil)
				timeout = nextTimer.timeIntervalSinceNow;
			else if (nextTimer == nil && deadline != nil)
				timeout = deadline.timeIntervalSinceNow;
			else
				timeout = [nextTimer earlierDate: deadline]
1692
1693
1694
1695
1696
1697
1698
1699

1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1687
1688
1689
1690
1691
1692
1693

1694

1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707







-
+
-













	} @finally {
		_currentMode = previousMode;
	}
}

- (void)stop
{
	OFRunLoopState *state =
	OFRunLoopState *state = stateForMode(self, OFDefaultRunLoopMode, false);
	    stateForMode(self, of_run_loop_mode_default, false);

	_stop = true;

	if (state == nil)
		return;

#if defined(OF_HAVE_SOCKETS)
	[state->_kernelEventObserver cancel];
#elif defined(OF_HAVE_THREADS)
	[state->_condition signal];
#endif
}
@end

Modified src/OFSPXSocket.h from [20d64f5e49] to [26e1e49cc2].

26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40







-
+







#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block which is called when the socket connected.
 *
 * @param exception An exception which occurred while connecting the socket or
 *		    `nil` on success
 */
typedef void (^of_spx_socket_async_connect_block_t)(id _Nullable exception);
typedef void (^OFSPXSocketAsyncConnectBlock)(id _Nullable exception);
#endif

/**
 * @protocol OFSPXSocketDelegate OFSPXSocket.h ObjFW/OFSPXSocket.h
 *
 * A delegate for OFSPXSocket.
 */
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
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







-
+














-
+














-
-
+
+









-
+



 * @param port The port (sometimes also called socket number) on the node to
 *	       connect to
 * @param runLoopMode The run loop mode in which to perform the async connect
 */
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode;
	       runLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously connect the OFSPXSocket to the specified destination.
 *
 * @param node The node to connect to
 * @param network The network on which the node to connect to is
 * @param port The port (sometimes also called socket number) on the node to
 *	       connect to
 * @param block The block to execute once the connection has been established
 */
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
		     block: (of_spx_socket_async_connect_block_t)block;
		     block: (OFSPXSocketAsyncConnectBlock)block;

/**
 * @brief Asynchronously connect the OFSPXSocket to the specified destination.
 *
 * @param node The node to connect to
 * @param network The network on which the node to connect to is
 * @param port The port (sometimes also called socket number) on the node to
 *	       connect to
 * @param runLoopMode The run loop mode in which to perform the async connect
 * @param block The block to execute once the connection has been established
 */
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
		     block: (of_spx_socket_async_connect_block_t)block;
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (OFSPXSocketAsyncConnectBlock)block;
#endif

/**
 * @brief Bind the socket to the specified network, node and port.
 *
 * @param port The port (sometimes called socket number) to bind to. 0 means to
 *	       pick one and return it.
 * @return The address on which this socket can be reached
 */
- (of_socket_address_t)bindToPort: (uint16_t)port;
- (OFSocketAddress)bindToPort: (uint16_t)port;
@end

OF_ASSUME_NONNULL_END

Modified src/OFSPXSocket.m from [852f3cc78c] to [823860587e].

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







-
+

-
+












-
+








-
+


-
+








-
+







#ifndef NSPROTO_SPX
# define NSPROTO_SPX 0
#endif

#define SPX_PACKET_TYPE 5

@interface OFSPXSocket ()
- (int)of_createSocketForAddress: (const of_socket_address_t *)address
- (int)of_createSocketForAddress: (const OFSocketAddress *)address
			   errNo: (int *)errNo;
- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address
- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo;
- (void)of_closeSocket;
@end

OF_DIRECT_MEMBERS
@interface OFSPXSocketAsyncConnectDelegate: OFObject <OFRunLoopConnectDelegate>
{
	OFSPXSocket *_socket;
	unsigned char _node[IPX_NODE_LEN];
	uint32_t _network;
	uint16_t _port;
#ifdef OF_HAVE_BLOCKS
	of_spx_socket_async_connect_block_t _block;
	OFSPXSocketAsyncConnectBlock _block;
#endif
}

- (instancetype)initWithSocket: (OFSPXSocket *)socket
			  node: (unsigned char [IPX_NODE_LEN])node
		       network: (uint32_t)network
			  port: (uint16_t)port
#ifdef OF_HAVE_BLOCKS
			 block: (of_spx_socket_async_connect_block_t)block
			 block: (OFSPXSocketAsyncConnectBlock)block
#endif
;
- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode;
@end

@implementation OFSPXSocketAsyncConnectDelegate
- (instancetype)initWithSocket: (OFSPXSocket *)sock
			  node: (unsigned char [IPX_NODE_LEN])node
		       network: (uint32_t)network
			  port: (uint16_t)port
#ifdef OF_HAVE_BLOCKS
			 block: (of_spx_socket_async_connect_block_t)block
			 block: (OFSPXSocketAsyncConnectBlock)block
#endif
{
	self = [super init];

	@try {
		_socket = [sock retain];
		memcpy(_node, node, IPX_NODE_LEN);
99
100
101
102
103
104
105
106

107
108
109


110
111
112
113
114
115
116
99
100
101
102
103
104
105

106
107


108
109
110
111
112
113
114
115
116







-
+

-
-
+
+







#ifdef OF_HAVE_BLOCKS
	[_block release];
#endif

	[super dealloc];
}

- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode
{
	of_socket_address_t address =
	    of_socket_address_ipx(_node, _network, _port);
	OFSocketAddress address =
	    OFSocketAddressMakeIPX(_node, _network, _port);
	id exception = nil;
	int errNo;

	if (![_socket of_createSocketForAddress: &address errNo: &errNo]) {
		exception = [self of_connectionFailedExceptionForErrNo: errNo];
		goto inform_delegate;
	}
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
170
171
172
173
174
175
176

177
178
179
180
181
182
183
184







-
+







							errNo: errNo];
}
@end

@implementation OFSPXSocket
@dynamic delegate;

- (int)of_createSocketForAddress: (const of_socket_address_t *)address
- (int)of_createSocketForAddress: (const OFSocketAddress *)address
			   errNo: (int *)errNo
{
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
194
195
196
197
198
199
200
201

202
203
204
205
206
207
208
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208







-
+







	if ((flags = fcntl(_socket, F_GETFD, 0)) != -1)
		fcntl(_socket, F_SETFD, flags | FD_CLOEXEC);
#endif

	return true;
}

- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address
- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (connect(_socket, &address->sockaddr.sockaddr,
	    address->length) != 0) {
219
220
221
222
223
224
225
226
227

228
229
230
231
232
233
234
219
220
221
222
223
224
225


226
227
228
229
230
231
232
233







-
-
+







	_socket = INVALID_SOCKET;
}

- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
	      network: (uint32_t)network
		 port: (uint16_t)port
{
	of_socket_address_t address =
	    of_socket_address_ipx(node, network, port);
	OFSocketAddress address = OFSocketAddressMakeIPX(node, network, port);
	int errNo;

	if (![self of_createSocketForAddress: &address errNo: &errNo])
		@throw [OFConnectionFailedException
		    exceptionWithNode: node
			      network: network
				 port: port
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
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
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
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







-
+





-
+




















-
+




-
+






-
-
+
+















-
+


-
+







-
+







- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
{
	[self asyncConnectToNode: node
			 network: network
			    port: port
		     runLoopMode: of_run_loop_mode_default];
		     runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
	       runLoopMode: (OFRunLoopMode)runLoopMode
{
	void *pool = objc_autoreleasePoolPush();

	[[[[OFSPXSocketAsyncConnectDelegate alloc]
	    initWithSocket: self
		      node: node
		   network: network
		      port: port
#ifdef OF_HAVE_BLOCKS
		     block: NULL
#endif
	    ] autorelease] startWithRunLoopMode: runLoopMode];

	objc_autoreleasePoolPop(pool);
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
		     block: (of_spx_socket_async_connect_block_t)block
		     block: (OFSPXSocketAsyncConnectBlock)block
{
	[self asyncConnectToNode: node
			 network: network
			    port: port
		     runLoopMode: of_run_loop_mode_default
		     runLoopMode: OFDefaultRunLoopMode
			   block: block];
}

- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
		     block: (of_spx_socket_async_connect_block_t)block
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (OFSPXSocketAsyncConnectBlock)block
{
	void *pool = objc_autoreleasePoolPush();

	[[[[OFSPXSocketAsyncConnectDelegate alloc]
	    initWithSocket: self
		      node: node
		   network: network
		      port: port
		     block: block
	    ] autorelease] startWithRunLoopMode: runLoopMode];

	objc_autoreleasePoolPop(pool);
}
#endif

- (of_socket_address_t)bindToPort: (uint16_t)port
- (OFSocketAddress)bindToPort: (uint16_t)port
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };
	of_socket_address_t address;
	OFSocketAddress address;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	address = of_socket_address_ipx(zeroNode, 0, port);
	address = OFSocketAddressMakeIPX(zeroNode, 0, port);

	if ((_socket = socket(address.sockaddr.sockaddr.sa_family,
	    SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET)
		@throw [OFBindFailedException
		    exceptionWithPort: port
			   packetType: SPX_PACKET_TYPE
			       socket: self
347
348
349
350
351
352
353
354

355
356
357
358
359
360
361
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360







-
+







		@throw [OFBindFailedException exceptionWithPort: port
						     packetType: SPX_PACKET_TYPE
							 socket: self
							  errNo: errNo];
	}

	memset(&address, 0, sizeof(address));
	address.family = OF_SOCKET_ADDRESS_FAMILY_IPX;
	address.family = OFSocketAddressFamilyIPX;
	address.length = (socklen_t)sizeof(address.sockaddr);

	if (of_getsockname(_socket, &address.sockaddr.sockaddr,
	    &address.length) != 0) {
		int errNo = of_socket_errno();

		closesocket(_socket);

Modified src/OFSPXStreamSocket.h from [9b835a4c0b] to [8a40db9be9].

26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40







-
-
+







#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block which is called when the socket connected.
 *
 * @param exception An exception which occurred while connecting the socket or
 *		    `nil` on success
 */
typedef void (^of_spx_stream_socket_async_connect_block_t)(
    id _Nullable exception);
typedef void (^OFSPXStreamSocketAsyncConnectBlock)(id _Nullable exception);
#endif

/**
 * @protocol OFSPXStreamSocketDelegate OFSPXStreamSocket.h \
 *	     ObjFW/OFSPXStreamSocket.h
 *
 * A delegate for OFSPXStreamSocket.
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
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







-
+















-
+















-
-
+
+









-
+



 * @param port The port (sometimes also called socket number) on the node to
 *	       connect to
 * @param runLoopMode The run loop mode in which to perform the async connect
 */
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode;
	       runLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously connect the OFSPXStreamSocket to the specified
 *	  destination.
 *
 * @param node The node to connect to
 * @param network The network on which the node to connect to is
 * @param port The port (sometimes also called socket number) on the node to
 *	       connect to
 * @param block The block to execute once the connection has been established
 */
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
		     block: (of_spx_stream_socket_async_connect_block_t)block;
		     block: (OFSPXStreamSocketAsyncConnectBlock)block;

/**
 * @brief Asynchronously connect the OFSPXStreamSocket to the specified
 *	  destination.
 *
 * @param node The node to connect to
 * @param network The network on which the node to connect to is
 * @param port The port (sometimes also called socket number) on the node to
 *	       connect to
 * @param runLoopMode The run loop mode in which to perform the async connect
 * @param block The block to execute once the connection has been established
 */
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
		     block: (of_spx_stream_socket_async_connect_block_t)block;
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (OFSPXStreamSocketAsyncConnectBlock)block;
#endif

/**
 * @brief Bind the socket to the specified network, node and port.
 *
 * @param port The port (sometimes called socket number) to bind to. 0 means to
 *	       pick one and return it.
 * @return The address on which this socket can be reached
 */
- (of_socket_address_t)bindToPort: (uint16_t)port;
- (OFSocketAddress)bindToPort: (uint16_t)port;
@end

OF_ASSUME_NONNULL_END

Modified src/OFSPXStreamSocket.m from [759cabd824] to [083a1554bc].

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







-
+

-
+













-
+








-
-
+


-
+








-
-
+







#ifndef NSPROTO_SPX
# define NSPROTO_SPX 0
#endif

#define SPX_PACKET_TYPE 5

@interface OFSPXStreamSocket ()
- (int)of_createSocketForAddress: (const of_socket_address_t *)address
- (int)of_createSocketForAddress: (const OFSocketAddress *)address
			   errNo: (int *)errNo;
- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address
- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo;
- (void)of_closeSocket;
@end

OF_DIRECT_MEMBERS
@interface OFSPXStreamSocketAsyncConnectDelegate: OFObject
    <OFRunLoopConnectDelegate>
{
	OFSPXStreamSocket *_socket;
	unsigned char _node[IPX_NODE_LEN];
	uint32_t _network;
	uint16_t _port;
#ifdef OF_HAVE_BLOCKS
	of_spx_stream_socket_async_connect_block_t _block;
	OFSPXStreamSocketAsyncConnectBlock _block;
#endif
}

- (instancetype)initWithSocket: (OFSPXStreamSocket *)socket
			  node: (unsigned char [IPX_NODE_LEN])node
		       network: (uint32_t)network
			  port: (uint16_t)port
#ifdef OF_HAVE_BLOCKS
			 block: (of_spx_stream_socket_async_connect_block_t)
				    block
			 block: (OFSPXStreamSocketAsyncConnectBlock)block
#endif
;
- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode;
@end

@implementation OFSPXStreamSocketAsyncConnectDelegate
- (instancetype)initWithSocket: (OFSPXStreamSocket *)sock
			  node: (unsigned char [IPX_NODE_LEN])node
		       network: (uint32_t)network
			  port: (uint16_t)port
#ifdef OF_HAVE_BLOCKS
			 block: (of_spx_stream_socket_async_connect_block_t)
				    block
			 block: (OFSPXStreamSocketAsyncConnectBlock)block
#endif
{
	self = [super init];

	@try {
		_socket = [sock retain];
		memcpy(_node, node, IPX_NODE_LEN);
102
103
104
105
106
107
108
109

110
111
112


113
114
115
116
117
118
119
100
101
102
103
104
105
106

107
108


109
110
111
112
113
114
115
116
117







-
+

-
-
+
+







#ifdef OF_HAVE_BLOCKS
	[_block release];
#endif

	[super dealloc];
}

- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode
{
	of_socket_address_t address =
	    of_socket_address_ipx(_node, _network, _port);
	OFSocketAddress address =
	    OFSocketAddressMakeIPX(_node, _network, _port);
	id exception = nil;
	int errNo;

	if (![_socket of_createSocketForAddress: &address errNo: &errNo]) {
		exception = [self of_connectionFailedExceptionForErrNo: errNo];
		goto inform_delegate;
	}
174
175
176
177
178
179
180
181

182
183
184
185
186
187
188
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186







-
+







							errNo: errNo];
}
@end

@implementation OFSPXStreamSocket
@dynamic delegate;

- (int)of_createSocketForAddress: (const of_socket_address_t *)address
- (int)of_createSocketForAddress: (const OFSocketAddress *)address
			   errNo: (int *)errNo
{
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
198
199
200
201
202
203
204
205

206
207
208
209
210
211
212
196
197
198
199
200
201
202

203
204
205
206
207
208
209
210







-
+







	if ((flags = fcntl(_socket, F_GETFD, 0)) != -1)
		fcntl(_socket, F_SETFD, flags | FD_CLOEXEC);
#endif

	return true;
}

- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address
- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (connect(_socket, &address->sockaddr.sockaddr,
	    address->length) != 0) {
223
224
225
226
227
228
229
230
231

232
233
234
235
236
237
238
221
222
223
224
225
226
227


228
229
230
231
232
233
234
235







-
-
+







	_socket = INVALID_SOCKET;
}

- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
	      network: (uint32_t)network
		 port: (uint16_t)port
{
	of_socket_address_t address =
	    of_socket_address_ipx(node, network, port);
	OFSocketAddress address = OFSocketAddressMakeIPX(node, network, port);
	int errNo;

	if (![self of_createSocketForAddress: &address errNo: &errNo])
		@throw [OFConnectionFailedException
		    exceptionWithNode: node
			      network: network
				 port: port
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
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
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
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







-
+





-
+




















-
+




-
+






-
-
+
+















-
+


-
+







-
+







- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
{
	[self asyncConnectToNode: node
			 network: network
			    port: port
		     runLoopMode: of_run_loop_mode_default];
		     runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
	       runLoopMode: (OFRunLoopMode)runLoopMode
{
	void *pool = objc_autoreleasePoolPush();

	[[[[OFSPXStreamSocketAsyncConnectDelegate alloc]
	    initWithSocket: self
		      node: node
		   network: network
		      port: port
#ifdef OF_HAVE_BLOCKS
		     block: NULL
#endif
	    ] autorelease] startWithRunLoopMode: runLoopMode];

	objc_autoreleasePoolPop(pool);
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
		     block: (of_spx_stream_socket_async_connect_block_t)block
		     block: (OFSPXStreamSocketAsyncConnectBlock)block
{
	[self asyncConnectToNode: node
			 network: network
			    port: port
		     runLoopMode: of_run_loop_mode_default
		     runLoopMode: OFDefaultRunLoopMode
			   block: block];
}

- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node
		   network: (uint32_t)network
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
		     block: (of_spx_stream_socket_async_connect_block_t)block
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (OFSPXStreamSocketAsyncConnectBlock)block
{
	void *pool = objc_autoreleasePoolPush();

	[[[[OFSPXStreamSocketAsyncConnectDelegate alloc]
	    initWithSocket: self
		      node: node
		   network: network
		      port: port
		     block: block
	    ] autorelease] startWithRunLoopMode: runLoopMode];

	objc_autoreleasePoolPop(pool);
}
#endif

- (of_socket_address_t)bindToPort: (uint16_t)port
- (OFSocketAddress)bindToPort: (uint16_t)port
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };
	of_socket_address_t address;
	OFSocketAddress address;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	address = of_socket_address_ipx(zeroNode, 0, port);
	address = OFSocketAddressMakeIPX(zeroNode, 0, port);

	if ((_socket = socket(address.sockaddr.sockaddr.sa_family,
	    SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET)
		@throw [OFBindFailedException
		    exceptionWithPort: port
			   packetType: SPX_PACKET_TYPE
			       socket: self
351
352
353
354
355
356
357
358

359
360
361
362
363
364
365
348
349
350
351
352
353
354

355
356
357
358
359
360
361
362







-
+







		@throw [OFBindFailedException exceptionWithPort: port
						     packetType: SPX_PACKET_TYPE
							 socket: self
							  errNo: errNo];
	}

	memset(&address, 0, sizeof(address));
	address.family = OF_SOCKET_ADDRESS_FAMILY_IPX;
	address.family = OFSocketAddressFamilyIPX;
	address.length = (socklen_t)sizeof(address.sockaddr);

	if (of_getsockname(_socket, &address.sockaddr.sockaddr,
	    &address.length) != 0) {
		int errNo = of_socket_errno();

		closesocket(_socket);

Modified src/OFSelectKernelEventObserver.m from [3e6bc46edc] to [7043fddc09].

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







-
+







	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	if (fd > _maxFD)
		_maxFD = fd;

	FD_SET((of_socket_t)fd, &_readFDs);
	FD_SET((OFSocketHandle)fd, &_readFDs);

	[super addObjectForReading: object];
}

- (void)addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	int fd = object.fileDescriptorForWriting;
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
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







-
+



















-
+




















-
+




-
+







	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	if (fd > _maxFD)
		_maxFD = fd;

	FD_SET((of_socket_t)fd, &_writeFDs);
	FD_SET((OFSocketHandle)fd, &_writeFDs);

	[super addObjectForWriting: object];
}

- (void)removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	/* TODO: Adjust _maxFD */

	int fd = object.fileDescriptorForReading;

	if (fd < 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: EBADF];

#ifndef OF_WINDOWS
	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	FD_CLR((of_socket_t)fd, &_readFDs);
	FD_CLR((OFSocketHandle)fd, &_readFDs);

	[super removeObjectForReading: object];
}

- (void)removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	/* TODO: Adjust _maxFD */

	int fd = object.fileDescriptorForWriting;

	if (fd < 0)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: EBADF];


#ifndef OF_WINDOWS
	if (fd >= (int)FD_SETSIZE)
		@throw [OFOutOfRangeException exception];
#endif

	FD_CLR((of_socket_t)fd, &_writeFDs);
	FD_CLR((OFSocketHandle)fd, &_writeFDs);

	[super removeObjectForWriting: object];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
- (void)observeForTimeInterval: (OFTimeInterval)timeInterval
{
	fd_set readFDs;
	fd_set writeFDs;
	struct timeval timeout;
	int events;
#ifdef OF_AMIGAOS
	BYTE cancelSignal;
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
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







-
+












-
+










	pool = objc_autoreleasePoolPush();

	for (id <OFReadyForReadingObserving> object in
	    [[_readObjects copy] autorelease]) {
		void *pool2 = objc_autoreleasePoolPush();
		int fd = object.fileDescriptorForReading;

		if (FD_ISSET((of_socket_t)fd, &readFDs) &&
		if (FD_ISSET((OFSocketHandle)fd, &readFDs) &&
		    [_delegate respondsToSelector:
		    @selector(objectIsReadyForReading:)])
			[_delegate objectIsReadyForReading: object];

		objc_autoreleasePoolPop(pool2);
	}

	for (id <OFReadyForWritingObserving> object in
	    [[_writeObjects copy] autorelease]) {
		void *pool2 = objc_autoreleasePoolPush();
		int fd = object.fileDescriptorForWriting;

		if (FD_ISSET((of_socket_t)fd, &writeFDs) &&
		if (FD_ISSET((OFSocketHandle)fd, &writeFDs) &&
		    [_delegate respondsToSelector:
		    @selector(objectIsReadyForWriting:)])
			[_delegate objectIsReadyForWriting: object];

		objc_autoreleasePoolPop(pool2);
	}

	objc_autoreleasePoolPop(pool);
}
@end

Modified src/OFSequencedPacketSocket.h from [441de8fe25] to [6e79cc4304].

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







-
+










-
+











-
+







 * @brief A block which is called when a packet has been received.
 *
 * @param length The length of the packet
 * @param exception An exception which occurred while receiving or `nil` on
 *		    success
 * @return A bool whether the same block should be used for the next receive
 */
typedef bool (^of_sequenced_packet_socket_async_receive_block_t)(size_t length,
typedef bool (^OFSequencedPacketSocketAsyncReceiveBlock)(size_t length,
    id _Nullable exception);

/**
 * @brief A block which is called when a packet has been sent.
 *
 * @param data The data which was sent
 * @param exception An exception which occurred while reading or `nil` on
 *		    success
 * @return The data to repeat the send with or nil if it should not repeat
 */
typedef OFData *_Nullable (^of_sequenced_packet_socket_async_send_data_block_t)(
typedef OFData *_Nullable (^OFSequencedPacketSocketAsyncSendDataBlock)(
    OFData *_Nonnull data, id _Nullable exception);

/**
 * @brief A block which is called when the socket accepted a 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_sequenced_packet_socket_async_accept_block_t)(
typedef bool (^OFSequencedPacketSocketAsyncAcceptBlock)(
    OFSequencedPacketSocket *acceptedSocket, id _Nullable exception);
#endif

/**
 * @protocol OFSequencedPacketSocketDelegate OFSequencedPacketSocket.h \
 *	     ObjFW/OFSequencedPacketSocket.h
 *
123
124
125
126
127
128
129
130

131
132

133
134
135
136
137
138
139
123
124
125
126
127
128
129

130
131

132
133
134
135
136
137
138
139







-
+

-
+







 *	    so context can be associated with a socket. Using a socket in more
 *	    than one thread at the same time is not thread-safe, even if copy
 *	    was called to create one "instance" for every thread!
 */
@interface OFSequencedPacketSocket: OFObject <OFCopying,
    OFReadyForReadingObserving, OFReadyForWritingObserving>
{
	of_socket_t _socket;
	OFSocketHandle _socket;
	bool _canBlock, _listening;
	of_socket_address_t _remoteAddress;
	OFSocketAddress _remoteAddress;
	id _Nullable _delegate;
	OF_RESERVE_IVARS(OFSequencedPacketSocket, 4)
}

/**
 * @brief Whether the socket can block.
 *
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161







-
+







@property (readonly, nonatomic, getter=isListening) bool listening;

/**
 * @brief The remote address.
 *
 * @note This only works for accepted sockets!
 */
@property (readonly, nonatomic) const of_socket_address_t *remoteAddress;
@property (readonly, nonatomic) const OFSocketAddress *remoteAddress;

/**
 * @brief The delegate for asynchronous operations on the socket.
 *
 * @note The delegate is retained for as long as asynchronous operations are
 *	 still ongoing.
 */
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
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







-
+
















-
-
-
+
+
-
-
+
















-
-
-
-
+
+
+
-
-
+







 *
 * @param buffer The buffer to write the packet to
 * @param length The length of the buffer
 * @param runLoopMode The run loop mode in which to perform the async receive
 */
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (of_run_loop_mode_t)runLoopMode;
		   runLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously receives a packet and stores it into the specified
 *	  buffer.
 *
 * If the buffer is too small, the receive operation fails.
 *
 * @param buffer The buffer to write the packet to
 * @param length The length of the buffer
 * @param block The block to call when the packet has been received. If the
 *		block returns true, it will be called again with the same
 *		buffer and maximum length when more packets have been received.
 *		If you want the next method in the queue to handle the packet
 *		received next, you need to return false from the method.
 */
- (void)
    asyncReceiveIntoBuffer: (void *)buffer
		    length: (size_t)length
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		     block: (of_sequenced_packet_socket_async_receive_block_t)
				block;
			 block: (OFSequencedPacketSocketAsyncReceiveBlock)block;

/**
 * @brief Asynchronously receives a packet and stores it into the specified
 *	  buffer.
 *
 * If the buffer is too small, the receive operation fails.
 *
 * @param buffer The buffer to write the packet to
 * @param length The length of the buffer
 * @param runLoopMode The run loop mode in which to perform the async receive
 * @param block The block to call when the packet has been received. If the
 *		block returns true, it will be called again with the same
 *		buffer and maximum length when more packets have been received.
 *		If you want the next method in the queue to handle the packet
 *		received next, you need to return false from the method.
 */
- (void)
    asyncReceiveIntoBuffer: (void *)buffer
		    length: (size_t)length
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (of_sequenced_packet_socket_async_receive_block_t)
				block;
			 block: (OFSequencedPacketSocketAsyncReceiveBlock)block;
#endif

/**
 * @brief Sends the specified packet.
 *
 * @param buffer The buffer to send as a packet
 * @param length The length of the buffer
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
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







-
+
-











-
-
+











-
+
-
-
+








/**
 * @brief Asynchronously sends the specified packet.
 *
 * @param data The data to send as a packet
 * @param runLoopMode The run loop mode in which to perform the async send
 */
- (void)asyncSendData: (OFData *)data
- (void)asyncSendData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode;
	  runLoopMode: (of_run_loop_mode_t)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously sends the specified packet.
 *
 * @param data The data to send as a packet
 * @param block The block to call when the packet has been sent. It should
 *		return the data for the next send with the same callback or nil
 *		if it should not repeat.
 */
- (void)asyncSendData: (OFData *)data
		block: (of_sequenced_packet_socket_async_send_data_block_t)
			   block;
		block: (OFSequencedPacketSocketAsyncSendDataBlock)block;

/**
 * @brief Asynchronously sends the specified packet.
 *
 * @param data The data to send as a packet
 * @param runLoopMode The run loop mode in which to perform the async send
 * @param block The block to call when the packet has been sent. It should
 *		return the data for the next send with the same callback or nil
 *		if it should not repeat.
 */
- (void)asyncSendData: (OFData *)data
	  runLoopMode: (of_run_loop_mode_t)runLoopMode
	  runLoopMode: (OFRunLoopMode)runLoopMode
		block: (of_sequenced_packet_socket_async_send_data_block_t)
			   block;
		block: (OFSequencedPacketSocketAsyncSendDataBlock)block;
#endif

/**
 * @brief Listen on the socket.
 *
 * @param backlog Maximum length for the queue of pending connections.
 */
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
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







-
+









-
+
-









+
-
-
+
+







- (void)asyncAccept;

/**
 * @brief Asynchronously accept an incoming connection.
 *
 * @param runLoopMode The run loop mode in which to perform the async accept
 */
- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously accept an incoming connection.
 *
 * @param block The block to execute when a new connection has been accepted.
 *		Returns whether the next incoming connection should be accepted
 *		by the specified block as well.
 */
- (void)asyncAcceptWithBlock:
- (void)asyncAcceptWithBlock: (OFSequencedPacketSocketAsyncAcceptBlock)block;
    (of_sequenced_packet_socket_async_accept_block_t)block;

/**
 * @brief Asynchronously accept an incoming connection.
 *
 * @param runLoopMode The run loop mode in which to perform the async accept
 * @param block The block to execute when a new connection has been accepted.
 *		Returns whether the next incoming connection should be accepted
 *		by the specified block as well.
 */
- (void)
- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
    block: (of_sequenced_packet_socket_async_accept_block_t)block;
    asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode
			 block: (OFSequencedPacketSocketAsyncAcceptBlock)block;
#endif

/**
 * @brief Cancels all pending asynchronous requests on the socket.
 */
- (void)cancelAsyncRequests;

Modified src/OFSequencedPacketSocket.m from [7bba0bbd14] to [1b0099da29].

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







-
+




-
+












-
-
-
+
+
-
-
+



-
+






-
+
-
-
+







	return ret;
}

- (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length
{
	[self asyncReceiveIntoBuffer: buffer
			      length: length
			 runLoopMode: of_run_loop_mode_default];
			 runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		   runLoopMode: (of_run_loop_mode_t)runLoopMode
		   runLoopMode: (OFRunLoopMode)runLoopMode
{
	[OFRunLoop of_addAsyncReceiveForSequencedPacketSocket: self
						       buffer: buffer
						       length: length
							 mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
							block: NULL
# endif
						     delegate: _delegate];
}

#ifdef OF_HAVE_BLOCKS
- (void)
    asyncReceiveIntoBuffer: (void *)buffer
		    length: (size_t)length
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
		     block: (of_sequenced_packet_socket_async_receive_block_t)
				block
			 block: (OFSequencedPacketSocketAsyncReceiveBlock)block
{
	[self asyncReceiveIntoBuffer: buffer
			      length: length
			 runLoopMode: of_run_loop_mode_default
			 runLoopMode: OFDefaultRunLoopMode
			       block: block];
}

- (void)
    asyncReceiveIntoBuffer: (void *)buffer
		    length: (size_t)length
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (of_sequenced_packet_socket_async_receive_block_t)
				block
		     block: (OFSequencedPacketSocketAsyncReceiveBlock)block
{
	[OFRunLoop of_addAsyncReceiveForSequencedPacketSocket: self
						       buffer: buffer
						       length: length
							 mode: runLoopMode
							block: block
						     delegate: nil];
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
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







-
+


-
+
-












-
+


-
+




-
-
+
+







						   requestedLength: length
						      bytesWritten: bytesWritten
							     errNo: 0];
}

- (void)asyncSendData: (OFData *)data
{
	[self asyncSendData: data runLoopMode: of_run_loop_mode_default];
	[self asyncSendData: data runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncSendData: (OFData *)data
- (void)asyncSendData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode
	  runLoopMode: (of_run_loop_mode_t)runLoopMode
{
	[OFRunLoop of_addAsyncSendForSequencedPacketSocket: self
						      data: data
						      mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
						     block: NULL
# endif
						  delegate: _delegate];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncSendData: (OFData *)data
		block: (of_sequenced_packet_socket_async_send_data_block_t)block
		block: (OFSequencedPacketSocketAsyncSendDataBlock)block
{
	[self asyncSendData: data
		runLoopMode: of_run_loop_mode_default
		runLoopMode: OFDefaultRunLoopMode
		      block: block];
}

- (void)asyncSendData: (OFData *)data
	  runLoopMode: (of_run_loop_mode_t)runLoopMode
		block: (of_sequenced_packet_socket_async_send_data_block_t)block
	  runLoopMode: (OFRunLoopMode)runLoopMode
		block: (OFSequencedPacketSocketAsyncSendDataBlock)block
{
	[OFRunLoop of_addAsyncSendForSequencedPacketSocket: self
						      data: data
						      mode: runLoopMode
						     block: block
						  delegate: nil];
}
364
365
366
367
368
369
370
371

372
373
374
375

376
377
378
379
380

381
382
383
384

385
386
387
388
389
390
391
392
393
394

395
396
397

398
399
400
401
402
403
404
405
406

407
408
409

410
411
412

413
414


415
416
417
418
419
420
421
422
423

424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440

441
442
443
444
445
446
447
360
361
362
363
364
365
366

367
368
369
370

371
372
373
374
375

376
377
378
379

380

381
382
383
384
385
386
387
388

389
390
391

392
393
394
395
396
397
398
399
400

401

402

403

404
405
406


407
408
409
410
411
412
413
414
415
416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433

434
435
436
437
438
439
440
441







-
+



-
+




-
+



-
+
-








-
+


-
+








-
+
-

-
+
-


+
-
-
+
+








-
+
















-
+







#endif

	assert(client->_remoteAddress.length <=
	    (socklen_t)sizeof(client->_remoteAddress.sockaddr));

	switch (client->_remoteAddress.sockaddr.sockaddr.sa_family) {
	case AF_INET:
		client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
		client->_remoteAddress.family = OFSocketAddressFamilyIPv4;
		break;
#ifdef OF_HAVE_IPV6
	case AF_INET6:
		client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV6;
		client->_remoteAddress.family = OFSocketAddressFamilyIPv6;
		break;
#endif
#ifdef OF_HAVE_IPX
	case AF_IPX:
		client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPX;
		client->_remoteAddress.family = OFSocketAddressFamilyIPX;
		break;
#endif
	default:
		client->_remoteAddress.family =
		client->_remoteAddress.family = OFSocketAddressFamilyUnknown;
		    OF_SOCKET_ADDRESS_FAMILY_UNKNOWN;
		break;
	}

	return client;
}

- (void)asyncAccept
{
	[self asyncAcceptWithRunLoopMode: of_run_loop_mode_default];
	[self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode
{
	[OFRunLoop of_addAsyncAcceptForSocket: self
					 mode: runLoopMode
					block: NULL
				     delegate: _delegate];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncAcceptWithBlock: (of_sequenced_packet_socket_async_accept_block_t)
- (void)asyncAcceptWithBlock: (OFSequencedPacketSocketAsyncAcceptBlock)block
				  block
{
	[self asyncAcceptWithRunLoopMode: of_run_loop_mode_default
	[self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode block: block];
				   block: block];
}

- (void)
- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
    block: (of_sequenced_packet_socket_async_accept_block_t)block
    asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode
			 block: (OFSequencedPacketSocketAsyncAcceptBlock)block
{
	[OFRunLoop of_addAsyncAcceptForSocket: self
					 mode: runLoopMode
					block: block
				     delegate: nil];
}
#endif

- (const of_socket_address_t *)remoteAddress
- (const OFSocketAddress *)remoteAddress
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (_remoteAddress.length == 0)
		@throw [OFInvalidArgumentException exception];

	if (_remoteAddress.length > (socklen_t)sizeof(_remoteAddress.sockaddr))
		@throw [OFOutOfRangeException exception];

	return &_remoteAddress;
}

- (void)cancelAsyncRequests
{
	[OFRunLoop of_cancelAsyncRequestsForObject: self
					      mode: of_run_loop_mode_default];
					      mode: OFDefaultRunLoopMode];
}

- (int)fileDescriptorForReading
{
#ifndef OF_WINDOWS
	return _socket;
#else

Modified src/OFSet.h from [14327ba57e] to [b05430c060].

36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58







-
+







-
+







/**
 * @brief A block for enumerating an OFSet.
 *
 * @param object The current object
 * @param stop A pointer to a variable that can be set to true to stop the
 *             enumeration
 */
typedef void (^of_set_enumeration_block_t)(id object, bool *stop);
typedef void (^OFSetEnumerationBlock)(id object, bool *stop);

/**
 * @brief A block for filtering an OFSet.
 *
 * @param object The object to inspect
 * @return Whether the object should be in the filtered set
 */
typedef bool (^of_set_filter_block_t)(id object);
typedef bool (^OFSetFilterBlock)(id object);
#endif

/**
 * @class OFSet OFSet.h ObjFW/OFSet.h
 *
 * @brief An abstract class for an unordered set of unique objects.
 *
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
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







-
+








-
-
+
+










#ifdef OF_HAVE_BLOCKS
/**
 * @brief Executes a block for each object in the set.
 *
 * @param block The block to execute for each object in the set
 */
- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block;
- (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block;

/**
 * @brief Creates a new set, only containing the objects for which the block
 *	  returns true.
 *
 * @param block A block which determines if the object should be in the new set
 * @return A new, autoreleased OFSet
 */
- (OFSet OF_GENERIC(ObjectType) *)filteredSetUsingBlock:
    (of_set_filter_block_t)block;
- (OFSet OF_GENERIC(ObjectType) *)
    filteredSetUsingBlock: (OFSetFilterBlock)block;
#endif
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef ObjectType
#endif
@end

OF_ASSUME_NONNULL_END

#import "OFMutableSet.h"

Modified src/OFSet.m from [f23395a631] to [b7d60ea604].

237
238
239
240
241
242
243
244

245
246
247
248
249
250
251
237
238
239
240
241
242
243

244
245
246
247
248
249
250
251







-
+







}

- (OFEnumerator *)objectEnumerator
{
	OF_UNRECOGNIZED_SELECTOR
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	OFEnumerator *enumerator;
	int i;

	memcpy(&enumerator, state->extra, sizeof(enumerator));
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
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







-
+











-
+







	void *pool = objc_autoreleasePoolPush();
	id ret = [[[self objectEnumerator] nextObject] retain];
	objc_autoreleasePoolPop(pool);
	return [ret autorelease];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block
- (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block
{
	bool stop = false;

	for (id object in self) {
		block(object, &stop);

		if (stop)
			break;
	}
}

- (OFSet *)filteredSetUsingBlock: (of_set_filter_block_t)block
- (OFSet *)filteredSetUsingBlock: (OFSetFilterBlock)block
{
	OFMutableSet *ret = [OFMutableSet set];

	[self enumerateObjectsUsingBlock: ^ (id object, bool *stop) {
		if (block(object))
			[ret addObject: object];
	}];

Added src/OFSizeValue.h version [48dc2259c8].





























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFValue.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFSizeValue: OFValue
{
	OFSize _size;
}

- (instancetype)initWithSize: (OFSize)size;
@end

OF_ASSUME_NONNULL_END

Added src/OFSizeValue.m version [c2a5ad86a9].





















































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFSizeValue.h"
#import "OFMethodSignature.h"
#import "OFString.h"

#import "OFOutOfRangeException.h"

@implementation OFSizeValue
@synthesize sizeValue = _size;

- (instancetype)initWithSize: (OFSize)size
{
	self = [super init];

	_size = size;

	return self;
}

- (const char *)objCType
{
	return @encode(OFSize);
}

- (void)getValue: (void *)value size: (size_t)size
{
	if (size != sizeof(_size))
		@throw [OFOutOfRangeException exception];

	memcpy(value, &_size, sizeof(_size));
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<OFValue: OFSize { %f, %f }>", _size.width, _size.height];
}
@end

Modified src/OFSortedList.h from [d2fd296ecb] to [10d4fe8869].

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







-
-
-
-
+
+
+
+

-
-
+
+








-
+






#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# define ObjectType id
#endif
{
	OF_RESERVE_IVARS(OFSortedList, 4)
}

- (of_list_object_t *)appendObject: (ObjectType)object OF_UNAVAILABLE;
- (of_list_object_t *)prependObject: (ObjectType)object OF_UNAVAILABLE;
- (of_list_object_t *)insertObject: (ObjectType)object
		  beforeListObject: (of_list_object_t *)listObject
- (OFListItem *)appendObject: (ObjectType)object OF_UNAVAILABLE;
- (OFListItem *)prependObject: (ObjectType)object OF_UNAVAILABLE;
- (OFListItem *)insertObject: (ObjectType)object
	      beforeListItem: (OFListItem *)listItem
    OF_UNAVAILABLE;
- (of_list_object_t *)insertObject: (ObjectType)object
		   afterListObject: (of_list_object_t *)listObject
- (OFListItem *)insertObject: (ObjectType)object
	       afterListItem: (OFListItem *)listItem
    OF_UNAVAILABLE;

/**
 * @brief Inserts the object to the list while keeping the list sorted.
 *
 * @param object The object to insert
 * @return The list object for the object just added
 */
- (of_list_object_t *)insertObject: (ObjectType <OFComparing>)object;
- (OFListItem *)insertObject: (ObjectType <OFComparing>)object;
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef ObjectType
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFSortedList.m from [1f44909bdd] to [228aa13ba0].

14
15
16
17
18
19
20
21

22
23
24
25
26

27
28
29
30
31
32


33
34
35
36
37
38


39
40
41
42
43

44
45

46
47
48
49



50
51
52
53
54
55
14
15
16
17
18
19
20

21
22
23
24
25

26
27
28
29
30


31
32
33
34
35
36


37
38
39
40
41
42

43
44

45
46



47
48
49

50
51
52
53
54







-
+




-
+




-
-
+
+




-
-
+
+




-
+

-
+

-
-
-
+
+
+
-





 */

#include "config.h"

#import "OFSortedList.h"

@implementation OFSortedList
- (of_list_object_t *)appendObject: (id)object
- (OFListItem *)appendObject: (id)object
{
	OF_UNRECOGNIZED_SELECTOR
}

- (of_list_object_t *)prependObject: (id)object
- (OFListItem *)prependObject: (id)object
{
	OF_UNRECOGNIZED_SELECTOR
}

- (of_list_object_t *)insertObject: (id)object
		  beforeListObject: (of_list_object_t *)listObject
- (OFListItem *)insertObject: (id)object
	      beforeListItem: (OFListItem *)listItem
{
	OF_UNRECOGNIZED_SELECTOR
}

- (of_list_object_t *)insertObject: (id)object
		   afterListObject: (of_list_object_t *)listObject
- (OFListItem *)insertObject: (id)object
	       afterListItem: (OFListItem *)listItem
{
	OF_UNRECOGNIZED_SELECTOR
}

- (of_list_object_t *)insertObject: (id <OFComparing>)object
- (OFListItem *)insertObject: (id <OFComparing>)object
{
	of_list_object_t *iter;
	OFListItem *iter;

	for (iter = _lastListObject; iter != NULL; iter = iter->previous) {
		if ([object compare: iter->object] != OF_ORDERED_ASCENDING)
			return [super insertObject: object
	for (iter = _lastListItem; iter != NULL; iter = iter->previous) {
		if ([object compare: iter->object] != OFOrderedAscending)
			return [super insertObject: object afterListItem: iter];
				   afterListObject: iter];
	}

	return [super prependObject: object];
}
@end

Modified src/OFStdIOStream.h from [db049cd597] to [cc0a782d1d].

114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
129

130
131
132
133
134
135
136
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136







-
+







-
+








/**
 * @brief Moves the cursor to the specified absolute position. Does nothing if
 *	  there is no underlying terminal.
 *
 * @param position The position to move the cursor to
 */
- (void)setCursorPosition: (of_point_t)position;
- (void)setCursorPosition: (OFPoint)position;

/**
 * @brief Moves the cursor to the specified relative position. Does nothing if
 *	  there is no underlying terminal.
 *
 * @param position The position to move the cursor to
 */
- (void)setRelativeCursorPosition: (of_point_t)position;
- (void)setRelativeCursorPosition: (OFPoint)position;
@end

#ifdef __cplusplus
extern "C" {
#endif
/** @file */

Modified src/OFStdIOStream.m from [56aed5bccb] to [4b65dc7955].

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







-
+













-
+







	if (!isatty(_fd))
		return;

	[self writeFormat: @"\033[%uG", column + 1];
#endif
}

- (void)setCursorPosition: (of_point_t)position
- (void)setCursorPosition: (OFPoint)position
{
	if (position.x < 0 || position.y < 0)
		@throw [OFInvalidArgumentException exception];

#ifdef HAVE_ISATTY
	if (!isatty(_fd))
		return;

	[self writeFormat: @"\033[%u;%uH",
			   (unsigned)position.y + 1, (unsigned)position.x + 1];
#endif
}

- (void)setRelativeCursorPosition: (of_point_t)position
- (void)setRelativeCursorPosition: (OFPoint)position
{
#ifdef HAVE_ISATTY
	if (!isatty(_fd))
		return;

	if (position.x > 0)
		[self writeFormat: @"\033[%uC", (unsigned)position.x];

Modified src/OFStream.h from [7fe1e202cf] to [b19f1dd539].

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







-
-
+











-
+














-
-
+
+













-
+







 *	  stream.
 *
 * @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)(size_t length,
    id _Nullable exception);
typedef bool (^OFStreamAsyncReadBlock)(size_t length, id _Nullable exception);

/**
 * @brief A block which is called when a line was read asynchronously from a
 *	  stream.
 *
 * @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)(OFString *_Nullable line,
typedef bool (^OFStreamAsyncReadLineBlock)(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)(
    OFData *_Nonnull data, size_t bytesWritten, id _Nullable exception);
typedef OFData *_Nullable (^OFStreamAsyncWriteDataBlock)(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 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)(
typedef OFString *_Nullable (^OFStreamAsyncWriteStringBlock)(
    OFString *_Nonnull string, size_t bytesWritten, id _Nullable exception);
#endif

/**
 * @protocol OFStreamDelegate OFStream.h ObjFW/OFStream.h
 *
 * A delegate for OFStream.
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170







-
+







 *		       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: (OFStream *)stream
	       didWriteString: (OFString *)string
		     encoding: (of_string_encoding_t)encoding
		     encoding: (OFStringEncoding)encoding
		 bytesWritten: (size_t)bytesWritten
		    exception: (nullable id)exception;
@end

/**
 * @class OFStream OFStream.h ObjFW/OFStream.h
 *
309
310
311
312
313
314
315
316

317
318
319
320
321
322
323
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322







-
+







 *		 The buffer must not be freed before the async read completed!
 * @param length The length of the data that should be read at most.
 *		 The buffer *must* be *at least* this big!
 * @param runLoopMode The run loop mode in which to perform the async read
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode;
		runLoopMode: (OFRunLoopMode)runLoopMode;

/**
 * @brief Asynchronously reads exactly the specified length bytes from the
 *	  stream into a buffer.
 *
 * Unlike @ref asyncReadIntoBuffer:length:, this method does not call the
 * method when less than the specified length has been read - instead, it waits
348
349
350
351
352
353
354
355

356
357
358
359
360
361
362
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361







-
+







 * @param buffer The buffer into which the data is read
 * @param length The length of the data that should be read.
 *		 The buffer *must* be *at least* this big!
 * @param runLoopMode The run loop mode in which to perform the async read
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode;
		runLoopMode: (OFRunLoopMode)runLoopMode;

# ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously reads *at most* ref size bytes from the stream into a
 *	  buffer.
 *
 * On network streams, this might read less than the specified number of bytes.
378
379
380
381
382
383
384
385

386
387
388
389
390
391
392
377
378
379
380
381
382
383

384
385
386
387
388
389
390
391







-
+







 *		If the block returns true, it will be called again with the same
 *		buffer and maximum length when more data has been received. If
 *		you want the next block in the queue to handle the data
 *		received next, you need to return false from the block.
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		      block: (of_stream_async_read_block_t)block;
		      block: (OFStreamAsyncReadBlock)block;

/**
 * @brief Asynchronously reads *at most* ref size bytes from the stream into a
 *	  buffer.
 *
 * On network streams, this might read less than the specified number of bytes.
 * If you want to read exactly the specified number of bytes, use
408
409
410
411
412
413
414
415
416


417
418
419
420
421
422
423
407
408
409
410
411
412
413


414
415
416
417
418
419
420
421
422







-
-
+
+







 *		If the block returns true, it will be called again with the same
 *		buffer and maximum length when more data has been received. If
 *		you want the next block in the queue to handle the data
 *		received next, you need to return false from the block.
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode
		      block: (of_stream_async_read_block_t)block;
		runLoopMode: (OFRunLoopMode)runLoopMode
		      block: (OFStreamAsyncReadBlock)block;

/**
 * @brief Asynchronously reads exactly the specified length bytes from the
 *	  stream into a buffer.
 *
 * Unlike @ref asyncReadIntoBuffer:length:block:, this method does not invoke
 * the block when less than the specified length has been read - instead, it
434
435
436
437
438
439
440
441

442
443
444
445
446
447
448
433
434
435
436
437
438
439

440
441
442
443
444
445
446
447







-
+







 *		If the block returns true, it will be called again with the same
 *		buffer and exact length when more data has been received. If
 *		you want the next block in the queue to handle the data
 *		received next, you need to return false from the block.
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		      block: (of_stream_async_read_block_t)block;
		      block: (OFStreamAsyncReadBlock)block;

/**
 * @brief Asynchronously reads exactly the specified length bytes from the
 *	  stream into a buffer.
 *
 * Unlike @ref asyncReadIntoBuffer:length:block:, this method does not invoke
 * the block when less than the specified length has been read - instead, it
460
461
462
463
464
465
466
467
468


469
470
471
472
473
474
475
459
460
461
462
463
464
465


466
467
468
469
470
471
472
473
474







-
-
+
+







 *		If the block returns true, it will be called again with the same
 *		buffer and exact length when more data has been received. If
 *		you want the next block in the queue to handle the data
 *		received next, you need to return false from the block.
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode
		      block: (of_stream_async_read_block_t)block;
		runLoopMode: (OFRunLoopMode)runLoopMode
		      block: (OFStreamAsyncReadBlock)block;
# endif
#endif

/**
 * @brief Reads a uint8_t from the stream.
 *
 * @warning Only call this when you know that enough data is available!
788
789
790
791
792
793
794
795

796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813

814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834

835
836
837
838
839
840
841
842
843
844
845
846
847


848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863

864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880


881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899



900
901
902
903
904
905
906
787
788
789
790
791
792
793

794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811

812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832

833
834
835
836
837
838
839
840
841
842
843
844


845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861

862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877


878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895



896
897
898
899
900
901
902
903
904
905







-
+

















-
+




















-
+











-
-
+
+















-
+















-
-
+
+
















-
-
-
+
+
+







 *	    Otherwise you will get an exception!
 *
 * @param encoding The encoding of the string to read from the stream
 * @param length The length (in bytes) of the string to read from the stream
 * @return A string with the specified length
 */
- (OFString *)readStringWithLength: (size_t)length
			  encoding: (of_string_encoding_t)encoding;
			  encoding: (OFStringEncoding)encoding;

/**
 * @brief Reads until a newline, `\0` or end of stream occurs.
 *
 * @return The line that was read, autoreleased, or `nil` if the end of the
 *	   stream has been reached.
 */
- (nullable OFString *)readLine;

/**
 * @brief Reads with the specified encoding until a newline, `\0` or end of
 *	  stream occurs.
 *
 * @param encoding The encoding used by the stream
 * @return The line that was read, autoreleased, or `nil` if the end of the
 *	   stream has been reached.
 */
- (nullable OFString *)readLineWithEncoding: (of_string_encoding_t)encoding;
- (nullable OFString *)readLineWithEncoding: (OFStringEncoding)encoding;

#ifdef OF_HAVE_SOCKETS
/**
 * @brief Asynchronously reads until a newline, `\0`, end of stream or an
 *	  exception occurs.
 *
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 */
- (void)asyncReadLine;

/**
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param encoding The encoding used by the stream
 */
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding;
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding;

/**
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param encoding The encoding used by the stream
 * @param runLoopMode The run loop mode in which to perform the async read
 */
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
		      runLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
		      runLoopMode: (OFRunLoopMode)runLoopMode;

# ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously reads until a newline, `\0`, end of stream or an
 *	  exception occurs.
 *
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again when the next
 *		line has been received. If you want the next block in the queue
 *		to handle the next line, you need to return false from the
 *		block.
 */
- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block;
- (void)asyncReadLineWithBlock: (OFStreamAsyncReadLineBlock)block;

/**
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param encoding The encoding used by the stream
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again when the next
 *		line has been received. If you want the next block in the queue
 *		to handle the next line, you need to return false from the
 *		block.
 */
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
			    block: (of_stream_async_read_line_block_t)block;
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
			    block: (OFStreamAsyncReadLineBlock)block;

/**
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must conform to @ref OFReadyForReadingObserving in order
 *	 for this to work!
 *
 * @param encoding The encoding used by the stream
 * @param runLoopMode The run loop mode in which to perform the async read
 * @param block The block to call when the data has been received.
 *		If the block returns true, it will be called again when the next
 *		line has been received. If you want the next block in the queue
 *		to handle the next line, you need to return false from the
 *		block.
 */
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
		      runLoopMode: (of_run_loop_mode_t)runLoopMode
			    block: (of_stream_async_read_line_block_t)block;
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
		      runLoopMode: (OFRunLoopMode)runLoopMode
			    block: (OFStreamAsyncReadLineBlock)block;
# endif
#endif

/**
 * @brief Tries to read a line from the stream (see @ref readLine) and returns
 *	  `nil` if no complete line has been received yet.
 *
914
915
916
917
918
919
920
921

922
923
924
925
926
927
928
913
914
915
916
917
918
919

920
921
922
923
924
925
926
927







-
+







 *	  @ref readLineWithEncoding:) and returns `nil` if no complete line has
 *	  been received yet.
 *
 * @param encoding The encoding used by the stream
 * @return The line that was read, autoreleased, or `nil` if the line is not
 *	   complete yet
 */
- (nullable OFString *)tryReadLineWithEncoding: (of_string_encoding_t)encoding;
- (nullable OFString *)tryReadLineWithEncoding: (OFStringEncoding)encoding;

/**
 * @brief Reads until the specified string or `\0` is found or the end of
 *	  stream occurs.
 *
 * @param delimiter The delimiter
 * @return The line that was read, autoreleased, or `nil` if the end of the
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
935
936
937
938
939
940
941

942
943
944
945
946
947
948
949







-
+







 *
 * @param delimiter The delimiter
 * @param encoding The encoding used by the stream
 * @return The line that was read, autoreleased, or `nil` if the end of the
 *	   stream has been reached.
 */
- (nullable OFString *)readTillDelimiter: (OFString *)delimiter
				encoding: (of_string_encoding_t)encoding;
				encoding: (OFStringEncoding)encoding;

/**
 * @brief Tries to reads until the specified string or `\0` is found or the end
 *	  of stream (see @ref readTillDelimiter:) and returns `nil` if not
 *	  enough data has been received yet.
 *
 * @param delimiter The delimiter
960
961
962
963
964
965
966
967

968
969
970
971
972
973
974
959
960
961
962
963
964
965

966
967
968
969
970
971
972
973







-
+







 *
 * @param delimiter The delimiter
 * @param encoding The encoding used by the stream
 * @return The line that was read, autoreleased, or `nil` if the end of the
 *	   stream has been reached.
 */
- (nullable OFString *)tryReadTillDelimiter: (OFString *)delimiter
				   encoding: (of_string_encoding_t)encoding;
				   encoding: (OFStringEncoding)encoding;

/**
 * @brief Writes everything in the write buffer to the stream.
 */
- (void)flushWriteBuffer;

/**
998
999
1000
1001
1002
1003
1004
1005

1006
1007
1008
1009
1010
1011
1012
997
998
999
1000
1001
1002
1003

1004
1005
1006
1007
1008
1009
1010
1011







-
+







 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param data The data which is written into the stream
 * @param runLoopMode The run loop mode in which to perform the async write
 */
- (void)asyncWriteData: (OFData *)data
	   runLoopMode: (of_run_loop_mode_t)runLoopMode;
	   runLoopMode: (OFRunLoopMode)runLoopMode;

/**
 * @brief Asynchronously writes a string in UTF-8 encoding into the stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
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
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
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
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







-
+














-
-
+
+














-
+














-
-
+
+













-
+
















-
-
+
+

















-
-
-
+
+
+







 *	 for this to work!
 *
 * @param string The string which is written into the stream
 * @param encoding The encoding in which the string should be written to the
 *		   stream
 */
- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding;
		encoding: (OFStringEncoding)encoding;

/**
 * @brief Asynchronously writes a string in the specified encoding into the
 *	  stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param string The string which is written into the stream
 * @param encoding The encoding in which the string should be written to the
 *		   stream
 * @param runLoopMode The run loop mode in which to perform the async write
 */
- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
	     runLoopMode: (of_run_loop_mode_t)runLoopMode;
		encoding: (OFStringEncoding)encoding
	     runLoopMode: (OFRunLoopMode)runLoopMode;

# ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously writes data into the stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param data The data which is written into the stream
 * @param block The block to call when the data has been written. It should
 *		return the data for the next write with the same callback or
 *		nil if it should not repeat.
 */
- (void)asyncWriteData: (OFData *)data
		 block: (of_stream_async_write_data_block_t)block;
		 block: (OFStreamAsyncWriteDataBlock)block;

/**
 * @brief Asynchronously writes data into the stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param data The data which is written into the stream
 * @param runLoopMode The run loop mode in which to perform the async write
 * @param block The block to call when the data has been written. It should
 *		return the data for the next write with the same callback or
 *		nil if it should not repeat.
 */
- (void)asyncWriteData: (OFData *)data
	   runLoopMode: (of_run_loop_mode_t)runLoopMode
		 block: (of_stream_async_write_data_block_t)block;
	   runLoopMode: (OFRunLoopMode)runLoopMode
		 block: (OFStreamAsyncWriteDataBlock)block;

/**
 * @brief Asynchronously writes a string into the stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param string The string which is written into the stream
 * @param block The block to call when the string has been written. It should
 *		return the string for the next write with the same callback or
 *		nil if it should not repeat.
 */
- (void)asyncWriteString: (OFString *)string
		   block: (of_stream_async_write_string_block_t)block;
		   block: (OFStreamAsyncWriteStringBlock)block;

/**
 * @brief Asynchronously writes a string in the specified encoding into the
 *	  stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param string The string which is written into the stream
 * @param encoding The encoding in which the string should be written to the
 *		   stream
 * @param block The block to call when the string has been written. It should
 *		return the string for the next write with the same callback or
 *		nil if it should not repeat.
 */
- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
		   block: (of_stream_async_write_string_block_t)block;
		encoding: (OFStringEncoding)encoding
		   block: (OFStreamAsyncWriteStringBlock)block;

/**
 * @brief Asynchronously writes a string in the specified encoding into the
 *	  stream.
 *
 * @note The stream must conform to @ref OFReadyForWritingObserving in order
 *	 for this to work!
 *
 * @param string The string which is written into the stream
 * @param encoding The encoding in which the string should be written to the
 *		   stream
 * @param runLoopMode The run loop mode in which to perform the async write
 * @param block The block to call when the string has been written. It should
 *		return the string for the next write with the same callback or
 *		nil if it should not repeat.
 */
- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
	     runLoopMode: (of_run_loop_mode_t)runLoopMode
		   block: (of_stream_async_write_string_block_t)block;
		encoding: (OFStringEncoding)encoding
	     runLoopMode: (OFRunLoopMode)runLoopMode
		   block: (OFStreamAsyncWriteStringBlock)block;
# endif
#endif

/**
 * @brief Writes a uint8_t into the stream.
 *
 * @param int8 A uint8_t
1339
1340
1341
1342
1343
1344
1345
1346

1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365

1366
1367
1368
1369
1370
1371
1372
1373


1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385


1386
1387
1388
1389
1390
1391
1392
1338
1339
1340
1341
1342
1343
1344

1345

1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362

1363

1364
1365
1366
1367
1368


1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380


1381
1382
1383
1384
1385
1386
1387
1388
1389







-
+
-

















-
+
-





-
-
+
+










-
-
+
+







 * @brief Writes a string into the stream in the specified encoding, without
 *	  the trailing zero.
 *
 * @param string The string from which the data is written to the stream
 * @param encoding The encoding in which to write the string to the stream
 * @return The number of bytes written
 */
- (size_t)writeString: (OFString *)string
- (size_t)writeString: (OFString *)string encoding: (OFStringEncoding)encoding;
	     encoding: (of_string_encoding_t)encoding;

/**
 * @brief Writes a string into the stream with a trailing newline.
 *
 * @param string The string from which the data is written to the stream
 * @return The number of bytes written
 */
- (size_t)writeLine: (OFString *)string;

/**
 * @brief Writes a string into the stream in the specified encoding with a
 *	  trailing newline.
 *
 * @param string The string from which the data is written to the stream
 * @param encoding The encoding in which to write the string to the stream
 * @return The number of bytes written
 */
- (size_t)writeLine: (OFString *)string
- (size_t)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding;
	   encoding: (of_string_encoding_t)encoding;

/**
 * @brief Writes a formatted string into the stream.
 *
 * See printf for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A string used as format
 * @return The number of bytes written
 */
- (size_t)writeFormat: (OFConstantString *)format, ...;

/**
 * @brief Writes a formatted string into the stream.
 *
 * See printf for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A string used as format
 * @param arguments The arguments used in the format string
 * @return The number of bytes written
 */
- (size_t)writeFormat: (OFConstantString *)format arguments: (va_list)arguments;

Modified src/OFStream.m from [7e32841415] to [60268de704].

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
282
283
284
285
286
287


288
289
290
291
292
293
294
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
282
283
284
285


286
287
288
289
290
291
292
293
294







-
+




-
+


















-
+




-
+

















-
+



-
+





-
-
+
+














-
+



-
+





-
-
+
+







}

#ifdef OF_HAVE_SOCKETS
- (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length
{
	[self asyncReadIntoBuffer: buffer
			   length: length
		      runLoopMode: of_run_loop_mode_default];
		      runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode
		runLoopMode: (OFRunLoopMode)runLoopMode
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				     length: length
				       mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
				      block: NULL
# endif
				   delegate: _delegate];
}

- (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length
{
	[self asyncReadIntoBuffer: buffer
		      exactLength: length
		      runLoopMode: of_run_loop_mode_default];
		      runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode
		runLoopMode: (OFRunLoopMode)runLoopMode
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				exactLength: length
				       mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
				      block: NULL
# endif
				   delegate: _delegate];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		      block: (of_stream_async_read_block_t)block
		      block: (OFStreamAsyncReadBlock)block
{
	[self asyncReadIntoBuffer: buffer
			   length: length
		      runLoopMode: of_run_loop_mode_default
		      runLoopMode: OFDefaultRunLoopMode
			    block: block];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode
		      block: (of_stream_async_read_block_t)block
		runLoopMode: (OFRunLoopMode)runLoopMode
		      block: (OFStreamAsyncReadBlock)block
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				     length: length
				       mode: runLoopMode
				      block: block
				   delegate: nil];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		      block: (of_stream_async_read_block_t)block
		      block: (OFStreamAsyncReadBlock)block
{
	[self asyncReadIntoBuffer: buffer
		      exactLength: length
		      runLoopMode: of_run_loop_mode_default
		      runLoopMode: OFDefaultRunLoopMode
			    block: block];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		runLoopMode: (of_run_loop_mode_t)runLoopMode
		      block: (of_stream_async_read_block_t)block
		runLoopMode: (OFRunLoopMode)runLoopMode
		      block: (OFStreamAsyncReadBlock)block
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadForStream: stream
				     buffer: buffer
				exactLength: length
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
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







-
+



-
+















-
+







	[data makeImmutable];
	return data;
}

- (OFString *)readStringWithLength: (size_t)length
{
	return [self readStringWithLength: length
				 encoding: OF_STRING_ENCODING_UTF_8];
				 encoding: OFStringEncodingUTF8];
}

- (OFString *)readStringWithLength: (size_t)length
			  encoding: (of_string_encoding_t)encoding
			  encoding: (OFStringEncoding)encoding
{
	OFString *ret;
	char *buffer = of_alloc(length + 1, 1);
	buffer[length] = 0;

	@try {
		[self readIntoBuffer: buffer exactLength: length];
		ret = [OFString stringWithCString: buffer encoding: encoding];
	} @finally {
		free(buffer);
	}

	return ret;
}

- (OFString *)tryReadLineWithEncoding: (of_string_encoding_t)encoding
- (OFString *)tryReadLineWithEncoding: (OFStringEncoding)encoding
{
	size_t pageSize, bufferLength;
	char *buffer, *readBuffer;
	OFString *ret;

	/* Look if there's a line or \0 in our buffer */
	if (!_waitingForDelimiter && _readBuffer != NULL) {
787
788
789
790
791
792
793
794

795
796
797

798
799
800
801
802
803
804
805
806
807
808
809
810
811
812


813
814
815

816
817
818

819
820
821
822


823
824
825
826
827
828
829
830
831
832
833
834
835
836
837

838
839
840


841
842
843
844
845


846
847
848

849
850
851
852
853
854



855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870

871
872
873
874

875
876
877
878
879
880
881
787
788
789
790
791
792
793

794
795
796

797
798
799
800
801
802
803
804
805
806
807
808
809
810


811
812
813
814

815
816
817

818
819
820


821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836

837
838


839
840
841
842
843


844
845
846
847

848
849
850
851



852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

870
871
872
873

874
875
876
877
878
879
880
881







-
+


-
+













-
-
+
+


-
+


-
+


-
-
+
+














-
+

-
-
+
+



-
-
+
+


-
+



-
-
-
+
+
+















-
+



-
+








	_waitingForDelimiter = true;
	return nil;
}

- (OFString *)readLine
{
	return [self readLineWithEncoding: OF_STRING_ENCODING_UTF_8];
	return [self readLineWithEncoding: OFStringEncodingUTF8];
}

- (OFString *)readLineWithEncoding: (of_string_encoding_t)encoding
- (OFString *)readLineWithEncoding: (OFStringEncoding)encoding
{
	OFString *line = nil;

	while ((line = [self tryReadLineWithEncoding: encoding]) == nil)
		if (self.atEndOfStream)
			return nil;

	return line;
}

#ifdef OF_HAVE_SOCKETS
- (void)asyncReadLine
{
	[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
			    runLoopMode: of_run_loop_mode_default];
	[self asyncReadLineWithEncoding: OFStringEncodingUTF8
			    runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
{
	[self asyncReadLineWithEncoding: encoding
			    runLoopMode: of_run_loop_mode_default];
			    runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
		      runLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
		      runLoopMode: (OFRunLoopMode)runLoopMode
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadLineForStream: stream
				       encoding: encoding
					   mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
					  block: NULL
# endif
				       delegate: _delegate];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block
- (void)asyncReadLineWithBlock: (OFStreamAsyncReadLineBlock)block
{
	[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
			    runLoopMode: of_run_loop_mode_default
	[self asyncReadLineWithEncoding: OFStringEncodingUTF8
			    runLoopMode: OFDefaultRunLoopMode
				  block: block];
}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
			    block: (of_stream_async_read_line_block_t)block
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
			    block: (OFStreamAsyncReadLineBlock)block
{
	[self asyncReadLineWithEncoding: encoding
			    runLoopMode: of_run_loop_mode_default
			    runLoopMode: OFDefaultRunLoopMode
				  block: block];
}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
		      runLoopMode: (of_run_loop_mode_t)runLoopMode
			    block: (of_stream_async_read_line_block_t)block
- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding
		      runLoopMode: (OFRunLoopMode)runLoopMode
			    block: (OFStreamAsyncReadLineBlock)block
{
	OFStream <OFReadyForReadingObserving> *stream =
	    (OFStream <OFReadyForReadingObserving> *)self;

	[OFRunLoop of_addAsyncReadLineForStream: stream
				       encoding: encoding
					   mode: runLoopMode
					  block: block
				       delegate: nil];
}
# endif
#endif

- (OFString *)tryReadLine
{
	return [self tryReadLineWithEncoding: OF_STRING_ENCODING_UTF_8];
	return [self tryReadLineWithEncoding: OFStringEncodingUTF8];
}

- (OFString *)tryReadTillDelimiter: (OFString *)delimiter
			  encoding: (of_string_encoding_t)encoding
			  encoding: (OFStringEncoding)encoding
{
	const char *delimiterCString;
	size_t j, delimiterLength, pageSize, bufferLength;
	char *buffer, *readBuffer;
	OFString *ret;

	delimiterCString = [delimiter cStringWithEncoding: encoding];
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
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







-
+



-
+














-
+







	return nil;
}


- (OFString *)readTillDelimiter: (OFString *)delimiter
{
	return [self readTillDelimiter: delimiter
			      encoding: OF_STRING_ENCODING_UTF_8];
			      encoding: OFStringEncodingUTF8];
}

- (OFString *)readTillDelimiter: (OFString *)delimiter
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
{
	OFString *ret = nil;

	while ((ret = [self tryReadTillDelimiter: delimiter
					encoding: encoding]) == nil)
		if (self.atEndOfStream)
			return nil;

	return ret;
}

- (OFString *)tryReadTillDelimiter: (OFString *)delimiter
{
	return [self tryReadTillDelimiter: delimiter
				 encoding: OF_STRING_ENCODING_UTF_8];
				 encoding: OFStringEncodingUTF8];
}

- (void)flushWriteBuffer
{
	if (_writeBuffer == NULL)
		return;

1092
1093
1094
1095
1096
1097
1098
1099

1100
1101
1102

1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121


1122
1123
1124
1125

1126
1127
1128
1129

1130
1131
1132
1133
1134


1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150

1151
1152
1153
1154

1155
1156
1157
1158
1159
1160


1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173

1174
1175
1176
1177


1178
1179
1180
1181
1182
1183


1184
1185
1186
1187

1188
1189
1190
1191
1192
1193
1194



1195
1196
1197
1198
1199
1200
1201
1092
1093
1094
1095
1096
1097
1098

1099
1100
1101

1102

1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118


1119
1120
1121
1122
1123

1124
1125
1126
1127

1128
1129
1130
1131


1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148

1149

1150
1151

1152
1153
1154
1155
1156


1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170

1171
1172
1173


1174
1175
1176
1177
1178
1179


1180
1181
1182
1183
1184

1185
1186
1187
1188
1189



1190
1191
1192
1193
1194
1195
1196
1197
1198
1199







-
+


-
+
-
















-
-
+
+



-
+



-
+



-
-
+
+















-
+
-


-
+




-
-
+
+












-
+


-
-
+
+




-
-
+
+



-
+




-
-
-
+
+
+







		return length;
	}
}

#ifdef OF_HAVE_SOCKETS
- (void)asyncWriteData: (OFData *)data
{
	[self asyncWriteData: data runLoopMode: of_run_loop_mode_default];
	[self asyncWriteData: data runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncWriteData: (OFData *)data
- (void)asyncWriteData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode
	   runLoopMode: (of_run_loop_mode_t)runLoopMode
{
	OFStream <OFReadyForWritingObserving> *stream =
	    (OFStream <OFReadyForWritingObserving> *)self;

	[OFRunLoop of_addAsyncWriteForStream: stream
					data: data
					mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
				       block: NULL
# endif
				    delegate: _delegate];
}

- (void)asyncWriteString: (OFString *)string
{
	[self asyncWriteString: string
		      encoding: OF_STRING_ENCODING_UTF_8
		   runLoopMode: of_run_loop_mode_default];
		      encoding: OFStringEncodingUTF8
		   runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
		encoding: (OFStringEncoding)encoding
{
	[self asyncWriteString: string
		      encoding: encoding
		   runLoopMode: of_run_loop_mode_default];
		   runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
	     runLoopMode: (of_run_loop_mode_t)runLoopMode
		encoding: (OFStringEncoding)encoding
	     runLoopMode: (OFRunLoopMode)runLoopMode
{
	OFStream <OFReadyForWritingObserving> *stream =
	    (OFStream <OFReadyForWritingObserving> *)self;

	[OFRunLoop of_addAsyncWriteForStream: stream
				      string: string
				    encoding: encoding
					mode: runLoopMode
# ifdef OF_HAVE_BLOCKS
				       block: NULL
# endif
				    delegate: _delegate];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncWriteData: (OFData *)data
- (void)asyncWriteData: (OFData *)data block: (OFStreamAsyncWriteDataBlock)block
		 block: (of_stream_async_write_data_block_t)block
{
	[self asyncWriteData: data
		 runLoopMode: of_run_loop_mode_default
		 runLoopMode: OFDefaultRunLoopMode
		       block: block];
}

- (void)asyncWriteData: (OFData *)data
	   runLoopMode: (of_run_loop_mode_t)runLoopMode
		 block: (of_stream_async_write_data_block_t)block
	   runLoopMode: (OFRunLoopMode)runLoopMode
		 block: (OFStreamAsyncWriteDataBlock)block
{
	OFStream <OFReadyForWritingObserving> *stream =
	    (OFStream <OFReadyForWritingObserving> *)self;

	[OFRunLoop of_addAsyncWriteForStream: stream
					data: data
					mode: runLoopMode
				       block: block
				    delegate: nil];
}

- (void)asyncWriteString: (OFString *)string
		   block: (of_stream_async_write_string_block_t)block
		   block: (OFStreamAsyncWriteStringBlock)block
{
	[self asyncWriteString: string
		      encoding: OF_STRING_ENCODING_UTF_8
		   runLoopMode: of_run_loop_mode_default
		      encoding: OFStringEncodingUTF8
		   runLoopMode: OFDefaultRunLoopMode
			 block: block];
}

- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
		   block: (of_stream_async_write_string_block_t)block
		encoding: (OFStringEncoding)encoding
		   block: (OFStreamAsyncWriteStringBlock)block
{
	[self asyncWriteString: string
		      encoding: encoding
		   runLoopMode: of_run_loop_mode_default
		   runLoopMode: OFDefaultRunLoopMode
			 block: block];
}

- (void)asyncWriteString: (OFString *)string
		encoding: (of_string_encoding_t)encoding
	     runLoopMode: (of_run_loop_mode_t)runLoopMode
		   block: (of_stream_async_write_string_block_t)block
		encoding: (OFStringEncoding)encoding
	     runLoopMode: (OFRunLoopMode)runLoopMode
		   block: (OFStreamAsyncWriteStringBlock)block
{
	OFStream <OFReadyForWritingObserving> *stream =
	    (OFStream <OFReadyForWritingObserving> *)self;

	[OFRunLoop of_addAsyncWriteForStream: stream
				      string: string
				    encoding: encoding
1557
1558
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
1555
1556
1557
1558
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







-
+


-
+
-




















-
+


-
+







	objc_autoreleasePoolPop(pool);

	return length;
}

- (size_t)writeString: (OFString *)string
{
	return [self writeString: string encoding: OF_STRING_ENCODING_UTF_8];
	return [self writeString: string encoding: OFStringEncodingUTF8];
}

- (size_t)writeString: (OFString *)string
- (size_t)writeString: (OFString *)string encoding: (OFStringEncoding)encoding
	     encoding: (of_string_encoding_t)encoding
{
	void *pool;
	size_t length;

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

	pool = objc_autoreleasePoolPush();
	length = [string cStringLengthWithEncoding: encoding];

	[self writeBuffer: [string cStringWithEncoding: encoding]
		   length: length];

	objc_autoreleasePoolPop(pool);

	return length;
}

- (size_t)writeLine: (OFString *)string
{
	return [self writeLine: string encoding: OF_STRING_ENCODING_UTF_8];
	return [self writeLine: string encoding: OFStringEncodingUTF8];
}

- (size_t)writeLine: (OFString *)string encoding: (of_string_encoding_t)encoding
- (size_t)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding
{
	size_t stringLength = [string cStringLengthWithEncoding: encoding];
	char *buffer;

	buffer = of_alloc(stringLength + 1, 1);

	@try {
1729
1730
1731
1732
1733
1734
1735
1736

1737
1738
1739
1740
1741
1742
1743
1726
1727
1728
1729
1730
1731
1732

1733
1734
1735
1736
1737
1738
1739
1740







-
+







	OF_UNRECOGNIZED_SELECTOR
}

#ifdef OF_HAVE_SOCKETS
- (void)cancelAsyncRequests
{
	[OFRunLoop of_cancelAsyncRequestsForObject: self
					      mode: of_run_loop_mode_default];
					      mode: OFDefaultRunLoopMode];
}
#endif

- (void)unreadFromBuffer: (const void *)buffer length: (size_t)length
{
	char *readBuffer;

Modified src/OFStreamSocket.h from [27f4a02196] to [3d3d625aa6].

29
30
31
32
33
34
35
36
37


38
39
40
41
42
43
44
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44







-
-
+
+







 *
 * @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_stream_socket_async_accept_block_t)(
    OFStreamSocket *acceptedSocket, id _Nullable exception);
typedef bool (^OFStreamSocketAsyncAcceptBlock)(OFStreamSocket *acceptedSocket,
    id _Nullable exception);
#endif

/**
 * @protocol OFStreamSocketDelegate OFStreamSocket.h ObjFW/OFStreamSocket.h
 *
 * A delegate for OFStreamSocket.
 */
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
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







-
+

-
+













-
+







 * @class OFStreamSocket OFStreamSocket.h ObjFW/OFStreamSocket.h
 *
 * @brief A class which provides methods to create and use stream sockets.
 */
@interface OFStreamSocket: OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	of_socket_t _socket;
	OFSocketHandle _socket;
	bool _atEndOfStream, _listening;
	of_socket_address_t _remoteAddress;
	OFSocketAddress _remoteAddress;
	OF_RESERVE_IVARS(OFStreamSocket, 4)
}

/**
 * @brief Whether the socket is a listening socket.
 */
@property (readonly, nonatomic, getter=isListening) bool listening;

/**
 * @brief The remote address.
 *
 * @note This only works for accepted sockets!
 */
@property (readonly, nonatomic) const of_socket_address_t *remoteAddress;
@property (readonly, nonatomic) const OFSocketAddress *remoteAddress;

/**
 * @brief The delegate for asynchronous operations on the socket.
 *
 * @note The delegate is retained for as long as asynchronous operations are
 *	 still ongoing.
 */
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
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







-
+









-
+









-
+
-
-
+




- (void)asyncAccept;

/**
 * @brief Asynchronously accept an incoming connection.
 *
 * @param runLoopMode The run loop mode in which to perform the async accept
 */
- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously accept an incoming connection.
 *
 * @param block The block to execute when a new connection has been accepted.
 *		Returns whether the next incoming connection should be accepted
 *		by the specified block as well.
 */
- (void)asyncAcceptWithBlock: (of_stream_socket_async_accept_block_t)block;
- (void)asyncAcceptWithBlock: (OFStreamSocketAsyncAcceptBlock)block;

/**
 * @brief Asynchronously accept an incoming connection.
 *
 * @param runLoopMode The run loop mode in which to perform the async accept
 * @param block The block to execute when a new connection has been accepted.
 *		Returns whether the next incoming connection should be accepted
 *		by the specified block as well.
 */
- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode
			     block: (of_stream_socket_async_accept_block_t)
					block;
			     block: (OFStreamSocketAsyncAcceptBlock)block;
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFStreamSocket.m from [7f5d88caa9] to [3262c13b9d].

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







-
+



-
+




-
+



-
+
-








-
+


-
+








-
+

-
+
-


-
-
+
+








-
+







#endif

	assert(client->_remoteAddress.length <=
	    (socklen_t)sizeof(client->_remoteAddress.sockaddr));

	switch (client->_remoteAddress.sockaddr.sockaddr.sa_family) {
	case AF_INET:
		client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
		client->_remoteAddress.family = OFSocketAddressFamilyIPv4;
		break;
#ifdef OF_HAVE_IPV6
	case AF_INET6:
		client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV6;
		client->_remoteAddress.family = OFSocketAddressFamilyIPv6;
		break;
#endif
#ifdef OF_HAVE_IPX
	case AF_IPX:
		client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPX;
		client->_remoteAddress.family = OFSocketAddressFamilyIPX;
		break;
#endif
	default:
		client->_remoteAddress.family =
		client->_remoteAddress.family = OFSocketAddressFamilyUnknown;
		    OF_SOCKET_ADDRESS_FAMILY_UNKNOWN;
		break;
	}

	return client;
}

- (void)asyncAccept
{
	[self asyncAcceptWithRunLoopMode: of_run_loop_mode_default];
	[self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode
{
	[OFRunLoop of_addAsyncAcceptForSocket: self
					 mode: runLoopMode
					block: NULL
				     delegate: _delegate];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncAcceptWithBlock: (of_stream_socket_async_accept_block_t)block
- (void)asyncAcceptWithBlock: (OFStreamSocketAsyncAcceptBlock)block
{
	[self asyncAcceptWithRunLoopMode: of_run_loop_mode_default
	[self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode block: block];
				   block: block];
}

- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode
			     block: (of_stream_socket_async_accept_block_t)block
- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode
			     block: (OFStreamSocketAsyncAcceptBlock)block
{
	[OFRunLoop of_addAsyncAcceptForSocket: self
					 mode: runLoopMode
					block: block
				     delegate: nil];
}
#endif

- (const of_socket_address_t *)remoteAddress
- (const OFSocketAddress *)remoteAddress
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (_remoteAddress.length == 0)
		@throw [OFInvalidArgumentException exception];

Modified src/OFString+CryptographicHashing.m from [9f70fbd17b] to [7e22b6306f].

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







-
+







		cString[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0');
		cString[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0');
	}

	objc_autoreleasePoolPop(pool);

	return [OFString stringWithCString: cString
				  encoding: OF_STRING_ENCODING_ASCII
				  encoding: OFStringEncodingASCII
				    length: digestSize * 2];
}

- (OFString *)stringByMD5Hashing
{
	return stringByHashing([OFMD5Hash class], self);
}

Modified src/OFString+JSONParsing.m from [c87ddb2735] to [b02567e9c8].

105
106
107
108
109
110
111
112

113
114
115

116
117
118
119
120
121
122
105
106
107
108
109
110
111

112
113
114

115
116
117
118
119
120
121
122







-
+


-
+







		old = *pointer;

		skipWhitespaces(pointer, stop, line);
		skipComment(pointer, stop, line);
	}
}

static inline of_char16_t
static inline OFChar16
parseUnicodeEscape(const char *pointer, const char *stop)
{
	of_char16_t ret = 0;
	OFChar16 ret = 0;

	if (pointer + 5 >= stop)
		return 0xFFFF;

	if (pointer[0] != '\\' || pointer[1] != 'u')
		return 0xFFFF;

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







-
-
+
+







				break;
			case 't':
				buffer[i++] = '\t';
				(*pointer)++;
				break;
			/* Parse Unicode escape sequence */
			case 'u':;
				of_char16_t c1, c2;
				of_unichar_t c;
				OFChar16 c1, c2;
				OFUnichar c;
				size_t l;

				c1 = parseUnicodeEscape(*pointer - 1, stop);
				if (c1 == 0xFFFF) {
					free(buffer);
					return nil;
				}
303
304
305
306
307
308
309
310
311


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


310
311
312
313
314
315
316
317
318







-
-
+
+







		    (**pointer >= 'A' && **pointer <= 'Z') ||
		    (**pointer >= '0' && **pointer <= '9') ||
		    **pointer == '_' || **pointer == '$' ||
		    (**pointer & 0x80)) {
			buffer[i++] = **pointer;
			(*pointer)++;
		} else if (**pointer == '\\') {
			of_char16_t c1, c2;
			of_unichar_t c;
			OFChar16 c1, c2;
			OFUnichar c;
			size_t l;

			if (++(*pointer) >= stop || **pointer != 'u') {
				free(buffer);
				return nil;
			}

Modified src/OFString+URLEncoding.m from [6ddd187364] to [88731f0af5].

30
31
32
33
34
35
36
37

38
39
40


41
42
43
44

45
46
47
48
49
50
51
30
31
32
33
34
35
36

37
38


39
40
41
42
43

44
45
46
47
48
49
50
51







-
+

-
-
+
+



-
+








@implementation OFString (URLEncoding)
- (OFString *)stringByURLEncodingWithAllowedCharacters:
    (OFCharacterSet *)allowedCharacters
{
	OFMutableString *ret = [OFMutableString string];
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *characters = self.characters;
	size_t length = self.length;
	bool (*characterIsMember)(id, SEL, of_unichar_t) =
	    (bool (*)(id, SEL, of_unichar_t))[allowedCharacters
	bool (*characterIsMember)(id, SEL, OFUnichar) =
	    (bool (*)(id, SEL, OFUnichar))[allowedCharacters
	    methodForSelector: @selector(characterIsMember:)];

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

		if (characterIsMember(allowedCharacters,
		    @selector(characterIsMember:), c))
			[ret appendCharacters: &c length: 1];
		else {
			char buffer[4];
			size_t bufferLen;

Modified src/OFString+XMLUnescaping.h from [d4c2a5d60a] to [cbe997ff43].

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







-
-
+
+







 * @brief A block which is called to replace unknown XML entities in an XML
 *	  string.
 *
 * @param string The XML string which contains an unknown entity
 * @param entity The XML entity which is unknown
 * @return A replacement string for the unknown entity
 */
typedef OFString *_Nullable (^of_string_xml_unescaping_block_t)(
    OFString *string, OFString *entity);
typedef OFString *_Nullable (^OFStringXMLUnescapingBlock)(OFString *string,
    OFString *entity);
#endif

/**
 * @protocol OFStringXMLUnescapingDelegate OFString.h ObjFW/OFString.h
 *
 * @brief A protocol that needs to be implemented by delegates for
 *	  stringByXMLUnescapingWithHandler:.
81
82
83
84
85
86
87
88

89
90
91
92
93
81
82
83
84
85
86
87

88

89
90
91
92







-
+
-




#ifdef OF_HAVE_BLOCKS
/**
 * @brief Unescapes XML in the string and uses the specified block for unknown
 *	  entities.
 *
 * @param block A block which handles unknown entities
 */
- (OFString *)stringByXMLUnescapingWithBlock:
- (OFString *)stringByXMLUnescapingWithBlock: (OFStringXMLUnescapingBlock)block;
    (of_string_xml_unescaping_block_t)block;
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFString+XMLUnescaping.m from [c09f1d107c] to [0a903f9009].

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 "OFUnknownXMLEntityException.h"

int _OFString_XMLUnescaping_reference;

static OF_INLINE OFString *
parseNumericEntity(const char *entity, size_t length)
{
	of_unichar_t c;
	OFUnichar c;
	size_t i;
	char buffer[5];

	if (length == 1 || *entity != '#')
		return nil;

	c = 0;
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
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







-
+




-
+




-
+




-
+




-
+







			inEntity = true;
		} else if (inEntity && string[i] == ';') {
			const char *entity = string + last;
			size_t entityLength = i - last;

			if (entityLength == 2 && memcmp(entity, "lt", 2) == 0)
				[ret appendCString: "<"
					  encoding: OF_STRING_ENCODING_ASCII
					  encoding: OFStringEncodingASCII
					    length: 1];
			else if (entityLength == 2 &&
			    memcmp(entity, "gt", 2) == 0)
				[ret appendCString: ">"
					  encoding: OF_STRING_ENCODING_ASCII
					  encoding: OFStringEncodingASCII
					    length: 1];
			else if (entityLength == 4 &&
			    memcmp(entity, "quot", 4) == 0)
				[ret appendCString: "\""
					  encoding: OF_STRING_ENCODING_ASCII
					  encoding: OFStringEncodingASCII
					    length: 1];
			else if (entityLength == 4 &&
			    memcmp(entity, "apos", 4) == 0)
				[ret appendCString: "'"
					  encoding: OF_STRING_ENCODING_ASCII
					  encoding: OFStringEncodingASCII
					    length: 1];
			else if (entityLength == 3 &&
			    memcmp(entity, "amp", 3) == 0)
				[ret appendCString: "&"
					  encoding: OF_STRING_ENCODING_ASCII
					  encoding: OFStringEncodingASCII
					    length: 1];
			else if (entity[0] == '#') {
				void *pool2;
				OFString *tmp;

				pool2 = objc_autoreleasePoolPush();
				tmp = parseNumericEntity(entity,
186
187
188
189
190
191
192
193

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

193
194
195
196
197
198
199
200







-
+







	return [delegate string: self containsUnknownEntityNamed: entity];
}

#ifdef OF_HAVE_BLOCKS
static id
lookupUsingBlock(void *context, OFString *self, OFString *entity)
{
	of_string_xml_unescaping_block_t block = context;
	OFStringXMLUnescapingBlock block = context;

	if (block == NULL)
		return nil;

	return block(self, entity);
}
#endif
208
209
210
211
212
213
214
215

216
217
218
219
220
221
208
209
210
211
212
213
214

215

216
217
218
219
220







-
+
-





- (OFString *)stringByXMLUnescapingWithDelegate:
    (id <OFStringXMLUnescapingDelegate>)delegate
{
	return parseEntities(self, lookupUsingDelegate, delegate);
}

#ifdef OF_HAVE_BLOCKS
- (OFString *)stringByXMLUnescapingWithBlock:
- (OFString *)stringByXMLUnescapingWithBlock: (OFStringXMLUnescapingBlock)block
    (of_string_xml_unescaping_block_t)block
{
	return parseEntities(self, lookupUsingBlock, block);
}
#endif
@end

Modified src/OFString.h from [9aa19fe6df] to [c20eafef33].

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







-
-
+
+

-
-
+
+

-
+




-
+





-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
-
+
+

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









-
+







@class OFConstantString;
@class OFString;
#else
typedef void OFString;
#endif

#if defined(__cplusplus) && __cplusplus >= 201103L
typedef char16_t of_char16_t;
typedef char32_t of_char32_t;
typedef char16_t OFChar16;
typedef char32_t OFChar32;
#else
typedef uint_least16_t of_char16_t;
typedef uint_least32_t of_char32_t;
typedef uint_least16_t OFChar16;
typedef uint_least32_t OFChar32;
#endif
typedef of_char32_t of_unichar_t;
typedef OFChar32 OFUnichar;

/**
 * @brief The encoding of a string.
 */
typedef enum of_string_encoding_t {
typedef enum OFStringEncoding {
	/*
	 * UTF-8 *has* to be 0, so that if the current @ref OFLocale is
	 * `nil`, `[OFLocale encoding]` returns UTF-8.
	 */
	/** UTF-8 */
	OF_STRING_ENCODING_UTF_8,
	OFStringEncodingUTF8,
	/** ASCII */
	OF_STRING_ENCODING_ASCII,
	OFStringEncodingASCII,
	/** ISO 8859-1 */
	OF_STRING_ENCODING_ISO_8859_1,
	OFStringEncodingISO8859_1,
	/** ISO 8859-2 */
	OF_STRING_ENCODING_ISO_8859_2,
	OFStringEncodingISO8859_2,
	/** ISO 8859-3 */
	OF_STRING_ENCODING_ISO_8859_3,
	OFStringEncodingISO8859_3,
	/** ISO 8859-15 */
	OF_STRING_ENCODING_ISO_8859_15,
	OFStringEncodingISO8859_15,
	/** Windows-1251 */
	OF_STRING_ENCODING_WINDOWS_1251,
	OFStringEncodingWindows1251,
	/** Windows-1252 */
	OF_STRING_ENCODING_WINDOWS_1252,
	OFStringEncodingWindows1252,
	/** Codepage 437 */
	OF_STRING_ENCODING_CODEPAGE_437,
	OFStringEncodingCodepage437,
	/** Codepage 850 */
	OF_STRING_ENCODING_CODEPAGE_850,
	OFStringEncodingCodepage850,
	/** Codepage 858 */
	OF_STRING_ENCODING_CODEPAGE_858,
	OFStringEncodingCodepage858,
	/** Mac OS Roman */
	OF_STRING_ENCODING_MAC_ROMAN,
	OFStringEncodingMacRoman,
	/** KOI8-R */
	OF_STRING_ENCODING_KOI8_R,
	OFStringEncodingKOI8R,
	/** KOI8-U */
	OF_STRING_ENCODING_KOI8_U,
	OFStringEncodingKOI8U,
	/** Try to automatically detect the encoding */
	OF_STRING_ENCODING_AUTODETECT = 0xFF
} of_string_encoding_t;
	OFStringEncodingAutodetect = 0xFF
} OFStringEncoding;

/**
 * @brief Options for searching in strings.
 *
 * This is a bit mask.
 */
enum {
	OF_STRING_SEARCH_BACKWARDS = 1,
	OF_STRING_SKIP_EMPTY	   = 2
typedef enum OFStringSearchOptions {
	/** Search backwards in the string */
	OFStringSearchBackwards = 1
} OFStringSearchOptions;

};
/**
 * @brief Options for separating strings.
 *
 * This is a bit mask.
 */
typedef enum OFStringSeparationOptions {
	/** Skip empty components */
	OFStringSkipEmptyComponents = 1
} OFStringSeparationOptions;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block for enumerating the lines of a string.
 *
 * @param line The current line
 * @param stop A pointer to a variable that can be set to true to stop the
 *	       enumeration
 */
typedef void (^of_string_line_enumeration_block_t)(OFString *line, bool *stop);
typedef void (^OFStringLineEnumerationBlock)(OFString *line, bool *stop);
#endif

#ifdef __OBJC__
@class OFArray OF_GENERIC(ObjectType);
@class OFCharacterSet;
@class OFURL;

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







-
+









-
+














-
+







/**
 * @brief The string as an array of Unicode characters.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 */
@property (readonly, nonatomic) const of_unichar_t *characters
@property (readonly, nonatomic) const OFUnichar *characters
    OF_RETURNS_INNER_POINTER;

/**
 * @brief The string in UTF-16 encoding with native byte order.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 */
@property (readonly, nonatomic) const of_char16_t *UTF16String
@property (readonly, nonatomic) const OFChar16 *UTF16String
    OF_RETURNS_INNER_POINTER;

/**
 * @brief The length of the string in UTF-16 characters.
 */
@property (readonly, nonatomic) size_t UTF16StringLength;

/**
 * @brief The string in UTF-32 encoding with native byte order.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 */
@property (readonly, nonatomic) const of_char32_t *UTF32String
@property (readonly, nonatomic) const OFChar32 *UTF32String
    OF_RETURNS_INNER_POINTER;

/**
 * @brief The string with leading whitespaces deleted.
 */
@property (readonly, nonatomic) OFString *stringByDeletingLeadingWhitespaces;

347
348
349
350
351
352
353
354

355
356
357
358
359
360
361
362
363
364
365
366

367
368
369
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
403
404

405
406
407
408
409
410
411
412
413
414

415
416
417
418
419
420
421
422
423
424
425
426


427
428
429
430
431
432
433
434
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
362
363
364
365
366
367
368

369
370
371
372
373
374
375
376
377
378
379
380

381
382
383
384
385
386
387
388
389
390
391

392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
426
427
428

429
430
431
432
433
434
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
506
507
508
509
510
511
512
513







-
+











-
+










-
+

















-
+








-
+









-
+










-
-
+
+











-
+

-
+







-
+









-
+










-
-
+
+











-
+

-
+





-
-
+
+







 * @brief Creates a new OFString from a C string with the specified encoding.
 *
 * @param cString A C string to initialize the OFString with
 * @param encoding The encoding of the C string
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithCString: (const char *)cString
			 encoding: (of_string_encoding_t)encoding;
			 encoding: (OFStringEncoding)encoding;

/**
 * @brief Creates a new OFString from a C string with the specified encoding
 *	  and length.
 *
 * @param cString A C string to initialize the OFString with
 * @param encoding The encoding of the C string
 * @param cStringLength The length of the C string
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithCString: (const char *)cString
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
			   length: (size_t)cStringLength;

/**
 * @brief Creates a new OFString from OFData with the specified encoding.
 *
 * @param data OFData with the contents of the string
 * @param encoding The encoding in which the string is stored in the OFData
 * @return An new autoreleased OFString
 */
+ (instancetype)stringWithData: (OFData *)data
		      encoding: (of_string_encoding_t)encoding;
		      encoding: (OFStringEncoding)encoding;

/**
 * @brief Creates a new OFString from another string.
 *
 * @param string A string to initialize the OFString with
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithString: (OFString *)string;

/**
 * @brief Creates a new OFString from a Unicode string with the specified
 *	  length.
 *
 * @param characters An array of Unicode characters
 * @param length The length of the Unicode character array
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithCharacters: (const of_unichar_t *)characters
+ (instancetype)stringWithCharacters: (const OFUnichar *)characters
			      length: (size_t)length;

/**
 * @brief Creates a new OFString from a UTF-16 encoded string.
 *
 * @param string The UTF-16 string
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF16String: (const of_char16_t *)string;
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string;

/**
 * @brief Creates a new OFString from a UTF-16 encoded string with the
 *	  specified length.
 *
 * @param string The UTF-16 string
 * @param length The length of the UTF-16 string
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
			       length: (size_t)length;

/**
 * @brief Creates a new OFString from a UTF-16 encoded string, assuming the
 *	  specified byte order if no byte order mark is found.
 *
 * @param string The UTF-16 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
			    byteOrder: (of_byte_order_t)byteOrder;
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
			    byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Creates a new OFString from a UTF-16 encoded string with the
 *	  specified length, assuming the specified byte order if no byte order
 *	  mark is found.
 *
 * @param string The UTF-16 string
 * @param length The length of the UTF-16 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)byteOrder;
			    byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Creates a new OFString from a UTF-32 encoded string.
 *
 * @param string The UTF-32 string
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF32String: (const of_char32_t *)string;
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string;

/**
 * @brief Creates a new OFString from a UTF-32 encoded string with the
 *	  specified length.
 *
 * @param string The UTF-32 string
 * @param length The length of the UTF-32 string
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
			       length: (size_t)length;

/**
 * @brief Creates a new OFString from a UTF-32 encoded string, assuming the
 *	  specified byte order if no byte order mark is found.
 *
 * @param string The UTF-32 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
			    byteOrder: (of_byte_order_t)byteOrder;
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
			    byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Creates a new OFString from a UTF-32 encoded string with the
 *	  specified length, assuming the specified byte order if no byte order
 *	  mark is found.
 *
 * @param string The UTF-32 string
 * @param length The length of the UTF-32 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)byteOrder;
			    byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Creates a new OFString from a format string.
 *
 * See printf for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A string used as format to initialize the OFString
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithFormat: (OFConstantString *)format, ...;

# ifdef OF_HAVE_FILES
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







-
+







 *	  specified encoding.
 *
 * @param path The path to the file
 * @param encoding The encoding of the file
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithContentsOfFile: (OFString *)path
				encoding: (of_string_encoding_t)encoding;
				encoding: (OFStringEncoding)encoding;
# endif

/**
 * @brief Creates a new OFString with the contents of the specified URL.
 *
 * If the URL's scheme is file, it tries UTF-8 encoding.
 *
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







-
+







 *	  specified encoding.
 *
 * @param URL The URL to the contents for the string
 * @param encoding The encoding to assume
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithContentsOfURL: (OFURL *)URL
			       encoding: (of_string_encoding_t)encoding;
			       encoding: (OFStringEncoding)encoding;

/**
 * @brief Initializes an already allocated OFString from a UTF-8 encoded C
 *	  string.
 *
 * @param UTF8String A UTF-8 encoded C string to initialize the OFString with
 * @return An initialized OFString
604
605
606
607
608
609
610
611

612
613
614
615
616
617
618
619
620
621
622
623

624
625
626
627
628
629
630
631
632
633
634
635

636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653

654
655
656
657
658
659
660
661
662

663
664
665
666
667
668
669
670
671
672

673
674
675
676
677
678
679
680
681
682
683
684


685
686
687
688
689
690
691
692
693
694
695
696

697
698

699
700
701
702
703
704
705
706

707
708
709
710
711
712
713
714
715
716

717
718
719
720
721
722
723
724
725
726
727
728


729
730
731
732
733
734
735
736
737
738
739
740

741
742

743
744
745
746
747
748
749


750
751
752
753
754
755
756
757
758
759
760
761


762
763
764
765
766
767
768
619
620
621
622
623
624
625

626
627
628
629
630
631
632
633
634
635
636
637

638
639
640
641
642
643
644
645
646
647
648
649

650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667

668
669
670
671
672
673
674
675
676

677
678
679
680
681
682
683
684
685
686

687
688
689
690
691
692
693
694
695
696
697


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

711
712

713
714
715
716
717
718
719
720

721
722
723
724
725
726
727
728
729
730

731
732
733
734
735
736
737
738
739
740
741


742
743
744
745
746
747
748
749
750
751
752
753
754

755
756

757
758
759
760
761
762


763
764
765
766
767
768
769
770
771
772
773
774


775
776
777
778
779
780
781
782
783







-
+











-
+











-
+

















-
+








-
+









-
+










-
-
+
+











-
+

-
+







-
+









-
+










-
-
+
+











-
+

-
+





-
-
+
+










-
-
+
+







 *	  specified encoding.
 *
 * @param cString A C string to initialize the OFString with
 * @param encoding The encoding of the C string
 * @return An initialized OFString
 */
- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding;
		       encoding: (OFStringEncoding)encoding;

/**
 * @brief Initializes an already allocated OFString from a C string with the
 *	  specified encoding and length.
 *
 * @param cString A C string to initialize the OFString with
 * @param encoding The encoding of the C string
 * @param cStringLength The length of the C string
 * @return An initialized OFString
 */
- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)cStringLength;

/**
 * @brief Initializes an already allocated OFString from OFData with the
 *	  specified encoding.
 *
 * @param data OFData with the contents of the string
 * @param encoding The encoding in which the string is stored in the OFData
 * @return An initialized OFString
 */
- (instancetype)initWithData: (OFData *)data
		    encoding: (of_string_encoding_t)encoding;
		    encoding: (OFStringEncoding)encoding;

/**
 * @brief Initializes an already allocated OFString with another string.
 *
 * @param string A string to initialize the OFString with
 * @return An initialized OFString
 */
- (instancetype)initWithString: (OFString *)string;

/**
 * @brief Initializes an already allocated OFString with a Unicode string with
 *	  the specified length.
 *
 * @param characters An array of Unicode characters
 * @param length The length of the Unicode character array
 * @return An initialized OFString
 */
- (instancetype)initWithCharacters: (const of_unichar_t *)characters
- (instancetype)initWithCharacters: (const OFUnichar *)characters
			    length: (size_t)length;

/**
 * @brief Initializes an already allocated OFString with a UTF-16 string.
 *
 * @param string The UTF-16 string
 * @return An initialized OFString
 */
- (instancetype)initWithUTF16String: (const of_char16_t *)string;
- (instancetype)initWithUTF16String: (const OFChar16 *)string;

/**
 * @brief Initializes an already allocated OFString with a UTF-16 string with
 *	  the specified length.
 *
 * @param string The UTF-16 string
 * @param length The length of the UTF-16 string
 * @return An initialized OFString
 */
- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length;

/**
 * @brief Initializes an already allocated OFString with a UTF-16 string,
 *	  assuming the specified byte order if no byte order mark is found.
 *
 * @param string The UTF-16 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return An initialized OFString
 */
- (instancetype)initWithUTF16String: (const of_char16_t *)string
			  byteOrder: (of_byte_order_t)byteOrder;
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			  byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Initializes an already allocated OFString with a UTF-16 string with
 *	  the specified length, assuming the specified byte order if no byte
 *	  order mark is found.
 *
 * @param string The UTF-16 string
 * @param length The length of the UTF-16 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return An initialized OFString
 */
- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder;
			  byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Initializes an already allocated OFString with a UTF-32 string.
 *
 * @param string The UTF-32 string
 * @return An initialized OFString
 */
- (instancetype)initWithUTF32String: (const of_char32_t *)string;
- (instancetype)initWithUTF32String: (const OFChar32 *)string;

/**
 * @brief Initializes an already allocated OFString with a UTF-32 string with
 *	  the specified length
 *
 * @param string The UTF-32 string
 * @param length The length of the UTF-32 string
 * @return An initialized OFString
 */
- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length;

/**
 * @brief Initializes an already allocated OFString with a UTF-32 string,
 *	  assuming the specified byte order if no byte order mark is found.
 *
 * @param string The UTF-32 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return An initialized OFString
 */
- (instancetype)initWithUTF32String: (const of_char32_t *)string
			  byteOrder: (of_byte_order_t)byteOrder;
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			  byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Initializes an already allocated OFString with a UTF-32 string with
 *	  the specified length, assuming the specified byte order if no byte
 *	  order mark is found.
 *
 * @param string The UTF-32 string
 * @param length The length of the UTF-32 string
 * @param byteOrder The byte order to assume if there is no byte order mark
 * @return An initialized OFString
 */
- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder;
			  byteOrder: (OFByteOrder)byteOrder;

/**
 * @brief Initializes an already allocated OFString with a format string.
 *
 * See printf for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A string used as format to initialize the OFString
 * @return An initialized OFString
 */
- (instancetype)initWithFormat: (OFConstantString *)format, ...;

/**
 * @brief Initializes an already allocated OFString with a format string.
 *
 * See printf for the format syntax. As an addition, `%@` is available as
 * format specifier for objects, `%C` for `of_unichar_t` and `%S` for
 * `const of_unichar_t *`.
 * format specifier for objects, `%C` for `OFUnichar` and `%S` for
 * `const OFUnichar *`.
 *
 * @param format A string used as format to initialize the OFString
 * @param arguments The arguments used in the format string
 * @return An initialized OFString
 */
- (instancetype)initWithFormat: (OFConstantString *)format
		     arguments: (va_list)arguments;
782
783
784
785
786
787
788
789

790
791
792
793
794
795
796
797
798
799
800
801
802
803

804
805
806
807
808
809
810
811







-
+







 *	  specified file in the specified encoding.
 *
 * @param path The path to the file
 * @param encoding The encoding of the file
 * @return An initialized OFString
 */
- (instancetype)initWithContentsOfFile: (OFString *)path
			      encoding: (of_string_encoding_t)encoding;
			      encoding: (OFStringEncoding)encoding;
# endif

/**
 * @brief Initializes an already allocated OFString with the contents of the
 *	  specified URL.
 *
 * If the URL's scheme is file, it tries UTF-8 encoding.
809
810
811
812
813
814
815
816

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831

832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847

848
849
850
851
852
853
854
855
856
857
858
859

860
861
862
863
864
865
866
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
882
883
884

885
886
887
888
889
890
891
892

893
894
895
896
897
898
899
900

901
902
903
904
905
906
907
908

909
910
911
912
913
914
915
916
917

918
919
920
921
922
923
924

925
926

927
928
929
930
931
932

933
934
935
936
937
938

939
940


941
942
943
944
945
946

947
948
949
950
951
952
953

954
955
956
957



958
959
960
961
962
963
964

965
966
967
968
969
970
971
972

973
974
975
976
977
978

979
980
981

982
983
984
985
986
987

988
989
990
991
992
993
994

995
996
997
998


999
1000
1001
1002
1003
1004
1005
824
825
826
827
828
829
830

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845

846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861

862
863
864
865
866
867
868
869
870
871
872
873

874
875
876
877
878
879
880
881
882
883
884
885
886
887
888

889
890
891
892
893
894
895
896
897
898

899
900
901
902
903
904
905
906

907
908
909
910
911
912
913
914

915
916
917
918
919
920
921
922

923
924
925
926
927
928
929
930
931

932
933
934
935
936
937
938

939
940

941
942
943
944
945
946

947




948

949
950

951
952
953
954
955
956
957

958




959
960

961
962



963
964
965
966
967
968
969
970
971

972
973
974
975
976
977
978
979

980




981

982
983
984

985
986
987
988
989
990

991




992
993

994
995
996


997
998
999
1000
1001
1002
1003
1004
1005







-
+














-
+















-
+











-
+














-
+









-
+







-
+







-
+







-
+








-
+






-
+

-
+





-
+
-
-
-
-

-
+

-
+
+





-
+
-
-
-
-


-
+

-
-
-
+
+
+






-
+







-
+
-
-
-
-

-
+


-
+





-
+
-
-
-
-


-
+


-
-
+
+







 *	  specified URL in the specified encoding.
 *
 * @param URL The URL to the contents for the string
 * @param encoding The encoding to assume
 * @return An initialized OFString
 */
- (instancetype)initWithContentsOfURL: (OFURL *)URL
			     encoding: (of_string_encoding_t)encoding;
			     encoding: (OFStringEncoding)encoding;

/**
 * @brief Writes the OFString into the specified C string with the specified
 *	  encoding.
 *
 * @param cString The C string to write into
 * @param maxLength The maximum number of bytes to write into the C string,
 *		    including the terminating zero
 * @param encoding The encoding to use for writing into the C string
 * @return The number of bytes written into the C string, without the
 *	   terminating zero
 */
- (size_t)getCString: (char *)cString
	   maxLength: (size_t)maxLength
	    encoding: (of_string_encoding_t)encoding;
	    encoding: (OFStringEncoding)encoding;

/**
 * @brief Writes the OFString into the specified C string with the specified
 *	  encoding, replacing characters that cannot be represented in the
 *	  specified encoding with a question mark.
 *
 * @param cString The C string to write into
 * @param maxLength The maximum number of bytes to write into the C string,
 *		    including the terminating zero
 * @param encoding The encoding to use for writing into the C string
 * @return The number of bytes written into the C string, without the
 *	   terminating zero
 */
- (size_t)getLossyCString: (char *)cString
		maxLength: (size_t)maxLength
		 encoding: (of_string_encoding_t)encoding;
		 encoding: (OFStringEncoding)encoding;

/**
 * @brief Returns the OFString as a C string in the specified encoding.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 *
 * @param encoding The encoding for the C string
 * @return The OFString as a C string in the specified encoding
 */
- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)cStringWithEncoding: (OFStringEncoding)encoding
    OF_RETURNS_INNER_POINTER;

/**
 * @brief Returns the OFString as a C string in the specified encoding,
 *	  replacing characters that cannot be represented in the specified
 *	  encoding with a question mark.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 *
 * @param encoding The encoding for the C string
 * @return The OFString as a C string in the specified encoding
 */
- (const char *)lossyCStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding
    OF_RETURNS_INNER_POINTER;

/**
 * @brief Returns the number of bytes the string needs in the specified
 *	  encoding.
 *
 * @param encoding The encoding for the string
 * @return The number of bytes the string needs in the specified encoding.
 */
- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding;
- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding;

/**
 * @brief Compares the string to another string.
 *
 * @param string The string to compare the string to
 * @return The result of the comparison
 */
- (of_comparison_result_t)compare: (OFString *)string;
- (OFComparisonResult)compare: (OFString *)string;

/**
 * @brief Compares the string to another string without caring about the case.
 *
 * @param string The string to compare the string to
 * @return The result of the comparison
 */
- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)string;
- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string;

/**
 * @brief Returns the Unicode character at the specified index.
 *
 * @param index The index of the Unicode character to return
 * @return The Unicode character at the specified index
 */
- (of_unichar_t)characterAtIndex: (size_t)index;
- (OFUnichar)characterAtIndex: (size_t)index;

/**
 * @brief Copies the Unicode characters in the specified range to the specified
 *	  buffer.
 *
 * @param buffer The buffer to store the Unicode characters
 * @param range The range of the Unicode characters to copy
 */
- (void)getCharacters: (of_unichar_t *)buffer inRange: (of_range_t)range;
- (void)getCharacters: (OFUnichar *)buffer inRange: (OFRange)range;

/**
 * @brief Returns the range of the first occurrence of the string.
 *
 * @param string The string to search
 * @return The range of the first occurrence of the string or a range with
 *	   `OF_NOT_FOUND` as start position if it was not found
 *	   `OFNotFound` as start position if it was not found
 */
- (of_range_t)rangeOfString: (OFString *)string;
- (OFRange)rangeOfString: (OFString *)string;

/**
 * @brief Returns the range of the string.
 *
 * @param string The string to search
 * @param options Options modifying search behavior.@n
 * @param options Options modifying search behavior
 *		  Possible values are:
 *		  Value                        | Description
 *		  -----------------------------|-------------------------------
 *		  `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string
 * @return The range of the first occurrence of the string or a range with
 *	   `OF_NOT_FOUND` as start position if it was not found
 *	   `OFNotFound` as start position if it was not found
 */
- (of_range_t)rangeOfString: (OFString *)string options: (int)options;
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options;

/**
 * @brief Returns the range of the string in the specified range.
 *
 * @param string The string to search
 * @param options Options modifying search behaviour.@n
 * @param options Options modifying search behaviour
 *		  Possible values are:
 *		  Value                        | Description
 *		  -----------------------------|-------------------------------
 *		  `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string
 * @param range The range in which to search
 * @return The range of the first occurrence of the string or a range with
 *	   `OF_NOT_FOUND` as start position if it was not found
 *	   `OFNotFound` as start position if it was not found
 */
- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
		      range: (of_range_t)range;
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options
		   range: (OFRange)range;

/**
 * @brief Returns the index of the first character from the set.
 *
 * @param characterSet The set of characters to search for
 * @return The index of the first occurrence of a character from the set or
 *	   `OF_NOT_FOUND` if it was not found
 *	   `OFNotFound` if it was not found
 */
- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet;

/**
 * @brief Returns the index of the first character from the set.
 *
 * @param characterSet The set of characters to search for
 * @param options Options modifying search behaviour.@n
 * @param options Options modifying search behaviour
 *		  Possible values are:
 *		  Value                        | Description
 *		  -----------------------------|-------------------------------
 *		  `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string
 * @return The index of the first occurrence of a character from the set or
 *	   `OF_NOT_FOUND` if it was not found
 *	   `OFNotFound` if it was not found
 */
- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options;
			  options: (OFStringSearchOptions)options;

/**
 * @brief Returns the index of the first character from the set.
 *
 * @param characterSet The set of characters to search for
 * @param options Options modifying search behaviour.@n
 * @param options Options modifying search behaviour
 *		  Possible values are:
 *		  Value                        | Description
 *		  -----------------------------|-------------------------------
 *		  `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string
 * @param range The range in which to search
 * @return The index of the first occurrence of a character from the set or
 *	   `OF_NOT_FOUND` if it was not found
 *	   `OFNotFound` if it was not found
 */
- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
			    range: (of_range_t)range;
			  options: (OFStringSearchOptions)options
			    range: (OFRange)range;

/**
 * @brief Returns whether the string contains the specified string.
 *
 * @param string The string to search
 * @return Whether the string contains the specified string
 */
1023
1024
1025
1026
1027
1028
1029
1030

1031
1032
1033
1034
1035
1036
1037
1023
1024
1025
1026
1027
1028
1029

1030
1031
1032
1033
1034
1035
1036
1037







-
+








/**
 * @brief Creates a substring with the specified range.
 *
 * @param range The range of the substring
 * @return The substring as a new autoreleased OFString
 */
- (OFString *)substringWithRange: (of_range_t)range;
- (OFString *)substringWithRange: (OFRange)range;

/**
 * @brief The value of the string in the specified base as a `long long`.
 *
 * Leading and trailing whitespaces are ignored.
 *
 * If the string contains any non-number characters, an
1124
1125
1126
1127
1128
1129
1130
1131

1132
1133
1134
1135
1136
1137
1138
1124
1125
1126
1127
1128
1129
1130

1131
1132
1133
1134
1135
1136
1137
1138







-
+







 *		    * None yet
 * @param range The range in which to replace the string
 * @return A new string with the occurrences of the specified string replaced
 */
- (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string
					withString: (OFString *)replacement
					   options: (int)options
					     range: (of_range_t)range;
					     range: (OFRange)range;

/**
 * @brief Checks whether the string has the specified prefix.
 *
 * @param prefix The prefix to check for
 * @return A boolean whether the string has the specified prefix
 */
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
1220
1221
1222
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
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266

1267
1268
1269
1270
1271
1272
1273
1274

1275
1276
1277
1278
1279
1280
1281











1282
1283
1284
1285
1286
1287













1288
1289
1290
1291
1292
1293
1294
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
1220
1221
1222
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
1255
1256
1257

1258
1259
1260
1261
1262
1263
1264
1265

1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284






1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304







-
+
-
-
-
-




-
+
















-
+
-
-
-
-




-
+











-
+












-
+








-
+
















-
+















-
+







-
+







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







    componentsSeparatedByString: (OFString *)delimiter;

/**
 * @brief Separates the string into an array of strings, split by the specified
 *	  delimiter.
 *
 * @param delimiter The delimiter for separating
 * @param options Options according to which the string should be separated.@n
 * @param options Options according to which the string should be separated
 *		  Possible values are:
 *		  Value                  | Description
 *		  -----------------------|----------------------
 * 		  `OF_STRING_SKIP_EMPTY` | Skip empty components
 * @return An autoreleased OFArray with the separated string
 */
- (OFArray OF_GENERIC(OFString *) *)
    componentsSeparatedByString: (OFString *)delimiter
			options: (int)options;
			options: (OFStringSeparationOptions)options;

/**
 * @brief Separates the string into an array of strings, split by characters in
 *	  the specified set.
 *
 * @param characterSet The character set for separating
 * @return An autoreleased OFArray with the separated string
 */
- (OFArray OF_GENERIC(OFString *) *)
    componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet;

/**
 * @brief Separates the string into an array of strings, split by characters in
 *	  the specified set.
 *
 * @param characterSet The character set for separating
 * @param options Options according to which the string should be separated.@n
 * @param options Options according to which the string should be separated
 *		  Possible values are:
 *		  Value                  | Description
 *		  -----------------------|----------------------
 * 		  `OF_STRING_SKIP_EMPTY` | Skip empty components
 * @return An autoreleased OFArray with the separated string
 */
- (OFArray OF_GENERIC(OFString *) *)
    componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet
				 options: (int)options;
				 options: (OFStringSeparationOptions)options;

/**
 * @brief Returns the string in UTF-16 encoding with the specified byte order.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 *
 * @param byteOrder The byte order for the UTF-16 encoding
 * @return The string in UTF-16 encoding with the specified byte order
 */
- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder
- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder
    OF_RETURNS_INNER_POINTER;

/**
 * @brief Returns the string in UTF-32 encoding with the specified byte order.
 *
 * The result is valid until the autorelease pool is released. If you want to
 * use the result outside the scope of the current autorelease pool, you have to
 * copy it.
 *
 * @param byteOrder The byte order for the UTF-32 encoding
 * @return The string in UTF-32 encoding with the specified byte order
 */
- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder
    OF_RETURNS_INNER_POINTER;

/**
 * @brief Returns the string as OFData with the specified encoding.
 *
 * @param encoding The encoding to use for the returned OFData
 * @return The string as OFData with the specified encoding
 */
- (OFData *)dataWithEncoding: (of_string_encoding_t)encoding;
- (OFData *)dataWithEncoding: (OFStringEncoding)encoding;

# ifdef OF_HAVE_FILES
/**
 * @brief Writes the string into the specified file using UTF-8 encoding.
 *
 * @param path The path of the file to write to
 */
- (void)writeToFile: (OFString *)path;

/**
 * @brief Writes the string into the specified file using the specified
 *	  encoding.
 *
 * @param path The path of the file to write to
 * @param encoding The encoding to use to write the string into the file
 */
- (void)writeToFile: (OFString *)path encoding: (of_string_encoding_t)encoding;
- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding;
# endif

/**
 * @brief Writes the string to the specified URL using UTF-8 encoding.
 *
 * @param URL The URL to write to
 */
- (void)writeToURL: (OFURL *)URL;

/**
 * @brief Writes the string to the specified URL using the specified encoding.
 *
 * @param URL The URL to write to
 * @param encoding The encoding to use to write the string to the URL
 */
- (void)writeToURL: (OFURL *)URL encoding: (of_string_encoding_t)encoding;
- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding;

# ifdef OF_HAVE_BLOCKS
/**
 * Enumerates all lines in the receiver using the specified block.
 *
 * @brief block The block to call for each line
 */
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block;
- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block;
# endif
@end
#endif

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief Parses the specified string encoding name and returns the
 *	  OFStringEncoding for it.
 *
 * Throws @ref OFInvalidArgumentException if the specified name is not a valid
 * encoding name.
 *
 * @param name The name to parse as a string encoding
 * @return The OFStringEncoding for the specified name
 */
extern OFStringEncoding OFParseStringEncodingName(OFString *name);
extern of_string_encoding_t of_string_parse_encoding(OFString *);
extern OFString *_Nullable of_string_name_of_encoding(of_string_encoding_t);
extern size_t of_string_utf8_encode(of_unichar_t, char *);
extern ssize_t of_string_utf8_decode(const char *, size_t, of_unichar_t *);
extern size_t of_string_utf16_length(const of_char16_t *);
extern size_t of_string_utf32_length(const of_char32_t *);

/**
 * @brief Returns the name of the specified OFStringEncoding.
 *
 * @param encoding The encoding for which to return the name
 * @return The name of the specified OFStringEncoding
 */
extern OFString *_Nullable OFStringEncodingName(OFStringEncoding encoding);

extern size_t of_string_utf8_encode(OFUnichar, char *);
extern ssize_t of_string_utf8_decode(const char *, size_t, OFUnichar *);
extern size_t of_string_utf16_length(const OFChar16 *);
extern size_t of_string_utf32_length(const OFChar32 *);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

#include "OFConstantString.h"

Modified src/OFString.m from [858181ff3a] to [8bdf1a14a9].

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







-
+

-
+








-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+







#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L)
static locale_t cLocale;
#endif

@interface OFString ()
- (size_t)of_getCString: (char *)cString
	      maxLength: (size_t)maxLength
	       encoding: (of_string_encoding_t)encoding
	       encoding: (OFStringEncoding)encoding
		  lossy: (bool)lossy OF_DIRECT;
- (const char *)of_cStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)of_cStringWithEncoding: (OFStringEncoding)encoding
				 lossy: (bool)lossy OF_DIRECT;
- (OFString *)of_JSONRepresentationWithOptions: (int)options
					 depth: (size_t)depth;
@end

@interface OFStringPlaceholder: OFString
@end

extern bool of_unicode_to_iso_8859_2(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_iso_8859_2(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_iso_8859_3(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_iso_8859_3(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_iso_8859_15(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_iso_8859_15(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_windows_1251(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_windows_1251(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_windows_1252(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_windows_1252(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_codepage_437(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_codepage_437(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_codepage_850(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_codepage_850(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_codepage_858(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_codepage_858(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_mac_roman(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_mac_roman(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_koi8_r(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_koi8_r(const OFUnichar *, unsigned char *,
    size_t, bool);
extern bool of_unicode_to_koi8_u(const of_unichar_t *, unsigned char *,
extern bool of_unicode_to_koi8_u(const OFUnichar *, unsigned char *,
    size_t, bool);

/* References for static linking */
void
_references_to_categories_of_OFString(void)
{
	_OFString_CryptographicHashing_reference = 1;
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
238
239
240
241
242
243

244
245
246
247
248
249
250
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
238
239
240
241
242

243
244
245
246
247
248
249
250







-
-
+
+


-
+




-
+

-
+


-
+


-
+


-
+


-
+



-
+



-
+


-
+


-
+


-
+

-
+

-
+

-
+









-
+


-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+







-
+








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

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

	string = string.lowercaseString;

	if ([string isEqual: @"utf8"] || [string isEqual: @"utf-8"])
		encoding = OF_STRING_ENCODING_UTF_8;
		encoding = OFStringEncodingUTF8;
	else if ([string isEqual: @"ascii"] || [string isEqual: @"us-ascii"])
		encoding = OF_STRING_ENCODING_ASCII;
		encoding = OFStringEncodingASCII;
	else if ([string isEqual: @"iso-8859-1"] ||
	    [string isEqual: @"iso_8859-1"])
		encoding = OF_STRING_ENCODING_ISO_8859_1;
		encoding = OFStringEncodingISO8859_1;
	else if ([string isEqual: @"iso-8859-2"] ||
	    [string isEqual: @"iso_8859-2"])
		encoding = OF_STRING_ENCODING_ISO_8859_2;
		encoding = OFStringEncodingISO8859_2;
	else if ([string isEqual: @"iso-8859-3"] ||
	    [string isEqual: @"iso_8859-3"])
		encoding = OF_STRING_ENCODING_ISO_8859_3;
		encoding = OFStringEncodingISO8859_3;
	else if ([string isEqual: @"iso-8859-15"] ||
	    [string isEqual: @"iso_8859-15"])
		encoding = OF_STRING_ENCODING_ISO_8859_15;
		encoding = OFStringEncodingISO8859_15;
	else if ([string isEqual: @"windows-1251"] ||
	    [string isEqual: @"cp1251"] || [string isEqual: @"cp-1251"] ||
	    [string isEqual: @"1251"])
		encoding = OF_STRING_ENCODING_WINDOWS_1251;
		encoding = OFStringEncodingWindows1251;
	else if ([string isEqual: @"windows-1252"] ||
	    [string isEqual: @"cp1252"] || [string isEqual: @"cp-1252"] ||
	    [string isEqual: @"1252"])
		encoding = OF_STRING_ENCODING_WINDOWS_1252;
		encoding = OFStringEncodingWindows1252;
	else if ([string isEqual: @"cp437"] || [string isEqual: @"cp-437"] ||
	    [string isEqual: @"ibm437"] || [string isEqual: @"437"])
		encoding = OF_STRING_ENCODING_CODEPAGE_437;
		encoding = OFStringEncodingCodepage437;
	else if ([string isEqual: @"cp850"] || [string isEqual: @"cp-850"] ||
	    [string isEqual: @"ibm850"] || [string isEqual: @"850"])
		encoding = OF_STRING_ENCODING_CODEPAGE_850;
		encoding = OFStringEncodingCodepage850;
	else if ([string isEqual: @"cp858"] || [string isEqual: @"cp-858"] ||
	    [string isEqual: @"ibm858"] || [string isEqual: @"858"])
		encoding = OF_STRING_ENCODING_CODEPAGE_858;
		encoding = OFStringEncodingCodepage858;
	else if ([string isEqual: @"macintosh"] || [string isEqual: @"mac"])
		encoding = OF_STRING_ENCODING_MAC_ROMAN;
		encoding = OFStringEncodingMacRoman;
	else if ([string isEqual: @"koi8-r"])
		encoding = OF_STRING_ENCODING_KOI8_R;
		encoding = OFStringEncodingKOI8R;
	else if ([string isEqual: @"koi8-u"])
		encoding = OF_STRING_ENCODING_KOI8_U;
		encoding = OFStringEncodingKOI8U;
	else
		@throw [OFInvalidArgumentException exception];

	objc_autoreleasePoolPop(pool);

	return encoding;
}

OFString *
of_string_name_of_encoding(of_string_encoding_t encoding)
OFStringEncodingName(OFStringEncoding encoding)
{
	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:
	case OFStringEncodingUTF8:
		return @"UTF-8";
	case OF_STRING_ENCODING_ASCII:
	case OFStringEncodingASCII:
		return @"ASCII";
	case OF_STRING_ENCODING_ISO_8859_1:
	case OFStringEncodingISO8859_1:
		return @"ISO 8859-1";
	case OF_STRING_ENCODING_ISO_8859_2:
	case OFStringEncodingISO8859_2:
		return @"ISO 8859-2";
	case OF_STRING_ENCODING_ISO_8859_3:
	case OFStringEncodingISO8859_3:
		return @"ISO 8859-3";
	case OF_STRING_ENCODING_ISO_8859_15:
	case OFStringEncodingISO8859_15:
		return @"ISO 8859-15";
	case OF_STRING_ENCODING_WINDOWS_1251:
	case OFStringEncodingWindows1251:
		return @"Windows-1251";
	case OF_STRING_ENCODING_WINDOWS_1252:
	case OFStringEncodingWindows1252:
		return @"Windows-1252";
	case OF_STRING_ENCODING_CODEPAGE_437:
	case OFStringEncodingCodepage437:
		return @"Codepage 437";
	case OF_STRING_ENCODING_CODEPAGE_850:
	case OFStringEncodingCodepage850:
		return @"Codepage 850";
	case OF_STRING_ENCODING_CODEPAGE_858:
	case OFStringEncodingCodepage858:
		return @"Codepage 858";
	case OF_STRING_ENCODING_MAC_ROMAN:
	case OFStringEncodingMacRoman:
		return @"Mac Roman";
	case OF_STRING_ENCODING_KOI8_R:
	case OFStringEncodingKOI8R:
		return @"KOI8-R";
	case OF_STRING_ENCODING_KOI8_U:
	case OFStringEncodingKOI8U:
		return @"KOI8-U";
	case OF_STRING_ENCODING_AUTODETECT:
	case OFStringEncodingAutodetect:
		return @"autodetect";
	}

	return nil;
}

size_t
of_string_utf8_encode(of_unichar_t character, char *buffer)
of_string_utf8_encode(OFUnichar character, char *buffer)
{
	if (character < 0x80) {
		buffer[0] = character;
		return 1;
	} else if (character < 0x800) {
		buffer[0] = 0xC0 | (character >> 6);
		buffer[1] = 0x80 | (character & 0x3F);
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276







-
+







		return 4;
	}

	return 0;
}

ssize_t
of_string_utf8_decode(const char *buffer_, size_t length, of_unichar_t *ret)
of_string_utf8_decode(const char *buffer_, size_t length, OFUnichar *ret)
{
	const unsigned char *buffer = (const unsigned char *)buffer_;

	if (!(*buffer & 0x80)) {
		*ret = buffer[0];
		return 1;
	}
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
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







-
+










-
+















-
+



-
+







		return 4;
	}

	return 0;
}

size_t
of_string_utf16_length(const of_char16_t *string)
of_string_utf16_length(const OFChar16 *string)
{
	size_t length = 0;

	while (*string++ != 0)
		length++;

	return length;
}

size_t
of_string_utf32_length(const of_char32_t *string)
of_string_utf32_length(const OFChar32 *string)
{
	size_t length = 0;

	while (*string++ != 0)
		length++;

	return length;
}

#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;
	const OFUnichar *characters = self.characters;
	size_t length = self.length;

	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = characters[i];
		OFUnichar c = characters[i];
		const char *const *page;

		if (c >= size) {
			[ret appendCharacters: &c length: 1];
			continue;
		}

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

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







-
+

-
+


















-
+


-
+

















-
+










-
+






-
+




-
+






-
-
+
+





-
+

-
+






-
+




-
+






-
-
+
+





-
+

-
+







	return (id)[[OFUTF8String alloc]
	    initWithUTF8StringNoCopy: UTF8String
			      length: UTF8StringLength
			freeWhenDone: freeWhenDone];
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
{
	if (encoding == OF_STRING_ENCODING_UTF_8) {
	if (encoding == OFStringEncodingUTF8) {
		OFUTF8String *string;
		size_t length;
		void *storage;

		length = strlen(cString);
		string = of_alloc_object([OFUTF8String class], length + 1, 1,
		    &storage);

		return (id)[string of_initWithUTF8String: cString
						  length: length
						 storage: storage];
	}

	return (id)[[OFUTF8String alloc] initWithCString: cString
						encoding: encoding];
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)cStringLength
{
	if (encoding == OF_STRING_ENCODING_UTF_8) {
	if (encoding == OFStringEncodingUTF8) {
		OFUTF8String *string;
		void *storage;

		string = of_alloc_object([OFUTF8String class],
		    cStringLength + 1, 1, &storage);

		return (id)[string of_initWithUTF8String: cString
						  length: cStringLength
						 storage: storage];
	}

	return (id)[[OFUTF8String alloc] initWithCString: cString
						encoding: encoding
						  length: cStringLength];
}

- (instancetype)initWithData: (OFData *)data
		    encoding: (of_string_encoding_t)encoding
		    encoding: (OFStringEncoding)encoding
{
	return (id)[[OFUTF8String alloc] initWithData: data
					     encoding: encoding];
}

- (instancetype)initWithString: (OFString *)string
{
	return (id)[[OFUTF8String alloc] initWithString: string];
}

- (instancetype)initWithCharacters: (const of_unichar_t *)string
- (instancetype)initWithCharacters: (const OFUnichar *)string
			    length: (size_t)length
{
	return (id)[[OFUTF8String alloc] initWithCharacters: string
						     length: length];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
{
	return (id)[[OFUTF8String alloc] initWithUTF16String: string];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
{
	return (id)[[OFUTF8String alloc] initWithUTF16String: string
						      length: length];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
			  byteOrder: (of_byte_order_t)byteOrder
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFUTF8String alloc] initWithUTF16String: string
						   byteOrder: byteOrder];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFUTF8String alloc] initWithUTF16String: string
						      length: length
						   byteOrder: byteOrder];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
{
	return (id)[[OFUTF8String alloc] initWithUTF32String: string];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
{
	return (id)[[OFUTF8String alloc] initWithUTF32String: string
						      length: length];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
			  byteOrder: (of_byte_order_t)byteOrder
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFUTF8String alloc] initWithUTF32String: string
						   byteOrder: byteOrder];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	return (id)[[OFUTF8String alloc] initWithUTF32String: string
						      length: length
						   byteOrder: byteOrder];
}

- (instancetype)initWithFormat: (OFConstantString *)format, ...
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
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







-
+












-
+







#ifdef OF_HAVE_FILES
- (instancetype)initWithContentsOfFile: (OFString *)path
{
	return (id)[[OFUTF8String alloc] initWithContentsOfFile: path];
}

- (instancetype)initWithContentsOfFile: (OFString *)path
			      encoding: (of_string_encoding_t)encoding
			      encoding: (OFStringEncoding)encoding
{
	return (id)[[OFUTF8String alloc] initWithContentsOfFile: path
						       encoding: encoding];
}
#endif

- (instancetype)initWithContentsOfURL: (OFURL *)URL
{
	return (id)[[OFUTF8String alloc] initWithContentsOfURL: URL];
}

- (instancetype)initWithContentsOfURL: (OFURL *)URL
			     encoding: (of_string_encoding_t)encoding
			     encoding: (OFStringEncoding)encoding
{
	return (id)[[OFUTF8String alloc] initWithContentsOfURL: URL
						      encoding: encoding];
}

- (instancetype)initWithSerialization: (OFXMLElement *)element
{
664
665
666
667
668
669
670
671

672
673
674
675
676
677
678

679
680
681
682
683
684
685
686
687

688
689
690
691
692
693
694
695
696
697
698

699
700
701
702
703
704
705

706
707
708
709
710

711
712
713
714
715
716
717
718


719
720
721
722
723
724

725
726

727
728
729
730
731
732
733

734
735
736
737
738

739
740
741
742
743
744
745
746


747
748
749
750
751
752

753
754

755
756
757
758
759
760
761
664
665
666
667
668
669
670

671
672
673
674
675
676
677

678
679
680
681
682
683
684
685
686

687
688
689
690
691
692
693
694
695
696
697

698
699
700
701
702
703
704

705
706
707
708
709

710
711
712
713
714
715
716


717
718
719
720
721
722
723

724
725

726
727
728
729
730
731
732

733
734
735
736
737

738
739
740
741
742
743
744


745
746
747
748
749
750
751

752
753

754
755
756
757
758
759
760
761







-
+






-
+








-
+










-
+






-
+




-
+






-
-
+
+





-
+

-
+






-
+




-
+






-
-
+
+





-
+

-
+







	return [[[self alloc]
	    initWithUTF8StringNoCopy: UTF8String
			      length: UTF8StringLength
			freeWhenDone: freeWhenDone] autorelease];
}

+ (instancetype)stringWithCString: (const char *)cString
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithCString: cString
				     encoding: encoding] autorelease];
}

+ (instancetype)stringWithCString: (const char *)cString
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
			   length: (size_t)cStringLength
{
	return [[[self alloc] initWithCString: cString
				     encoding: encoding
				       length: cStringLength] autorelease];
}

+ (instancetype)stringWithData: (OFData *)data
		      encoding: (of_string_encoding_t)encoding
		      encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithData: data
				  encoding: encoding] autorelease];
}

+ (instancetype)stringWithString: (OFString *)string
{
	return [[[self alloc] initWithString: string] autorelease];
}

+ (instancetype)stringWithCharacters: (const of_unichar_t *)string
+ (instancetype)stringWithCharacters: (const OFUnichar *)string
			      length: (size_t)length
{
	return [[[self alloc] initWithCharacters: string
					  length: length] autorelease];
}

+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
{
	return [[[self alloc] initWithUTF16String: string] autorelease];
}

+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
			       length: (size_t)length
{
	return [[[self alloc] initWithUTF16String: string
					   length: length] autorelease];
}

+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
			    byteOrder: (of_byte_order_t)byteOrder
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
			    byteOrder: (OFByteOrder)byteOrder
{
	return [[[self alloc] initWithUTF16String: string
					byteOrder: byteOrder] autorelease];
}

+ (instancetype)stringWithUTF16String: (const of_char16_t *)string
+ (instancetype)stringWithUTF16String: (const OFChar16 *)string
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)byteOrder
			    byteOrder: (OFByteOrder)byteOrder
{
	return [[[self alloc] initWithUTF16String: string
					   length: length
					byteOrder: byteOrder] autorelease];
}

+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
{
	return [[[self alloc] initWithUTF32String: string] autorelease];
}

+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
			       length: (size_t)length
{
	return [[[self alloc] initWithUTF32String: string
					   length: length] autorelease];
}

+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
			    byteOrder: (of_byte_order_t)byteOrder
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
			    byteOrder: (OFByteOrder)byteOrder
{
	return [[[self alloc] initWithUTF32String: string
					byteOrder: byteOrder] autorelease];
}

+ (instancetype)stringWithUTF32String: (const of_char32_t *)string
+ (instancetype)stringWithUTF32String: (const OFChar32 *)string
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)byteOrder
			    byteOrder: (OFByteOrder)byteOrder
{
	return [[[self alloc] initWithUTF32String: string
					   length: length
					byteOrder: byteOrder] autorelease];
}

+ (instancetype)stringWithFormat: (OFConstantString *)format, ...
774
775
776
777
778
779
780
781

782
783
784
785
786
787
788
789
790
791
792
793
794

795
796
797
798
799
800
801
774
775
776
777
778
779
780

781
782
783
784
785
786
787
788
789
790
791
792
793

794
795
796
797
798
799
800
801







-
+












-
+







#ifdef OF_HAVE_FILES
+ (instancetype)stringWithContentsOfFile: (OFString *)path
{
	return [[[self alloc] initWithContentsOfFile: path] autorelease];
}

+ (instancetype)stringWithContentsOfFile: (OFString *)path
				encoding: (of_string_encoding_t)encoding
				encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithContentsOfFile: path
					    encoding: encoding] autorelease];
}
#endif

+ (instancetype)stringWithContentsOfURL: (OFURL *)URL
{
	return [[[self alloc] initWithContentsOfURL: URL] autorelease];
}

+ (instancetype)stringWithContentsOfURL: (OFURL *)URL
			       encoding: (of_string_encoding_t)encoding
			       encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithContentsOfURL: URL
					   encoding: encoding] autorelease];
}

- (instancetype)init
{
812
813
814
815
816
817
818
819

820
821
822
823
824
825
826
827

828
829
830
831
832
833
834
812
813
814
815
816
817
818

819
820
821
822
823
824
825
826

827
828
829
830
831
832
833
834







-
+







-
+








	return [super init];
}

- (instancetype)initWithUTF8String: (const char *)UTF8String
{
	return [self initWithCString: UTF8String
			    encoding: OF_STRING_ENCODING_UTF_8
			    encoding: OFStringEncodingUTF8
			      length: strlen(UTF8String)];
}

- (instancetype)initWithUTF8String: (const char *)UTF8String
			    length: (size_t)UTF8StringLength
{
	return [self initWithCString: UTF8String
			    encoding: OF_STRING_ENCODING_UTF_8
			    encoding: OFStringEncodingUTF8
			      length: UTF8StringLength];
}

- (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String
			    freeWhenDone: (bool)freeWhenDone
{
	id ret = [self initWithUTF8String: UTF8String];
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
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







-
+







-
+






-
+







	if (freeWhenDone)
		free(UTF8String);

	return ret;
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
{
	return [self initWithCString: cString
			    encoding: encoding
			      length: strlen(cString)];
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)cStringLength
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithData: (OFData *)data
		    encoding: (of_string_encoding_t)encoding
		    encoding: (OFStringEncoding)encoding
{
	@try {
		if (data.itemSize != 1)
			@throw [OFInvalidArgumentException exception];
	} @catch (id e) {
		[self release];
		@throw e;
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
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







-
+





-
+



-
+


-
+




-
+


-
-
+
+






-
+

-
+




-
+



-
+


-
+




-
+


-
-
+
+






-
+

-
+







}

- (instancetype)initWithString: (OFString *)string
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithCharacters: (const of_unichar_t *)string
- (instancetype)initWithCharacters: (const OFUnichar *)string
			    length: (size_t)length
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
{
	return [self initWithUTF16String: string
				  length: of_string_utf16_length(string)
			       byteOrder: OF_BYTE_ORDER_NATIVE];
			       byteOrder: OFByteOrderNative];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
{
	return [self initWithUTF16String: string
				  length: length
			       byteOrder: OF_BYTE_ORDER_NATIVE];
			       byteOrder: OFByteOrderNative];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
			  byteOrder: (of_byte_order_t)byteOrder
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			  byteOrder: (OFByteOrder)byteOrder
{
	return [self initWithUTF16String: string
				  length: of_string_utf16_length(string)
			       byteOrder: byteOrder];
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
{
	return [self initWithUTF32String: string
				  length: of_string_utf32_length(string)
			       byteOrder: OF_BYTE_ORDER_NATIVE];
			       byteOrder: OFByteOrderNative];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
{
	return [self initWithUTF32String: string
				  length: length
			       byteOrder: OF_BYTE_ORDER_NATIVE];
			       byteOrder: OFByteOrderNative];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
			  byteOrder: (of_byte_order_t)byteOrder
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			  byteOrder: (OFByteOrder)byteOrder
{
	return [self initWithUTF32String: string
				  length: of_string_utf32_length(string)
			       byteOrder: byteOrder];
}

- (instancetype)initWithUTF32String: (const of_char32_t *)string
- (instancetype)initWithUTF32String: (const OFChar32 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithFormat: (OFConstantString *)format, ...
{
	id ret;
973
974
975
976
977
978
979
980

981
982
983
984

985
986
987
988
989
990
991
973
974
975
976
977
978
979

980
981
982
983

984
985
986
987
988
989
990
991







-
+



-
+







	OF_INVALID_INIT_METHOD
}

#ifdef OF_HAVE_FILES
- (instancetype)initWithContentsOfFile: (OFString *)path
{
	return [self initWithContentsOfFile: path
				   encoding: OF_STRING_ENCODING_UTF_8];
				   encoding: OFStringEncodingUTF8];
}

- (instancetype)initWithContentsOfFile: (OFString *)path
			      encoding: (of_string_encoding_t)encoding
			      encoding: (OFStringEncoding)encoding
{
	char *tmp;
	unsigned long long fileSize;

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFFile *file = nil;
1028
1029
1030
1031
1032
1033
1034
1035

1036
1037
1038
1039
1040
1041
1042
1028
1029
1030
1031
1032
1033
1034

1035
1036
1037
1038
1039
1040
1041
1042







-
+








		tmp[(size_t)fileSize] = '\0';
	} @catch (id e) {
		[self release];
		@throw e;
	}

	if (encoding == OF_STRING_ENCODING_UTF_8) {
	if (encoding == OFStringEncodingUTF8) {
		@try {
			self = [self initWithUTF8StringNoCopy: tmp
						       length: (size_t)fileSize
						 freeWhenDone: true];
		} @catch (id e) {
			free(tmp);
			@throw e;
1054
1055
1056
1057
1058
1059
1060
1061

1062
1063
1064
1065

1066
1067
1068
1069
1070
1071
1072
1054
1055
1056
1057
1058
1059
1060

1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
1072







-
+



-
+







	return self;
}
#endif

- (instancetype)initWithContentsOfURL: (OFURL *)URL
{
	return [self initWithContentsOfURL: URL
				  encoding: OF_STRING_ENCODING_AUTODETECT];
				  encoding: OFStringEncodingAutodetect];
}

- (instancetype)initWithContentsOfURL: (OFURL *)URL
			     encoding: (of_string_encoding_t)encoding
			     encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFData *data;

	@try {
		data = [OFData dataWithContentsOfURL: URL];
	} @catch (id e) {
1111
1112
1113
1114
1115
1116
1117
1118

1119
1120
1121

1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
1111
1112
1113
1114
1115
1116
1117

1118
1119
1120

1121
1122
1123
1124

1125
1126
1127
1128
1129
1130
1131
1132







-
+


-
+



-
+







	objc_autoreleasePoolPop(pool);

	return self;
}

- (size_t)of_getCString: (char *)cString
	      maxLength: (size_t)maxLength
	       encoding: (of_string_encoding_t)encoding
	       encoding: (OFStringEncoding)encoding
		  lossy: (bool)lossy
{
	const of_unichar_t *characters = self.characters;
	const OFUnichar *characters = self.characters;
	size_t i, length = self.length;

	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:;
	case OFStringEncodingUTF8:;
		size_t j = 0;

		for (i = 0; i < length; i++) {
			char buffer[4];
			size_t len = of_string_utf8_encode(characters[i],
			    buffer);

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
1220
1221
1222
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
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264

1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277

1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
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
1323
1324
1325
1326
1327
1328
1329

1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349

1350
1351
1352
1353
1354
1355
1356
1357
1358
1359

1360
1361
1362
1363
1364
1365
1366
1367

1368
1369
1370
1371
1372
1373
1374
1375

1376
1377
1378
1379
1380
1381
1382

1383
1384
1385
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
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
1220
1221
1222
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
1255
1256
1257
1258
1259
1260
1261
1262
1263

1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276

1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
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
1323
1324
1325
1326
1327
1328

1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348

1349
1350
1351
1352
1353
1354
1355
1356
1357
1358

1359
1360
1361
1362
1363
1364
1365
1366

1367
1368
1369
1370
1371
1372
1373
1374

1375
1376
1377
1378
1379
1380
1381

1382
1383
1384
1385
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







-
+

















-
+


















-
+












-
+












-
+












-
+












-
+












-
+












-
+












-
+












-
+












-
+












-
+



















-
+









-
+







-
+







-
+






-
+













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







				break;
			}
		}

		cString[j] = '\0';

		return j;
	case OF_STRING_ENCODING_ASCII:
	case OFStringEncodingASCII:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		for (i = 0; i < length; i++) {
			if OF_UNLIKELY (characters[i] > 0x80) {
				if (lossy)
					cString[i] = '?';
				else
					@throw [OFInvalidEncodingException
					    exception];
			} else
				cString[i] = (unsigned char)characters[i];
		}

		cString[i] = '\0';

		return length;
	case OF_STRING_ENCODING_ISO_8859_1:
	case OFStringEncodingISO8859_1:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		for (i = 0; i < length; i++) {
			if OF_UNLIKELY (characters[i] > 0xFF) {
				if (lossy)
					cString[i] = '?';
				else
					@throw [OFInvalidEncodingException
					    exception];
			} else
				cString[i] = (unsigned char)characters[i];
		}

		cString[i] = '\0';

		return length;
#ifdef HAVE_ISO_8859_2
	case OF_STRING_ENCODING_ISO_8859_2:
	case OFStringEncodingISO8859_2:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_iso_8859_2(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_ISO_8859_3
	case OF_STRING_ENCODING_ISO_8859_3:
	case OFStringEncodingISO8859_3:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_iso_8859_3(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_ISO_8859_15
	case OF_STRING_ENCODING_ISO_8859_15:
	case OFStringEncodingISO8859_15:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_iso_8859_15(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_WINDOWS_1251
	case OF_STRING_ENCODING_WINDOWS_1251:
	case OFStringEncodingWindows1251:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_windows_1251(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_WINDOWS_1252
	case OF_STRING_ENCODING_WINDOWS_1252:
	case OFStringEncodingWindows1252:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_windows_1252(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_CODEPAGE_437
	case OF_STRING_ENCODING_CODEPAGE_437:
	case OFStringEncodingCodepage437:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_codepage_437(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_CODEPAGE_850
	case OF_STRING_ENCODING_CODEPAGE_850:
	case OFStringEncodingCodepage850:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_codepage_850(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_CODEPAGE_858
	case OF_STRING_ENCODING_CODEPAGE_858:
	case OFStringEncodingCodepage858:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_codepage_858(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_MAC_ROMAN
	case OF_STRING_ENCODING_MAC_ROMAN:
	case OFStringEncodingMacRoman:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_mac_roman(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_KOI8_R
	case OF_STRING_ENCODING_KOI8_R:
	case OFStringEncodingKOI8R:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_koi8_r(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
#ifdef HAVE_KOI8_U
	case OF_STRING_ENCODING_KOI8_U:
	case OFStringEncodingKOI8U:
		if (length + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		if (!of_unicode_to_koi8_u(characters,
		    (unsigned char *)cString, length, lossy))
			@throw [OFInvalidEncodingException exception];

		cString[length] = '\0';

		return length;
#endif
	default:
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];
	}
}

- (size_t)getCString: (char *)cString
	   maxLength: (size_t)maxLength
	    encoding: (of_string_encoding_t)encoding
	    encoding: (OFStringEncoding)encoding
{
	return [self of_getCString: cString
			 maxLength: maxLength
			  encoding: encoding
			     lossy: false];
}

- (size_t)getLossyCString: (char *)cString
		maxLength: (size_t)maxLength
		 encoding: (of_string_encoding_t)encoding
		 encoding: (OFStringEncoding)encoding
{
	return [self of_getCString: cString
			 maxLength: maxLength
			  encoding: encoding
			     lossy: true];
}

- (const char *)of_cStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)of_cStringWithEncoding: (OFStringEncoding)encoding
				 lossy: (bool)lossy
{
	size_t length = self.length;
	char *cString;
	size_t cStringLength;

	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:
	case OFStringEncodingUTF8:
		cString = of_alloc((length * 4) + 1, 1);

		@try {
			cStringLength = [self
			    of_getCString: cString
				maxLength: (length * 4) + 1
				 encoding: OF_STRING_ENCODING_UTF_8
				 encoding: OFStringEncodingUTF8
				    lossy: lossy];
		} @catch (id e) {
			free(cString);
			@throw e;
		}

		@try {
			cString = of_realloc(cString, cStringLength + 1, 1);
		} @catch (OFOutOfMemoryException *e) {
			/* We don't care, as we only tried to make it smaller */
		}

		break;
	case OF_STRING_ENCODING_ASCII:
	case OF_STRING_ENCODING_ISO_8859_1:
	case OF_STRING_ENCODING_ISO_8859_2:
	case OF_STRING_ENCODING_ISO_8859_3:
	case OF_STRING_ENCODING_ISO_8859_15:
	case OF_STRING_ENCODING_WINDOWS_1251:
	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:
	case OFStringEncodingASCII:
	case OFStringEncodingISO8859_1:
	case OFStringEncodingISO8859_2:
	case OFStringEncodingISO8859_3:
	case OFStringEncodingISO8859_15:
	case OFStringEncodingWindows1251:
	case OFStringEncodingWindows1252:
	case OFStringEncodingCodepage437:
	case OFStringEncodingCodepage850:
	case OFStringEncodingCodepage858:
	case OFStringEncodingMacRoman:
	case OFStringEncodingKOI8R:
	case OFStringEncodingKOI8U:
		cString = of_alloc(length + 1, 1);

		@try {
			cStringLength = [self of_getCString: cString
						  maxLength: length + 1
						   encoding: encoding
						      lossy: lossy];
1429
1430
1431
1432
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
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490













1491
1492
1493
1494
1495
1496
1497
1498
1499

1500
1501
1502

1503
1504
1505
1506
1507
1508


1509
1510
1511
1512
1513
1514
1515
1516
1517
1518

1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539

1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
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
1616
1617
1618
1619


1620
1621
1622
1623

1624
1625
1626
1627
1628
1629
1630

1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643

1644
1645
1646
1647

1648
1649
1650
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
1677
1429
1430
1431
1432
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
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477













1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498

1499
1500
1501

1502
1503
1504
1505
1506


1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517

1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538

1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558

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


1618
1619
1620
1621
1622

1623
1624
1625
1626
1627
1628
1629

1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642

1643
1644
1645
1646

1647
1648
1649
1650
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
1677







-
+




-
+






-
+







-
+


-
-
+
+

















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








-
+


-
+




-
-
+
+









-
+




















-
+



















-
+


-
+



-
+















-
+




-
+






-
+

-
+

-
+


-
+


-
+



-
+









-
-
+
+



-
+






-
+












-
+



-
+






-
+

-
+

-
+




-
+






-
+







				       freeWhenDone: true] items];
	} @catch (id e) {
		free(cString);
		@throw e;
	}
}

- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)cStringWithEncoding: (OFStringEncoding)encoding
{
	return [self of_cStringWithEncoding: encoding lossy: false];
}

- (const char *)lossyCStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding
{
	return [self of_cStringWithEncoding: encoding lossy: true];
}

- (const char *)UTF8String
{
	return [self cStringWithEncoding: OF_STRING_ENCODING_UTF_8];
	return [self cStringWithEncoding: OFStringEncodingUTF8];
}

- (size_t)length
{
	OF_UNRECOGNIZED_SELECTOR
}

- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding
- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding
{
	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:;
		const of_unichar_t *characters;
	case OFStringEncodingUTF8:;
		const OFUnichar *characters;
		size_t length, UTF8StringLength = 0;

		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)
				@throw [OFInvalidEncodingException exception];

			UTF8StringLength += len;
		}

		return UTF8StringLength;
	case OF_STRING_ENCODING_ASCII:
	case OF_STRING_ENCODING_ISO_8859_1:
	case OF_STRING_ENCODING_ISO_8859_2:
	case OF_STRING_ENCODING_ISO_8859_3:
	case OF_STRING_ENCODING_ISO_8859_15:
	case OF_STRING_ENCODING_WINDOWS_1251:
	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:
	case OFStringEncodingASCII:
	case OFStringEncodingISO8859_1:
	case OFStringEncodingISO8859_2:
	case OFStringEncodingISO8859_3:
	case OFStringEncodingISO8859_15:
	case OFStringEncodingWindows1251:
	case OFStringEncodingWindows1252:
	case OFStringEncodingCodepage437:
	case OFStringEncodingCodepage850:
	case OFStringEncodingCodepage858:
	case OFStringEncodingMacRoman:
	case OFStringEncodingKOI8R:
	case OFStringEncodingKOI8U:
		return self.length;
	default:
		@throw [OFInvalidEncodingException exception];
	}
}

- (size_t)UTF8StringLength
{
	return [self cStringLengthWithEncoding: OF_STRING_ENCODING_UTF_8];
	return [self cStringLengthWithEncoding: OFStringEncodingUTF8];
}

- (of_unichar_t)characterAtIndex: (size_t)idx
- (OFUnichar)characterAtIndex: (size_t)idx
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)getCharacters: (of_unichar_t *)buffer
	      inRange: (of_range_t)range
- (void)getCharacters: (OFUnichar *)buffer
	      inRange: (OFRange)range
{
	for (size_t i = 0; i < range.length; i++)
		buffer[i] = [self characterAtIndex: range.location + i];
}

- (bool)isEqual: (id)object
{
	void *pool;
	OFString *string;
	const of_unichar_t *characters, *otherCharacters;
	const OFUnichar *characters, *otherCharacters;
	size_t length;

	if (object == self)
		return true;

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

	string = object;
	length = self.length;

	if (string.length != length)
		return false;

	pool = objc_autoreleasePoolPush();

	characters = self.characters;
	otherCharacters = string.characters;

	if (memcmp(characters, otherCharacters,
	    length * sizeof(of_unichar_t)) != 0) {
	    length * sizeof(OFUnichar)) != 0) {
		objc_autoreleasePoolPop(pool);
		return false;
	}

	objc_autoreleasePoolPop(pool);

	return true;
}

- (id)copy
{
	return [self retain];
}

- (id)mutableCopy
{
	return [[OFMutableString alloc] initWithString: self];
}

- (of_comparison_result_t)compare: (OFString *)string
- (OFComparisonResult)compare: (OFString *)string
{
	void *pool;
	const of_unichar_t *characters, *otherCharacters;
	const OFUnichar *characters, *otherCharacters;
	size_t minimumLength;

	if (string == self)
		return OF_ORDERED_SAME;
		return OFOrderedSame;

	if (![string isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];

	minimumLength = (self.length > string.length
	    ? string.length : self.length);

	pool = objc_autoreleasePoolPush();

	characters = self.characters;
	otherCharacters = string.characters;

	for (size_t i = 0; i < minimumLength; i++) {
		if (characters[i] > otherCharacters[i]) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		}

		if (characters[i] < otherCharacters[i]) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;
		}
	}

	objc_autoreleasePoolPop(pool);

	if (self.length > string.length)
		return OF_ORDERED_DESCENDING;
		return OFOrderedDescending;
	if (self.length < string.length)
		return OF_ORDERED_ASCENDING;
		return OFOrderedAscending;

	return OF_ORDERED_SAME;
	return OFOrderedSame;
}

- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)string
- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters, *otherCharacters;
	const OFUnichar *characters, *otherCharacters;
	size_t length, otherLength, minimumLength;

	if (string == self)
		return OF_ORDERED_SAME;
		return OFOrderedSame;

	characters = self.characters;
	otherCharacters = string.characters;
	length = self.length;
	otherLength = string.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];
		OFUnichar c = characters[i];
		OFUnichar oc = otherCharacters[i];

#ifdef OF_HAVE_UNICODE_TABLES
		if (c >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) {
			of_unichar_t tc =
			OFUnichar tc =
			    of_unicode_casefolding_table[c >> 8][c & 0xFF];

			if (tc)
				c = tc;
		}
		if (oc >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) {
			of_unichar_t tc =
			OFUnichar tc =
			    of_unicode_casefolding_table[oc >> 8][oc & 0xFF];

			if (tc)
				oc = tc;
		}
#else
		c = of_ascii_toupper(c);
		oc = of_ascii_toupper(oc);
#endif

		if (c > oc) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		}
		if (c < oc) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;
		}
	}

	objc_autoreleasePoolPop(pool);

	if (length > otherLength)
		return OF_ORDERED_DESCENDING;
		return OFOrderedDescending;
	if (length < otherLength)
		return OF_ORDERED_ASCENDING;
		return OFOrderedAscending;

	return OF_ORDERED_SAME;
	return OFOrderedSame;
}

- (unsigned long)hash
{
	const of_unichar_t *characters = self.characters;
	const OFUnichar *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];
		const OFUnichar 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_FINALIZE(hash);
1794
1795
1796
1797
1798
1799
1800
1801

1802
1803
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
1860

1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871

1872
1873
1874
1875
1876
1877
1878

1879
1880
1881
1882

1883
1884
1885
1886

1887
1888
1889
1890
1891


1892
1893
1894


1895
1896

1897
1898
1899

1900
1901

1902
1903
1904

1905
1906
1907
1908

1909
1910
1911
1912
1913
1914
1915
1794
1795
1796
1797
1798
1799
1800

1801
1802
1803
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
1860

1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871

1872
1873
1874
1875
1876
1877
1878

1879
1880
1881
1882

1883
1884
1885
1886

1887
1888
1889
1890


1891
1892
1893


1894
1895
1896

1897
1898
1899

1900
1901

1902
1903
1904

1905
1906
1907
1908

1909
1910
1911
1912
1913
1914
1915
1916







-
+



-
+


-
+
+



-
+


-
-
-
+
+
+


-
-
+
+



-
+


-
+

-
+






-
+



-
+


-
+

-
+











-
+

-
+










-
+






-
+



-
+



-
+



-
-
+
+

-
-
+
+

-
+


-
+

-
+


-
+



-
+







		@throw [OFOutOfRangeException exception];

	[data addItems: self.UTF8String count: length];

	return data;
}

- (of_range_t)rangeOfString: (OFString *)string
- (OFRange)rangeOfString: (OFString *)string
{
	return [self rangeOfString: string
			   options: 0
			     range: of_range(0, self.length)];
			     range: OFMakeRange(0, self.length)];
}

- (of_range_t)rangeOfString: (OFString *)string options: (int)options
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options
{
	return [self rangeOfString: string
			   options: options
			     range: of_range(0, self.length)];
			     range: OFMakeRange(0, self.length)];
}

- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
		      range: (of_range_t)range
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options
		   range: (OFRange)range
{
	void *pool;
	const of_unichar_t *searchCharacters;
	of_unichar_t *characters;
	const OFUnichar *searchCharacters;
	OFUnichar *characters;
	size_t searchLength;

	if ((searchLength = string.length) == 0)
		return of_range(0, 0);
		return OFMakeRange(0, 0);

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

	if (range.length > SIZE_MAX / sizeof(of_unichar_t))
	if (range.length > SIZE_MAX / sizeof(OFUnichar))
		@throw [OFOutOfRangeException exception];

	pool = objc_autoreleasePoolPush();

	searchCharacters = string.characters;

	characters = of_alloc(range.length, sizeof(of_unichar_t));
	characters = of_alloc(range.length, sizeof(OFUnichar));
	@try {
		[self getCharacters: characters inRange: range];

		if (options & OF_STRING_SEARCH_BACKWARDS) {
		if (options & OFStringSearchBackwards) {
			for (size_t i = range.length - searchLength;; i--) {
				if (memcmp(characters + i, searchCharacters,
				    searchLength * sizeof(of_unichar_t)) == 0) {
				    searchLength * sizeof(OFUnichar)) == 0) {
					objc_autoreleasePoolPop(pool);
					return of_range(range.location + i,
					return OFMakeRange(range.location + i,
					    searchLength);
				}

				/* No match and we're at the last character */
				if (i == 0)
					break;
			}
		} else {
			for (size_t i = 0;
			    i <= range.length - searchLength; i++) {
				if (memcmp(characters + i, searchCharacters,
				    searchLength * sizeof(of_unichar_t)) == 0) {
				    searchLength * sizeof(OFUnichar)) == 0) {
					objc_autoreleasePoolPop(pool);
					return of_range(range.location + i,
					return OFMakeRange(range.location + i,
					    searchLength);
				}
			}
		}
	} @finally {
		free(characters);
	}

	objc_autoreleasePoolPop(pool);

	return of_range(OF_NOT_FOUND, 0);
	return OFMakeRange(OFNotFound, 0);
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
{
	return [self indexOfCharacterFromSet: characterSet
				     options: 0
				       range: of_range(0, self.length)];
				       range: OFMakeRange(0, self.length)];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
			  options: (OFStringSearchOptions)options
{
	return [self indexOfCharacterFromSet: characterSet
				     options: options
				       range: of_range(0, self.length)];
				       range: OFMakeRange(0, self.length)];
}

- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet
			  options: (int)options
			    range: (of_range_t)range
			  options: (OFStringSearchOptions)options
			    range: (OFRange)range
{
	bool (*characterIsMember)(id, SEL, of_unichar_t) =
	    (bool (*)(id, SEL, of_unichar_t))[characterSet
	bool (*characterIsMember)(id, SEL, OFUnichar) =
	    (bool (*)(id, SEL, OFUnichar))[characterSet
	    methodForSelector: @selector(characterIsMember:)];
	of_unichar_t *characters;
	OFUnichar *characters;

	if (range.length == 0)
		return OF_NOT_FOUND;
		return OFNotFound;

	if (range.length > SIZE_MAX / sizeof(of_unichar_t))
	if (range.length > SIZE_MAX / sizeof(OFUnichar))
		@throw [OFOutOfRangeException exception];

	characters = of_alloc(range.length, sizeof(of_unichar_t));
	characters = of_alloc(range.length, sizeof(OFUnichar));
	@try {
		[self getCharacters: characters inRange: range];

		if (options & OF_STRING_SEARCH_BACKWARDS) {
		if (options & OFStringSearchBackwards) {
			for (size_t i = range.length - 1;; i--) {
				if (characterIsMember(characterSet,
				    @selector(characterIsMember:),
				    characters[i]))
					return range.location + i;

				/* No match and we're at the last character */
1923
1924
1925
1926
1927
1928
1929
1930

1931
1932
1933
1934
1935
1936

1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952

1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965

1966
1967
1968
1969
1970

1971
1972
1973

1974
1975
1976
1977
1978
1979
1980
1924
1925
1926
1927
1928
1929
1930

1931
1932
1933
1934
1935
1936

1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952

1953
1954
1955
1956
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







-
+





-
+















-
+












-
+




-
+


-
+







				    characters[i]))
					return range.location + i;
		}
	} @finally {
		free(characters);
	}

	return OF_NOT_FOUND;
	return OFNotFound;
}

- (bool)containsString: (OFString *)string
{
	void *pool;
	const of_unichar_t *characters, *searchCharacters;
	const OFUnichar *characters, *searchCharacters;
	size_t length, searchLength;

	if ((searchLength = string.length) == 0)
		return true;

	if (searchLength > (length = self.length))
		return false;

	pool = objc_autoreleasePoolPush();

	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) {
		    searchLength * sizeof(OFUnichar)) == 0) {
			objc_autoreleasePoolPop(pool);
			return true;
		}
	}

	objc_autoreleasePoolPop(pool);

	return false;
}

- (OFString *)substringFromIndex: (size_t)idx
{
	return [self substringWithRange: of_range(idx, self.length - idx)];
	return [self substringWithRange: OFMakeRange(idx, self.length - idx)];
}

- (OFString *)substringToIndex: (size_t)idx
{
	return [self substringWithRange: of_range(0, idx)];
	return [self substringWithRange: OFMakeRange(0, idx)];
}

- (OFString *)substringWithRange: (of_range_t)range
- (OFString *)substringWithRange: (OFRange)range
{
	void *pool;
	OFString *ret;

	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > self.length)
		@throw [OFOutOfRangeException exception];
2037
2038
2039
2040
2041
2042
2043
2044

2045
2046
2047
2048
2049
2050
2051
2038
2039
2040
2041
2042
2043
2044

2045
2046
2047
2048
2049
2050
2051
2052







-
+







	[new makeImmutable];
	return new;
}

- (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string
					withString: (OFString *)replacement
					   options: (int)options
					     range: (of_range_t)range
					     range: (OFRange)range
{
	OFMutableString *new = [[self mutableCopy] autorelease];
	[new replaceOccurrencesOfString: string
			     withString: replacement
				options: options
				  range: range];
	[new makeImmutable];
2098
2099
2100
2101
2102
2103
2104
2105

2106
2107
2108
2109
2110
2111
2112

2113
2114
2115
2116

2117
2118
2119

2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132


2133
2134
2135
2136
2137
2138
2139
2140
2141

2142
2143
2144
2145
2146

2147
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
2099
2100
2101
2102
2103
2104
2105

2106
2107
2108
2109
2110
2111
2112

2113
2114
2115
2116

2117
2118
2119

2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131


2132
2133
2134
2135
2136
2137
2138
2139
2140
2141

2142
2143
2144
2145
2146

2147
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







-
+






-
+



-
+


-
+











-
-
+
+








-
+




-
+




-
+















-
+



-
-
+
+







	[new deleteEnclosingWhitespaces];
	[new makeImmutable];
	return new;
}

- (bool)hasPrefix: (OFString *)prefix
{
	of_unichar_t *tmp;
	OFUnichar *tmp;
	size_t prefixLength;
	bool hasPrefix;

	if ((prefixLength = prefix.length) > self.length)
		return false;

	tmp = of_alloc(prefixLength, sizeof(of_unichar_t));
	tmp = of_alloc(prefixLength, sizeof(OFUnichar));
	@try {
		void *pool = objc_autoreleasePoolPush();

		[self getCharacters: tmp inRange: of_range(0, prefixLength)];
		[self getCharacters: tmp inRange: OFMakeRange(0, prefixLength)];

		hasPrefix = (memcmp(tmp, prefix.characters,
		    prefixLength * sizeof(of_unichar_t)) == 0);
		    prefixLength * sizeof(OFUnichar)) == 0);

		objc_autoreleasePoolPop(pool);
	} @finally {
		free(tmp);
	}

	return hasPrefix;
}

- (bool)hasSuffix: (OFString *)suffix
{
	of_unichar_t *tmp;
	const of_unichar_t *suffixCharacters;
	OFUnichar *tmp;
	const OFUnichar *suffixCharacters;
	size_t length, suffixLength;
	bool hasSuffix;

	if ((suffixLength = suffix.length) > self.length)
		return false;

	length = self.length;

	tmp = of_alloc(suffixLength, sizeof(of_unichar_t));
	tmp = of_alloc(suffixLength, sizeof(OFUnichar));
	@try {
		void *pool = objc_autoreleasePoolPush();

		[self getCharacters: tmp
			    inRange: of_range(length - suffixLength,
			    inRange: OFMakeRange(length - suffixLength,
					 suffixLength)];

		suffixCharacters = suffix.characters;
		hasSuffix = (memcmp(tmp, suffixCharacters,
		    suffixLength * sizeof(of_unichar_t)) == 0);
		    suffixLength * sizeof(OFUnichar)) == 0);

		objc_autoreleasePoolPop(pool);
	} @finally {
		free(tmp);
	}

	return hasSuffix;
}

- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
{
	return [self componentsSeparatedByString: delimiter options: 0];
}

- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
				 options: (int)options
				 options: (OFStringSeparationOptions)options
{
	void *pool;
	OFMutableArray *array;
	const of_unichar_t *characters, *delimiterCharacters;
	bool skipEmpty = (options & OF_STRING_SKIP_EMPTY);
	const OFUnichar *characters, *delimiterCharacters;
	bool skipEmpty = (options & OFStringSkipEmptyComponents);
	size_t length = self.length;
	size_t delimiterLength = delimiter.length;
	size_t last;
	OFString *component;

	if (delimiter == nil)
		@throw [OFInvalidArgumentException exception];
2195
2196
2197
2198
2199
2200
2201
2202

2203
2204
2205


2206
2207
2208
2209
2210
2211
2212

2213
2214
2215
2216
2217
2218
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
2196
2197
2198
2199
2200
2201
2202

2203
2204
2205

2206
2207
2208
2209
2210
2211
2212
2213

2214
2215
2216
2217
2218
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
2267
2268







-
+


-
+
+






-
+



















-
+



-
-
+
+

-
-
+
+









-
+








-
+








		return array;
	}

	last = 0;
	for (size_t i = 0; i <= length - delimiterLength; i++) {
		if (memcmp(characters + i, delimiterCharacters,
		    delimiterLength * sizeof(of_unichar_t)) != 0)
		    delimiterLength * sizeof(OFUnichar)) != 0)
			continue;

		component = [self substringWithRange: of_range(last, i - last)];
		component = [self substringWithRange:
		    OFMakeRange(last, i - last)];
		if (!skipEmpty || component.length > 0)
			[array addObject: component];

		i += delimiterLength - 1;
		last = i + 1;
	}
	component = [self substringWithRange: of_range(last, length - last)];
	component = [self substringWithRange: OFMakeRange(last, length - last)];
	if (!skipEmpty || component.length > 0)
		[array addObject: component];

	[array makeImmutable];

	objc_autoreleasePoolPop(pool);

	return array;
}

- (OFArray *)
    componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet
{
	return [self componentsSeparatedByCharactersInSet: characterSet
						  options: 0];
}

- (OFArray *)
   componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet
				options: (int)options
				options: (OFStringSeparationOptions)options
{
	OFMutableArray *array = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();
	bool skipEmpty = (options & OF_STRING_SKIP_EMPTY);
	const of_unichar_t *characters = self.characters;
	bool skipEmpty = (options & OFStringSkipEmptyComponents);
	const OFUnichar *characters = self.characters;
	size_t length = self.length;
	bool (*characterIsMember)(id, SEL, of_unichar_t) =
	    (bool (*)(id, SEL, of_unichar_t))[characterSet
	bool (*characterIsMember)(id, SEL, OFUnichar) =
	    (bool (*)(id, SEL, OFUnichar))[characterSet
	    methodForSelector: @selector(characterIsMember:)];
	size_t last;

	last = 0;
	for (size_t i = 0; i < length; i++) {
		if (characterIsMember(characterSet,
		    @selector(characterIsMember:), characters[i])) {
			if (!skipEmpty || i != last) {
				OFString *component = [self substringWithRange:
				    of_range(last, i - last)];
				    OFMakeRange(last, i - last)];
				[array addObject: component];
			}

			last = i + 1;
		}
	}
	if (!skipEmpty || length != last) {
		OFString *component = [self substringWithRange:
		    of_range(last, length - last)];
		    OFMakeRange(last, length - last)];
		[array addObject: component];
	}

	[array makeImmutable];

	objc_autoreleasePoolPop(pool);

2417
2418
2419
2420
2421
2422
2423
2424
2425


2426
2427
2428


2429
2430

2431
2432

2433
2434
2435
2436
2437
2438
2439
2419
2420
2421
2422
2423
2424
2425


2426
2427
2428


2429
2430
2431

2432
2433

2434
2435
2436
2437
2438
2439
2440
2441







-
-
+
+

-
-
+
+

-
+

-
+







}

- (float)floatValue
{
	void *pool = objc_autoreleasePoolPush();
	OFString *stripped = self.stringByDeletingEnclosingWhitespaces;

	if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"INF"] == OFOrderedSame ||
	    [stripped caseInsensitiveCompare: @"INFINITY"] == OFOrderedSame)
		return INFINITY;
	if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"-INF"] == OFOrderedSame ||
	    [stripped caseInsensitiveCompare: @"-INFINITY"] == OFOrderedSame)
		return -INFINITY;
	if ([stripped caseInsensitiveCompare: @"NAN"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"NAN"] == OFOrderedSame)
		return NAN;
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame)
		return -NAN;

#ifdef HAVE_STRTOF_L
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtof_l, we have no other choice but to replace "."
2470
2471
2472
2473
2474
2475
2476
2477
2478


2479
2480
2481


2482
2483

2484
2485

2486
2487
2488
2489
2490
2491
2492
2472
2473
2474
2475
2476
2477
2478


2479
2480
2481


2482
2483
2484

2485
2486

2487
2488
2489
2490
2491
2492
2493
2494







-
-
+
+

-
-
+
+

-
+

-
+







}

- (double)doubleValue
{
	void *pool = objc_autoreleasePoolPush();
	OFString *stripped = self.stringByDeletingEnclosingWhitespaces;

	if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"INF"] == OFOrderedSame ||
	    [stripped caseInsensitiveCompare: @"INFINITY"] == OFOrderedSame)
		return INFINITY;
	if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME ||
	    [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"-INF"] == OFOrderedSame ||
	    [stripped caseInsensitiveCompare: @"-INFINITY"] == OFOrderedSame)
		return -INFINITY;
	if ([stripped caseInsensitiveCompare: @"NAN"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"NAN"] == OFOrderedSame)
		return NAN;
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OF_ORDERED_SAME)
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame)
		return -NAN;

#ifdef HAVE_STRTOD_L
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtod_l, we have no other choice but to replace "."
2518
2519
2520
2521
2522
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
2558
2559

2560
2561
2562
2563

2564
2565
2566
2567
2568
2569
2570
2520
2521
2522
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

2558
2559
2560

2561
2562
2563
2564

2565
2566
2567
2568
2569
2570
2571
2572







-
+


-
+

-
+

-
+



-
+







-
+

-
+


-
+


-
+

-
+

-
+


-
+



-
+







				@throw [OFInvalidFormatException exception];

	objc_autoreleasePoolPop(pool);

	return value;
}

- (const of_unichar_t *)characters
- (const OFUnichar *)characters
{
	size_t length = self.length;
	of_unichar_t *buffer;
	OFUnichar *buffer;

	buffer = of_alloc(length, sizeof(of_unichar_t));
	buffer = of_alloc(length, sizeof(OFUnichar));
	@try {
		[self getCharacters: buffer inRange: of_range(0, length)];
		[self getCharacters: buffer inRange: OFMakeRange(0, length)];

		return [[OFData dataWithItemsNoCopy: buffer
					      count: length
					   itemSize: sizeof(of_unichar_t)
					   itemSize: sizeof(OFUnichar)
				       freeWhenDone: true] items];
	} @catch (id e) {
		free(buffer);
		@throw e;
	}
}

- (const of_char16_t *)UTF16String
- (const OFChar16 *)UTF16String
{
	return [self UTF16StringWithByteOrder: OF_BYTE_ORDER_NATIVE];
	return [self UTF16StringWithByteOrder: OFByteOrderNative];
}

- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder
- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *characters = self.characters;
	size_t length = self.length;
	of_char16_t *buffer;
	OFChar16 *buffer;
	size_t j;
	bool swap = (byteOrder != OF_BYTE_ORDER_NATIVE);
	bool swap = (byteOrder != OFByteOrderNative);

	/* Allocate memory for the worst case */
	buffer = of_alloc((length + 1) * 2, sizeof(of_char16_t));
	buffer = of_alloc((length + 1) * 2, sizeof(OFChar16));

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

		if (c > 0x10FFFF) {
			free(buffer);
			@throw [OFInvalidEncodingException exception];
		}

		if (swap) {
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
2609

2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621

2622
2623

2624
2625
2626

2627
2628
2629

2630
2631

2632
2633

2634
2635
2636

2637
2638
2639
2640
2641
2642

2643
2644
2645
2646
2647
2648
2649
2650

2651
2652
2653
2654
2655
2656
2657
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
2609
2610

2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622

2623
2624

2625
2626
2627

2628
2629
2630

2631
2632

2633
2634

2635
2636
2637

2638
2639
2640
2641
2642
2643

2644
2645
2646
2647
2648
2649
2650
2651

2652
2653
2654
2655
2656
2657
2658
2659







-
+









-
+









-
+











-
+

-
+


-
+


-
+

-
+

-
+


-
+





-
+







-
+







			} else
				buffer[j++] = c;
		}
	}
	buffer[j] = 0;

	@try {
		buffer = of_realloc(buffer, j + 1, sizeof(of_char16_t));
		buffer = of_realloc(buffer, j + 1, sizeof(OFChar16));
	} @catch (OFOutOfMemoryException *e) {
		/* We don't care, as we only tried to make it smaller */
	}

	objc_autoreleasePoolPop(pool);

	@try {
		return [[OFData dataWithItemsNoCopy: buffer
					      count: j + 1
					   itemSize: sizeof(of_char16_t)
					   itemSize: sizeof(OFChar16)
				       freeWhenDone: true] items];
	} @catch (id e) {
		free(buffer);
		@throw e;
	}
}

- (size_t)UTF16StringLength
{
	const of_unichar_t *characters = self.characters;
	const OFUnichar *characters = self.characters;
	size_t length, UTF16StringLength;

	length = UTF16StringLength = self.length;

	for (size_t i = 0; i < length; i++)
		if (characters[i] > 0xFFFF)
			UTF16StringLength++;

	return UTF16StringLength;
}

- (const of_char32_t *)UTF32String
- (const OFChar32 *)UTF32String
{
	return [self UTF32StringWithByteOrder: OF_BYTE_ORDER_NATIVE];
	return [self UTF32StringWithByteOrder: OFByteOrderNative];
}

- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder
{
	size_t length = self.length;
	of_char32_t *buffer;
	OFChar32 *buffer;

	buffer = of_alloc(length + 1, sizeof(of_char32_t));
	buffer = of_alloc(length + 1, sizeof(OFChar32));
	@try {
		[self getCharacters: buffer inRange: of_range(0, length)];
		[self getCharacters: buffer inRange: OFMakeRange(0, length)];
		buffer[length] = 0;

		if (byteOrder != OF_BYTE_ORDER_NATIVE)
		if (byteOrder != OFByteOrderNative)
			for (size_t i = 0; i < length; i++)
				buffer[i] = OF_BSWAP32(buffer[i]);

		return [[OFData dataWithItemsNoCopy: buffer
					      count: length + 1
					   itemSize: sizeof(of_char32_t)
					   itemSize: sizeof(OFChar32)
				       freeWhenDone: true] items];
	} @catch (id e) {
		free(buffer);
		@throw e;
	}
}

- (OFData *)dataWithEncoding: (of_string_encoding_t)encoding
- (OFData *)dataWithEncoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFData *data =
	    [OFData dataWithItems: [self cStringWithEncoding: encoding]
			    count: [self cStringLengthWithEncoding: encoding]];

	[data retain];
2685
2686
2687
2688
2689
2690
2691
2692

2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711

2712
2713
2714

2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725

2726
2727
2728

2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744

2745
2746
2747

2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763

2764
2765
2766
2767
2768
2769
2770
2771
2772
2773

2774
2775
2776
2777
2778
2779
2687
2688
2689
2690
2691
2692
2693

2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712

2713
2714
2715

2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726

2727
2728
2729

2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745

2746
2747
2748

2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764

2765
2766
2767
2768
2769
2770
2771
2772
2773
2774

2775
2776
2777
2778
2779
2780
2781







-
+


















-
+


-
+










-
+


-
+















-
+


-
+















-
+









-
+






		if ((length = ExpandEnvironmentStringsW(self.UTF16String,
		    buffer, sizeof(buffer))) == 0)
			return self;

		return [OFString stringWithUTF16String: buffer
						length: length - 1];
	} else {
		of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];
		char buffer[512];
		size_t length;

		if ((length = ExpandEnvironmentStringsA(
		    [self cStringWithEncoding: encoding], buffer,
		    sizeof(buffer))) == 0)
			return self;

		return [OFString stringWithCString: buffer
					  encoding: encoding
					    length: length - 1];
	}
}
#endif

#ifdef OF_HAVE_FILES
- (void)writeToFile: (OFString *)path
{
	[self writeToFile: path encoding: OF_STRING_ENCODING_UTF_8];
	[self writeToFile: path encoding: OFStringEncodingUTF8];
}

- (void)writeToFile: (OFString *)path encoding: (of_string_encoding_t)encoding
- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFFile *file = [OFFile fileWithPath: path mode: @"w"];
	[file writeString: self encoding: encoding];
	objc_autoreleasePoolPop(pool);
}
#endif

- (void)writeToURL: (OFURL *)URL
{
	[self writeToURL: URL encoding: OF_STRING_ENCODING_UTF_8];
	[self writeToURL: URL encoding: OFStringEncodingUTF8];
}

- (void)writeToURL: (OFURL *)URL encoding: (of_string_encoding_t)encoding
- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding
{
	void *pool = objc_autoreleasePoolPush();
	OFURLHandler *URLHandler;
	OFStream *stream;

	if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil)
		@throw [OFUnsupportedProtocolException exceptionWithURL: URL];

	stream = [URLHandler openItemAtURL: URL mode: @"w"];
	[stream writeString: self encoding: encoding];

	objc_autoreleasePoolPop(pool);
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *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++;

			continue;
		}

		if (characters[i] == '\n' || characters[i] == '\r') {
			void *pool2 = objc_autoreleasePoolPush();

			block([self substringWithRange:
			    of_range(last, i - last)], &stop);
			    OFMakeRange(last, i - last)], &stop);
			last = i + 1;

			objc_autoreleasePoolPop(pool2);
		}

		lastCarriageReturn = (characters[i] == '\r');
	}

	if (!stop)
		block([self substringWithRange: of_range(last, i - last)],
		block([self substringWithRange: OFMakeRange(last, i - last)],
		    &stop);

	objc_autoreleasePoolPop(pool);
}
#endif
@end

Modified src/OFSubarray.h from [a7a115b770] to [398ae6fbae].

16
17
18
19
20
21
22
23

24
25
26
27


28
29
30
16
17
18
19
20
21
22

23
24
25


26
27
28
29
30







-
+


-
-
+
+



#import "OFArray.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFSubarray: OFArray
{
	OFArray *_array;
	of_range_t _range;
	OFRange _range;
}

+ (instancetype)arrayWithArray: (OFArray *)array range: (of_range_t)range;
- (instancetype)initWithArray: (OFArray *)array range: (of_range_t)range;
+ (instancetype)arrayWithArray: (OFArray *)array range: (OFRange)range;
- (instancetype)initWithArray: (OFArray *)array range: (OFRange)range;
@end

OF_ASSUME_NONNULL_END

Modified src/OFSubarray.m from [a275f23615] to [d5bd07084c].

16
17
18
19
20
21
22
23

24
25
26
27
28

29
30
31
32
33
34
35
16
17
18
19
20
21
22

23
24
25
26
27

28
29
30
31
32
33
34
35







-
+




-
+







#include "config.h"

#import "OFSubarray.h"

#import "OFOutOfRangeException.h"

@implementation OFSubarray
+ (instancetype)arrayWithArray: (OFArray *)array range: (of_range_t)range
+ (instancetype)arrayWithArray: (OFArray *)array range: (OFRange)range
{
	return [[[self alloc] initWithArray: array range: range] autorelease];
}

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

	@try {
		/* Should usually be retain, as it's useless with a copy */
		_array = [array copy];
		_range = range;
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
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







-
+















-
+




-
+









-
+




-
+




-
+










{
	if (idx >= _range.length)
		@throw [OFOutOfRangeException exception];

	return [_array objectAtIndex: idx + _range.location];
}

- (void)getObjects: (id *)buffer inRange: (of_range_t)range
- (void)getObjects: (id *)buffer inRange: (OFRange)range
{
	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > _range.length)
		@throw [OFOutOfRangeException exception];

	range.location += _range.location;

	[_array getObjects: buffer inRange: range];
}

- (size_t)indexOfObject: (id)object
{
	size_t idx = [_array indexOfObject: object];

	if (idx < _range.location)
		return OF_NOT_FOUND;
		return OFNotFound;

	idx -= _range.location;

	if (idx >= _range.length)
		return OF_NOT_FOUND;
		return OFNotFound;

	return idx;
}

- (size_t)indexOfObjectIdenticalTo: (id)object
{
	size_t idx = [_array indexOfObjectIdenticalTo: object];

	if (idx < _range.location)
		return OF_NOT_FOUND;
		return OFNotFound;

	idx -= _range.location;

	if (idx >= _range.length)
		return OF_NOT_FOUND;
		return OFNotFound;

	return idx;
}

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

	range.location += _range.location;

	return [_array objectsInRange: range];
}
@end

Modified src/OFSystemInfo.m from [6c63cf09e4] to [014dd1b2fc].

160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
160
161
162
163
164
165
166

167
168
169
170
171
172
173
174







-
+







	}
# endif
#elif defined(OF_WINDOWS)
# ifdef OF_HAVE_FILES
	void *pool = objc_autoreleasePoolPush();

	@try {
		of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];
		char systemDir[PATH_MAX];
		UINT systemDirLen;
		OFString *systemDirString;
		const char *path;
		void *buffer;
		DWORD bufferLen;

386
387
388
389
390
391
392
393

394
395
396
397
398
399
400
386
387
388
389
390
391
392

393
394
395
396
397
398
399
400







-
+







		OFString *home;

		if ((home = [env objectForKey: @"HOME"]) == nil)
			@throw [OFNotImplementedException
			    exceptionWithSelector: _cmd
					   object: self];

		[path deleteCharactersInRange: of_range(0, 1)];
		[path deleteCharactersInRange: OFMakeRange(0, 1)];
		[path prependString: home];
	}

	[path makeImmutable];

	return path;
# elif defined(OF_WINDOWS)
478
479
480
481
482
483
484
485

486
487
488
489
490
491
492
478
479
480
481
482
483
484

485
486
487
488
489
490
491
492







-
+







		OFString *home;

		if ((home = [env objectForKey: @"HOME"]) == nil)
			@throw [OFNotImplementedException
			    exceptionWithSelector: _cmd
					   object: self];

		[path deleteCharactersInRange: of_range(0, 1)];
		[path deleteCharactersInRange: OFMakeRange(0, 1)];
		[path prependString: home];
	}

	[path appendString: @"/Preferences"];
	[path makeImmutable];

	return path;
537
538
539
540
541
542
543
544

545
546
547
548
549
550
551
537
538
539
540
541
542
543

544
545
546
547
548
549
550
551







-
+







		return nil;

	buffer[0] = regs.ebx;
	buffer[1] = regs.edx;
	buffer[2] = regs.ecx;

	return [OFString stringWithCString: (char *)buffer
				  encoding: OF_STRING_ENCODING_ASCII
				  encoding: OFStringEncodingASCII
				    length: 12];
#else
	return nil;
#endif
}

+ (OFString *)CPUModel
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
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







-
+










-
+







		buffer[i++] = regs.eax;
		buffer[i++] = regs.ebx;
		buffer[i++] = regs.ecx;
		buffer[i++] = regs.edx;
	}

	return [OFString stringWithCString: (char *)buffer
				  encoding: OF_STRING_ENCODING_ASCII];
				  encoding: OFStringEncodingASCII];
#elif defined(OF_AMIGAOS4)
	CONST_STRPTR model, version;

	GetCPUInfoTags(GCIT_ModelString, &model,
	    GCIT_VersionString, &version, TAG_END);

	if (version != NULL)
		return [OFString stringWithFormat: @"%s V%s", model, version];
	else
		return [OFString stringWithCString: model
					  encoding: OF_STRING_ENCODING_ASCII];
					  encoding: OFStringEncodingASCII];
#else
	return nil;
#endif
}

#if defined(OF_X86_64) || defined(OF_X86)
+ (bool)supportsMMX

Modified src/OFTCPSocket.h from [b81cee61b1] to [d5a780252d].

26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40







-
+







#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block which is called when the socket connected.
 *
 * @param exception An exception which occurred while connecting the socket or
 *		    `nil` on success
 */
typedef void (^of_tcp_socket_async_connect_block_t)(id _Nullable exception);
typedef void (^OFTCPSocketAsyncConnectBlock)(id _Nullable exception);
#endif

/**
 * @protocol OFTCPSocketDelegate OFTCPSocket.h ObjFW/OFTCPSocket.h
 *
 * A delegate for OFTCPSocket.
 */
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
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







-
+











-
+











-
-
+
+







 *
 * @param host The host to connect to
 * @param port The port on the host to connect to
 * @param runLoopMode The run loop mode in which to perform the async connect
 */
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode;
	       runLoopMode: (OFRunLoopMode)runLoopMode;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Asynchronously connect the OFTCPSocket to the specified destination.
 *
 * @param host The host to connect to
 * @param port The port on the host to connect to
 * @param block The block to execute once the connection has been established
 */
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
		     block: (of_tcp_socket_async_connect_block_t)block;
		     block: (OFTCPSocketAsyncConnectBlock)block;

/**
 * @brief Asynchronously connect the OFTCPSocket to the specified destination.
 *
 * @param host The host to connect to
 * @param port The port on the host to connect to
 * @param runLoopMode The run loop mode in which to perform the async connect
 * @param block The block to execute once the connection has been established
 */
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
		     block: (of_tcp_socket_async_connect_block_t)block;
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (OFTCPSocketAsyncConnectBlock)block;
#endif

/**
 * @brief Bind the socket to the specified host and port.
 *
 * @param host The host to bind to. Use `@"0.0.0.0"` for IPv4 or `@"::"` for
 *	       IPv6 to bind to all.

Modified src/OFTCPSocket.m from [5cdf6dd0d8] to [98d3158581].

47
48
49
50
51
52
53
54
55


56
57
58
59
60
61
62
47
48
49
50
51
52
53


54
55
56
57
58
59
60
61
62







-
-
+
+







#import "OFNotImplementedException.h"
#import "OFNotOpenException.h"
#import "OFSetOptionFailedException.h"

#import "socket.h"
#import "socket_helpers.h"

static const of_run_loop_mode_t connectRunLoopMode =
    @"of_tcp_socket_connect_mode";
static const OFRunLoopMode connectRunLoopMode =
    @"OFTCPSocketConnectRunLoopMode";

Class of_tls_socket_class = Nil;

static OFString *defaultSOCKS5Host = nil;
static uint16_t defaultSOCKS5Port = 1080;

@interface OFTCPSocket () <OFIPSocketAsyncConnecting>
132
133
134
135
136
137
138
139

140
141
142
143
144
145
146
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146







-
+







- (void)dealloc
{
	[_SOCKS5Host release];

	[super dealloc];
}

- (bool)of_createSocketForAddress: (const of_socket_address_t *)address
- (bool)of_createSocketForAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170







-
+







	if ((flags = fcntl(_socket, F_GETFD, 0)) != -1)
		fcntl(_socket, F_SETFD, flags | FD_CLOEXEC);
#endif

	return true;
}

- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address
- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	/* Cast needed for AmigaOS, where the argument is declared non-const */
	if (connect(_socket, (struct sockaddr *)&address->sockaddr.sockaddr,
209
210
211
212
213
214
215
216

217
218
219
220
221

222
223
224
225
226
227
228
209
210
211
212
213
214
215

216
217
218
219
220

221
222
223
224
225
226
227
228







-
+




-
+







	objc_autoreleasePoolPop(pool);
}

- (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port
{
	[self asyncConnectToHost: host
			    port: port
		     runLoopMode: of_run_loop_mode_default];
		     runLoopMode: OFDefaultRunLoopMode];
}

- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
	       runLoopMode: (OFRunLoopMode)runLoopMode
{
	void *pool = objc_autoreleasePoolPush();
	id <OFTCPSocketDelegate> delegate;

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

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







-
+



-
+





-
-
+
+








	objc_autoreleasePoolPop(pool);
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
		     block: (of_tcp_socket_async_connect_block_t)block
		     block: (OFTCPSocketAsyncConnectBlock)block
{
	[self asyncConnectToHost: host
			    port: port
		     runLoopMode: of_run_loop_mode_default
		     runLoopMode: OFDefaultRunLoopMode
			   block: block];
}

- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
	       runLoopMode: (of_run_loop_mode_t)runLoopMode
		     block: (of_tcp_socket_async_connect_block_t)block
	       runLoopMode: (OFRunLoopMode)runLoopMode
		     block: (OFTCPSocketAsyncConnectBlock)block
{
	void *pool = objc_autoreleasePoolPush();
	id <OFTCPSocketDelegate> delegate = nil;

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

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







-
+













-
+

-
-
+
+







#endif

- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port
{
	const int one = 1;
	void *pool = objc_autoreleasePoolPush();
	OFData *socketAddresses;
	of_socket_address_t address;
	OFSocketAddress address;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	if (_SOCKS5Host != nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	socketAddresses = [[OFThread DNSResolver]
	    resolveAddressesForHost: host
		      addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY];
		      addressFamily: OFSocketAddressFamilyAny];

	address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0];
	of_socket_address_set_port(&address, port);
	address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0];
	OFSocketAddressSetPort(&address, port);

	if ((_socket = socket(address.sockaddr.sockaddr.sa_family,
	    SOCK_STREAM | SOCK_CLOEXEC, 0)) == INVALID_SOCKET)
		@throw [OFBindFailedException
		    exceptionWithHost: host
				 port: port
			       socket: self
359
360
361
362
363
364
365
366

367
368
369
370
371
372
373
359
360
361
362
363
364
365

366
367
368
369
370
371
372
373







-
+







		for (;;) {
			uint16_t rnd = 0;
			int ret;

			while (rnd < 1024)
				rnd = (uint16_t)rand();

			of_socket_address_set_port(&address, rnd);
			OFSocketAddressSetPort(&address, rnd);

			if ((ret = bind(_socket, &address.sockaddr.sockaddr,
			    address.length)) == 0) {
				port = rnd;
				break;
			}

Modified src/OFTCPSocketSOCKS5Connector.h from [edab2535a4] to [2e0767356b].

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







-
+




















-
+
-






@interface OFTCPSocketSOCKS5Connector: OFObject <OFTCPSocketDelegate>
{
	OFTCPSocket *_socket;
	OFString *_host;
	uint16_t _port;
	id <OFTCPSocketDelegate> _Nullable _delegate;
#ifdef OF_HAVE_BLOCKS
	of_tcp_socket_async_connect_block_t _Nullable _block;
	OFTCPSocketAsyncConnectBlock _Nullable _block;
#endif
	id _Nullable _exception;
	enum {
		OF_SOCKS5_STATE_SEND_AUTHENTICATION = 1,
		OF_SOCKS5_STATE_READ_VERSION,
		OF_SOCKS5_STATE_SEND_REQUEST,
		OF_SOCKS5_STATE_READ_RESPONSE,
		OF_SOCKS5_STATE_READ_ADDRESS,
		OF_SOCKS5_STATE_READ_ADDRESS_LENGTH,
	} _SOCKS5State;
	/* Longest read is domain name (max 255 bytes) + port */
	unsigned char _buffer[257];
	OFMutableData *_Nullable _request;
}

- (instancetype)initWithSocket: (OFTCPSocket *)sock
			  host: (OFString *)host
			  port: (uint16_t)port
		      delegate: (nullable id <OFTCPSocketDelegate>)delegate
#ifdef OF_HAVE_BLOCKS
			 block: (nullable of_tcp_socket_async_connect_block_t)
			 block: (nullable OFTCPSocketAsyncConnectBlock)block
				    block
#endif
;
- (void)didConnect;
@end

OF_ASSUME_NONNULL_END

Modified src/OFTCPSocketSOCKS5Connector.m from [777126a470] to [e22943df87].

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







-
+








@implementation OFTCPSocketSOCKS5Connector
- (instancetype)initWithSocket: (OFTCPSocket *)sock
			  host: (OFString *)host
			  port: (uint16_t)port
		      delegate: (id <OFTCPSocketDelegate>)delegate
#ifdef OF_HAVE_BLOCKS
			 block: (of_tcp_socket_async_connect_block_t)block
			 block: (OFTCPSocketAsyncConnectBlock)block
#endif
{
	self = [super init];

	@try {
		_socket = [sock retain];
		_host = [host copy];
112
113
114
115
116
117
118
119

120
121
122
123
124
125
126
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126







-
+







}

-      (bool)stream: (OFStream *)sock
  didReadIntoBuffer: (void *)buffer
	     length: (size_t)length
	  exception: (id)exception
{
	of_run_loop_mode_t runLoopMode;
	OFRunLoopMode runLoopMode;
	unsigned char *SOCKSVersion;
	uint8_t hostLength;
	unsigned char port[2];
	unsigned char *response, *addressLength;

	if (exception != nil) {
		_exception = [exception retain];
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
265
266
267
268
269
270
271

272
273
274
275
276
277
278
279







-
+







}

- (OFData *)stream: (OFStream *)sock
      didWriteData: (OFData *)data
      bytesWritten: (size_t)bytesWritten
	 exception: (id)exception
{
	of_run_loop_mode_t runLoopMode;
	OFRunLoopMode runLoopMode;

	if (exception != nil) {
		_exception = [exception retain];
		[self didConnect];
		return nil;
	}

Modified src/OFTarArchive.h from [a2350271f7] to [0ba5d85fe3].

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







-
-
-
-
+
+
+
+

-
+






-
+







 *
 * @brief A class for accessing and manipulating tar archives.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFTarArchive: OFObject
{
	OFStream *_stream;
	enum {
		OF_TAR_ARCHIVE_MODE_READ,
		OF_TAR_ARCHIVE_MODE_WRITE,
		OF_TAR_ARCHIVE_MODE_APPEND
	enum OFTarArchiveMode {
		OFTarArchiveModeRead,
		OFTarArchiveModeWrite,
		OFTarArchiveModeAppend
	} _mode;
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
	OFStream *_Nullable _lastReturnedStream;
}

/**
 * @brief The encoding to use for the archive. Defaults to UTF-8.
 */
@property (nonatomic) of_string_encoding_t encoding;
@property (nonatomic) OFStringEncoding encoding;

/**
 * @brief A stream for reading the current entry.
 *
 * @note This is only available in read mode.
 *
 * @note The returned stream conforms to @ref OFReadyForReadingObserving if the

Modified src/OFTarArchive.m from [0481cd7f61] to [72e6e59f69].

82
83
84
85
86
87
88
89

90
91

92
93

94
95
96
97

98
99
100
101
102
103
104
82
83
84
85
86
87
88

89
90

91
92

93
94
95
96

97
98
99
100
101
102
103
104







-
+

-
+

-
+



-
+







{
	self = [super init];

	@try {
		_stream = [stream retain];

		if ([mode isEqual: @"r"])
			_mode = OF_TAR_ARCHIVE_MODE_READ;
			_mode = OFTarArchiveModeRead;
		else if ([mode isEqual: @"w"])
			_mode = OF_TAR_ARCHIVE_MODE_WRITE;
			_mode = OFTarArchiveModeWrite;
		else if ([mode isEqual: @"a"])
			_mode = OF_TAR_ARCHIVE_MODE_APPEND;
			_mode = OFTarArchiveModeAppend;
		else
			@throw [OFInvalidArgumentException exception];

		if (_mode == OF_TAR_ARCHIVE_MODE_APPEND) {
		if (_mode == OFTarArchiveModeAppend) {
			uint32_t buffer[1024 / sizeof(uint32_t)];
			bool empty = true;

			if (![_stream isKindOfClass: [OFSeekableStream class]])
				@throw [OFInvalidArgumentException exception];

			[(OFSeekableStream *)_stream seekToOffset: -1024
112
113
114
115
116
117
118
119

120
121
122
123
124
125
126
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126







-
+







			if (!empty)
				@throw [OFInvalidFormatException exception];

			[(OFSeekableStream *)stream seekToOffset: -1024
							  whence: SEEK_END];
		}

		_encoding = OF_STRING_ENCODING_UTF_8;
		_encoding = OFStringEncodingUTF8;
	} @catch (id e) {
		[self release];
		@throw e;
	}

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







-
+








- (OFTarArchiveEntry *)nextEntry
{
	OFTarArchiveEntry *entry;
	uint32_t buffer[512 / sizeof(uint32_t)];
	bool empty = true;

	if (_mode != OF_TAR_ARCHIVE_MODE_READ)
	if (_mode != OFTarArchiveModeRead)
		@throw [OFInvalidArgumentException exception];

	[(OFTarArchiveFileReadStream *)_lastReturnedStream of_skip];
	@try {
		[_lastReturnedStream close];
	} @catch (OFNotOpenException *e) {
		/* Might have already been closed by the user - that's fine. */
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
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







-
+













-
+
-







			entry: entry];

	return entry;
}

- (OFStream *)streamForReadingCurrentEntry
{
	if (_mode != OF_TAR_ARCHIVE_MODE_READ)
	if (_mode != OFTarArchiveModeRead)
		@throw [OFInvalidArgumentException exception];

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

	return [[(OFTarArchiveFileReadStream *)_lastReturnedStream
	    retain] autorelease];
}

- (OFStream *)streamForWritingEntry: (OFTarArchiveEntry *)entry
{
	void *pool;

	if (_mode != OF_TAR_ARCHIVE_MODE_WRITE &&
	if (_mode != OFTarArchiveModeWrite && _mode != OFTarArchiveModeAppend)
	    _mode != OF_TAR_ARCHIVE_MODE_APPEND)
		@throw [OFInvalidArgumentException exception];

	pool = objc_autoreleasePoolPush();

	@try {
		[_lastReturnedStream close];
	} @catch (OFNotOpenException *e) {
251
252
253
254
255
256
257
258

259
260
261
262

263
264
265
266
267
268
269
270
250
251
252
253
254
255
256

257

258
259

260

261
262
263
264
265
266
267







-
+
-


-
+
-







		[_lastReturnedStream close];
	} @catch (OFNotOpenException *e) {
		/* Might have already been closed by the user - that's fine. */
	}
	[_lastReturnedStream release];
	_lastReturnedStream = nil;

	if (_mode == OF_TAR_ARCHIVE_MODE_WRITE ||
	if (_mode == OFTarArchiveModeWrite || _mode == OFTarArchiveModeAppend) {
	    _mode == OF_TAR_ARCHIVE_MODE_APPEND) {
		char buffer[1024];
		memset(buffer, '\0', 1024);
		[_stream writeBuffer: buffer
		[_stream writeBuffer: buffer length: 1024];
			      length: 1024];
	}

	[_stream release];
	_stream = nil;
}
@end

Modified src/OFTarArchiveEntry+Private.h from [e07f2ba876] to [929bab9877].

19
20
21
22
23
24
25
26

27
28
29

30
31
32
19
20
21
22
23
24
25

26
27
28

29
30
31
32







-
+


-
+



OF_ASSUME_NONNULL_BEGIN

@class OFStream;

OF_DIRECT_MEMBERS
@interface OFTarArchiveEntry ()
- (instancetype)of_initWithHeader: (unsigned char [_Nonnull 512])header
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
    OF_METHOD_FAMILY(init);
- (void)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding;
		encoding: (OFStringEncoding)encoding;
@end

OF_ASSUME_NONNULL_END

Modified src/OFTarArchiveEntry.h from [e9a73505d7] to [5715325220].

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







-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
-
+
+













-
+







/** @file */

@class OFDate;

/**
 * @brief The type of the archive entry.
 */
typedef enum of_tar_archive_entry_type_t {
typedef enum OFTarArchiveEntryType {
	/** Normal file */
	OF_TAR_ARCHIVE_ENTRY_TYPE_FILE		   = '0',
	OFTarArchiveEntryTypeFile	     = '0',
	/** Hard link */
	OF_TAR_ARCHIVE_ENTRY_TYPE_LINK		   = '1',
	OFTarArchiveEntryTypeLink	     = '1',
	/** Symbolic link */
	OF_TAR_ARCHIVE_ENTRY_TYPE_SYMLINK	   = '2',
	OFTarArchiveEntryTypeSymlink	     = '2',
	/** Character device */
	OF_TAR_ARCHIVE_ENTRY_TYPE_CHARACTER_DEVICE = '3',
	OFTarArchiveEntryTypeCharacterDevice = '3',
	/** Block device */
	OF_TAR_ARCHIVE_ENTRY_TYPE_BLOCK_DEVICE	   = '4',
	OFTarArchiveEntryTypeBlockDevice     = '4',
	/** Directory */
	OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY	   = '5',
	OFTarArchiveEntryTypeDirectory	     = '5',
	/** FIFO */
	OF_TAR_ARCHIVE_ENTRY_TYPE_FIFO		   = '6',
	OFTarArchiveEntryTypeFIFO	     = '6',
	/** Contiguous file */
	OF_TAR_ARCHIVE_ENTRY_TYPE_CONTIGUOUS_FILE  = '7',
} of_tar_archive_entry_type_t;
	OFTarArchiveEntryTypeContiguousFile  = '7',
} OFTarArchiveEntryType;

/**
 * @class OFTarArchiveEntry OFTarArchiveEntry.h ObjFW/OFTarArchiveEntry.h
 *
 * @brief A class which represents an entry of a tar archive.
 */
@interface OFTarArchiveEntry: OFObject <OFCopying, OFMutableCopying>
{
	OFString *_fileName;
	unsigned long _mode;
	unsigned long long _size;
	unsigned long _UID, _GID;
	OFDate *_modificationDate;
	of_tar_archive_entry_type_t _type;
	OFTarArchiveEntryType _type;
	OFString *_Nullable _targetFileName;
	OFString *_Nullable _owner, *_Nullable _group;
	unsigned long _deviceMajor, _deviceMinor;
	OF_RESERVE_IVARS(OFTarArchiveEntry, 4)
}

/**
91
92
93
94
95
96
97
98

99
100

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

98
99

100
101
102
103
104
105
106
107







-
+

-
+







 * @brief The date of the last modification of the file.
 */
@property (readonly, retain, nonatomic) OFDate *modificationDate;

/**
 * @brief The type of the archive entry.
 *
 * See @ref of_tar_archive_entry_type_t.
 * See @ref OFTarArchiveEntryType.
 */
@property (readonly, nonatomic) of_tar_archive_entry_type_t type;
@property (readonly, nonatomic) OFTarArchiveEntryType type;

/**
 * @brief The file name of the target (for a hard link or symbolic link).
 */
@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic)
    OFString *targetFileName;

Modified src/OFTarArchiveEntry.m from [9e0aa08280] to [4eb33d5a79].

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







-
+












-
+







#import "OFStream.h"
#import "OFString.h"

#import "OFOutOfRangeException.h"

static OFString *
stringFromBuffer(const unsigned char *buffer, size_t length,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	for (size_t i = 0; i < length; i++)
		if (buffer[i] == '\0')
			length = i;

	return [OFString stringWithCString: (const char *)buffer
				  encoding: encoding
				    length: length];
}

static void
stringToBuffer(unsigned char *buffer, OFString *string, size_t length,
    of_string_encoding_t encoding)
    OFStringEncoding encoding)
{
	size_t cStringLength = [string cStringLengthWithEncoding: encoding];

	if (cStringLength > length)
		@throw [OFOutOfRangeException exception];

	memcpy(buffer, [string cStringWithEncoding: encoding], cStringLength);
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
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







-
+



















-
+


















-
+








-
+







		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) unsignedLongLongValueWithBase: 8];
		    OFStringEncodingASCII) unsignedLongLongValueWithBase: 8];

	if (value > max)
		@throw [OFOutOfRangeException exception];

	return value;
}

@implementation OFTarArchiveEntry
+ (instancetype)entryWithFileName: (OFString *)fileName
{
	return [[[self alloc] initWithFileName: fileName] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)of_initWithHeader: (unsigned char [512])header
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFString *targetFileName;

		_fileName = [stringFromBuffer(header, 100, encoding) copy];
		_mode = (unsigned long)octalValueFromBuffer(
		    header + 100, 8, ULONG_MAX);
		_UID = (unsigned long)octalValueFromBuffer(
		    header + 108, 8, ULONG_MAX);
		_GID = (unsigned long)octalValueFromBuffer(
		    header + 116, 8, ULONG_MAX);
		_size = (unsigned long long)octalValueFromBuffer(
		    header + 124, 12, ULLONG_MAX);
		_modificationDate = [[OFDate alloc]
		    initWithTimeIntervalSince1970:
		    (of_time_interval_t)octalValueFromBuffer(
		    (OFTimeInterval)octalValueFromBuffer(
		    header + 136, 12, ULLONG_MAX)];
		_type = header[156];

		targetFileName = stringFromBuffer(header + 157, 100, encoding);
		if (targetFileName.length > 0)
			_targetFileName = [targetFileName copy];

		if (_type == '\0')
			_type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE;
			_type = OFTarArchiveEntryTypeFile;

		if (memcmp(header + 257, "ustar\0" "00", 8) == 0) {
			OFString *prefix;

			_owner = [stringFromBuffer(header + 265, 32, encoding)
			    copy];
			_group = [stringFromBuffer(header + 297, 32, encoding)
149
150
151
152
153
154
155
156

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

156
157
158
159
160
161
162
163







-
+








- (instancetype)initWithFileName: (OFString *)fileName
{
	self = [super init];

	@try {
		_fileName = [fileName copy];
		_type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE;
		_type = OFTarArchiveEntryTypeFile;
		_mode = 0644;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
228
229
230
231
232
233
234

235
236
237
238
239
240
241
242







-
+







}

- (OFDate *)modificationDate
{
	return _modificationDate;
}

- (of_tar_archive_entry_type_t)type
- (OFTarArchiveEntryType)type
{
	return _type;
}

- (OFString *)targetFileName
{
	return _targetFileName;
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
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







-
+








-
+


-
+


-
+


-
+



-
+
















-
+


-
+







-
+





	objc_autoreleasePoolPop(pool);

	return [ret autorelease];
}

- (void)of_writeToStream: (OFStream *)stream
		encoding: (of_string_encoding_t)encoding
		encoding: (OFStringEncoding)encoding
{
	unsigned char buffer[512];
	unsigned long long modificationDate;
	uint16_t checksum = 0;

	stringToBuffer(buffer, _fileName, 100, encoding);
	stringToBuffer(buffer + 100,
	    [OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);
	stringToBuffer(buffer + 108,
	    [OFString stringWithFormat: @"%06" PRIo16 " ", _UID], 8,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);
	stringToBuffer(buffer + 116,
	    [OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);
	stringToBuffer(buffer + 124,
	    [OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);
	modificationDate = _modificationDate.timeIntervalSince1970;
	stringToBuffer(buffer + 136,
	    [OFString stringWithFormat: @"%011llo", modificationDate],
	    12, OF_STRING_ENCODING_ASCII);
	    12, OFStringEncodingASCII);

	/*
	 * During checksumming, the checksum field is expected to be set to 8
	 * spaces.
	 */
	memset(buffer + 148, ' ', 8);

	buffer[156] = _type;
	stringToBuffer(buffer + 157, _targetFileName, 100, encoding);

	/* ustar */
	memcpy(buffer + 257, "ustar\0" "00", 8);
	stringToBuffer(buffer + 265, _owner, 32, encoding);
	stringToBuffer(buffer + 297, _group, 32, encoding);
	stringToBuffer(buffer + 329,
	    [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMajor], 8,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);
	stringToBuffer(buffer + 337,
	    [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMinor], 8,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);
	memset(buffer + 345, '\0', 155 + 12);

	/* Fill in the checksum */
	for (size_t i = 0; i < 500; i++)
		checksum += buffer[i];
	stringToBuffer(buffer + 148,
	    [OFString stringWithFormat: @"%06" PRIo16, checksum], 7,
	    OF_STRING_ENCODING_ASCII);
	    OFStringEncodingASCII);

	[stream writeBuffer: buffer length: sizeof(buffer)];
}
@end

Modified src/OFThread.h from [f4a6bc3a11] to [4486e81af4].

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







-
+








#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_BLOCKS)
/**
 * @brief A block to be executed in a new thread.
 *
 * @return The object which should be returned when the thread is joined
 */
typedef id _Nullable (^of_thread_block_t)(void);
typedef id _Nullable (^OFThreadBlock)(void);
#endif

/**
 * @class OFThread OFThread.h ObjFW/OFThread.h
 *
 * @brief A class which provides portable threads.
 *
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85







-
+







		OF_THREAD_RUNNING,
		OF_THREAD_WAITING_FOR_JOIN
	} _running;
# ifndef OF_OBJFW_RUNTIME
	void *_pool;
# endif
# ifdef OF_HAVE_BLOCKS
	of_thread_block_t _Nullable _threadBlock;
	OFThreadBlock _Nullable _threadBlock;
# endif
	jmp_buf _exitEnv;
	id _returnValue;
	bool _supportsSockets;
	OFRunLoop *_Nullable _runLoop;
	OFMutableDictionary *_threadDictionary;
	OFString *_Nullable _name;
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
115
116
117
118
119
120
121

122

123
124
125
126
127
128
129







-
+
-







 */
@property OF_NULLABLE_PROPERTY (copy) OFString *name;

# ifdef OF_HAVE_BLOCKS
/**
 * @brief The block to execute in the thread.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThreadBlock threadBlock;
    of_thread_block_t threadBlock;
# endif

/**
 * @brief The run loop for the thread.
 */
@property (readonly, nonatomic) OFRunLoop *runLoop;

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







-
+







# ifdef OF_HAVE_BLOCKS
/**
 * @brief Creates a new thread with the specified block.
 *
 * @param threadBlock A block which is executed by the thread
 * @return A new, autoreleased thread
 */
+ (instancetype)threadWithThreadBlock: (of_thread_block_t)threadBlock;
+ (instancetype)threadWithThreadBlock: (OFThreadBlock)threadBlock;
# endif

/**
 * @brief Returns the current thread.
 *
 * @return The current thread
 */
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
212
213
214
215
216
217
218

219
220
221
222
223
224
225
226







-
+








/**
 * @brief Suspends execution of the current thread for the specified time
 *	  interval.
 *
 * @param timeInterval The number of seconds to sleep
 */
+ (void)sleepForTimeInterval: (of_time_interval_t)timeInterval;
+ (void)sleepForTimeInterval: (OFTimeInterval)timeInterval;

/**
 * @brief Suspends execution of the current thread until the specified date.
 *
 * @param date The date to wait for
 */
+ (void)sleepUntilDate: (OFDate *)date;
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
264
265
266
267
268
269
270

271
272
273
274
275
276
277
278







-
+







# ifdef OF_HAVE_BLOCKS
/**
 * @brief Initializes an already allocated thread with the specified block.
 *
 * @param threadBlock A block which is executed by the thread
 * @return An initialized OFThread.
 */
- (instancetype)initWithThreadBlock: (of_thread_block_t)threadBlock;
- (instancetype)initWithThreadBlock: (OFThreadBlock)threadBlock;
# endif

/**
 * @brief The main routine of the thread. You need to reimplement this!
 *
 * @return The object the join method should return when called for this thread
 */

Modified src/OFThread.m from [9da78353a7] to [edb1078c84].

171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185







-
+








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

# ifdef OF_HAVE_BLOCKS
+ (instancetype)threadWithThreadBlock: (of_thread_block_t)threadBlock
+ (instancetype)threadWithThreadBlock: (OFThreadBlock)threadBlock
{
	return [[[self alloc] initWithThreadBlock: threadBlock] autorelease];
}
# endif

+ (OFThread *)currentThread
{
231
232
233
234
235
236
237
238

239
240
241
242
243
244
245
231
232
233
234
235
236
237

238
239
240
241
242
243
244
245







-
+







		DNSResolver = [[OFDNSResolver alloc] init];

	return DNSResolver;
# endif
}
#endif

+ (void)sleepForTimeInterval: (of_time_interval_t)timeInterval
+ (void)sleepForTimeInterval: (OFTimeInterval)timeInterval
{
	if (timeInterval < 0)
		return;

#if defined(OF_WINDOWS)
	if (timeInterval * 1000 > UINT_MAX)
		@throw [OFOutOfRangeException exception];
372
373
374
375
376
377
378
379

380
381
382
383
384
385
386
372
373
374
375
376
377
378

379
380
381
382
383
384
385
386







-
+







		@throw e;
	}

	return self;
}

# ifdef OF_HAVE_BLOCKS
- (instancetype)initWithThreadBlock: (of_thread_block_t)threadBlock
- (instancetype)initWithThreadBlock: (OFThreadBlock)threadBlock
{
	self = [self init];

	@try {
		_threadBlock = [threadBlock copy];
	} @catch (id e) {
		[self release];

Modified src/OFThreadPool.h from [7948e1d39c] to [4da774feaf].

19
20
21
22
23
24
25
26

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

26
27
28
29
30
31
32
33







-
+








/** @file */

#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block for a job which should be executed in a thread pool.
 */
typedef void (^of_thread_pool_block_t)(void);
typedef void (^OFThreadPoolBlock)(void);
#endif

@class OFCondition;
@class OFList OF_GENERIC(ObjectType);
@class OFMutableArray OF_GENERIC(ObjectType);
@class OFThreadPoolJob;

100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115
116







-
+










#ifdef OF_HAVE_BLOCKS
/**
 * @brief Executes the specified block as soon as a thread is ready.
 *
 * @param block The block to execute
 */
- (void)dispatchWithBlock: (of_thread_pool_block_t)block;
- (void)dispatchWithBlock: (OFThreadPoolBlock)block;
#endif

/**
 * @brief Waits until all jobs are done.
 */
- (void)waitUntilDone;
@end

OF_ASSUME_NONNULL_END

Modified src/OFThreadPool.m from [1d33cef32f] to [62afef694d].

27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
49







-
+







-
+







OF_DIRECT_MEMBERS
@interface OFThreadPoolJob: OFObject
{
	id _target;
	SEL _selector;
	id _object;
#ifdef OF_HAVE_BLOCKS
	of_thread_pool_block_t _block;
	OFThreadPoolBlock _block;
#endif
}

- (instancetype)initWithTarget: (id)target
		      selector: (SEL)selector
			object: (id)object;
#ifdef OF_HAVE_BLOCKS
- (instancetype)initWithBlock: (of_thread_pool_block_t)block;
- (instancetype)initWithBlock: (OFThreadPoolBlock)block;
#endif
- (void)perform;
@end

@implementation OFThreadPoolJob
- (instancetype)initWithTarget: (id)target
		      selector: (SEL)selector
60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74







-
+







		@throw e;
	}

	return self;
}

#ifdef OF_HAVE_BLOCKS
- (instancetype)initWithBlock: (of_thread_pool_block_t)block
- (instancetype)initWithBlock: (OFThreadPoolBlock)block
{
	self = [super init];

	@try {
		_block = [block copy];
	} @catch (id e) {
		[self release];
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
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







-
+






-
+

-
+







-
+


-
-
+
+







	pool = objc_autoreleasePoolPush();

	for (;;) {
		OFThreadPoolJob *job;

		[_queueCondition lock];
		@try {
			of_list_object_t *listObject;
			OFListItem *listItem;

			if (_terminate) {
				objc_autoreleasePoolPop(pool);
				return nil;
			}

			listObject = _queue.firstListObject;
			listItem = _queue.firstListItem;

			while (listObject == NULL) {
			while (listItem == NULL) {
				[_queueCondition wait];

				if (_terminate) {
					objc_autoreleasePoolPop(pool);
					return nil;
				}

				listObject = _queue.firstListObject;
				listItem = _queue.firstListItem;
			}

			job = [[listObject->object retain] autorelease];
			[_queue removeListObject: listObject];
			job = [[listItem->object retain] autorelease];
			[_queue removeListItem: listItem];
		} @finally {
			[_queueCondition unlock];
		}

		if (_terminate) {
			objc_autoreleasePoolPop(pool);
			return nil;
338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352







-
+







		[self of_dispatchJob: job];
	} @finally {
		[job release];
	}
}

#ifdef OF_HAVE_BLOCKS
- (void)dispatchWithBlock: (of_thread_pool_block_t)block
- (void)dispatchWithBlock: (OFThreadPoolBlock)block
{
	OFThreadPoolJob *job = [[OFThreadPoolJob alloc] initWithBlock: block];
	@try {
		[self of_dispatchJob: job];
	} @finally {
		[job release];
	}

Modified src/OFTimer+Private.h from [a79edf83ef] to [766374c70a].

16
17
18
19
20
21
22
23

24
25
26
16
17
18
19
20
21
22

23
24
25
26







-
+



#import "OFTimer.h"

OF_ASSUME_NONNULL_BEGIN

OF_DIRECT_MEMBERS
@interface OFTimer ()
- (void)of_setInRunLoop: (nullable OFRunLoop *)runLoop
		   mode: (nullable of_run_loop_mode_t)mode;
		   mode: (nullable OFRunLoopMode)mode;
@end

OF_ASSUME_NONNULL_END

Modified src/OFTimer.h from [4d79b8c7ef] to [2337ad9abd].

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







-
+











-
+






-
+







-
+






-
+








#ifdef OF_HAVE_BLOCKS
/**
 * @brief A block to execute when a timer fires.
 *
 * @param timer The timer which fired
 */
typedef void (^of_timer_block_t)(OFTimer *timer);
typedef void (^OFTimerBlock)(OFTimer *timer);
#endif

/**
 * @class OFTimer OFTimer.h ObjFW/OFTimer.h
 *
 * @brief A class for creating and firing timers.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFTimer: OFObject <OFComparing>
{
	OFDate *_fireDate;
	of_time_interval_t _interval;
	OFTimeInterval _interval;
	id _target;
	id _Nullable _object1, _object2, _object3, _object4;
	SEL _selector;
	unsigned char _arguments;
	bool _repeats;
#ifdef OF_HAVE_BLOCKS
	of_timer_block_t _block;
	OFTimerBlock _block;
#endif
	bool _valid;
#ifdef OF_HAVE_THREADS
	OFCondition *_condition;
	bool _done;
#endif
	OFRunLoop *_Nullable _inRunLoop;
	of_run_loop_mode_t _Nullable _inRunLoopMode;
	OFRunLoopMode _Nullable _inRunLoopMode;
}

/**
 * @brief The time interval in which the timer will repeat, if it is a
 *	  repeating timer.
 */
@property (readonly, nonatomic) of_time_interval_t timeInterval;
@property (readonly, nonatomic) OFTimeInterval timeInterval;

/**
 * @brief Whether the timer is repeating.
 */
@property (readonly, nonatomic, getter=isRepeating) bool repeating;

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







-
+














-
+


















-
+







 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
				       repeats: (bool)repeats;

/**
 * @brief Creates and schedules a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param object An object to pass when calling the selector on the target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (nullable id)object
				       repeats: (bool)repeats;

/**
 * @brief Creates and schedules a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param object1 The first object to pass when calling the selector on the
 *		  target
 * @param object2 The second object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (nullable id)object1
					object: (nullable id)object2
				       repeats: (bool)repeats;

/**
149
150
151
152
153
154
155
156

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

156
157
158
159
160
161
162
163







-
+







 * @param object2 The second object to pass when calling the selector on the
 *		  target
 * @param object3 The third object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (nullable id)object1
					object: (nullable id)object2
					object: (nullable id)object3
				       repeats: (bool)repeats;

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







-
+

















-
+

-
+











-
+














-
+


















-
+







 * @param object3 The third object to pass when calling the selector on the
 *		  target
 * @param object4 The fourth object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (nullable id)object1
					object: (nullable id)object2
					object: (nullable id)object3
					object: (nullable id)object4
				       repeats: (bool)repeats;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Creates and schedules a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param repeats Whether the timer repeats after it has been executed
 * @param block The block to invoke when the timer fires
 * @return A new, autoreleased timer
 */
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
				       repeats: (bool)repeats
					 block: (of_timer_block_t)block;
					 block: (OFTimerBlock)block;
#endif

/**
 * @brief Creates a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			      repeats: (bool)repeats;

/**
 * @brief Creates a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param object An object to pass when calling the selector on the target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (nullable id)object
			      repeats: (bool)repeats;

/**
 * @brief Creates a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param object1 The first object to pass when calling the selector on the
 *		  target
 * @param object2 The second object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (nullable id)object1
			       object: (nullable id)object2
			      repeats: (bool)repeats;

/**
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276







-
+







 * @param object2 The second object to pass when calling the selector on the
 *		  target
 * @param object3 The third object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (nullable id)object1
			       object: (nullable id)object2
			       object: (nullable id)object3
			      repeats: (bool)repeats;

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







-
+

















-
+

-
+

















-
+


















-
+







 * @param object3 The third object to pass when calling the selector on the
 *		  target
 * @param object4 The fourth object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return A new, autoreleased timer
 */
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (nullable id)object1
			       object: (nullable id)object2
			       object: (nullable id)object3
			       object: (nullable id)object4
			      repeats: (bool)repeats;

#ifdef OF_HAVE_BLOCKS
/**
 * @brief Creates a new timer with the specified time interval.
 *
 * @param timeInterval The time interval after which the timer should be fired
 * @param repeats Whether the timer repeats after it has been executed
 * @param block The block to invoke when the timer fires
 * @return A new, autoreleased timer
 */
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			      repeats: (bool)repeats
				block: (of_timer_block_t)block;
				block: (OFTimerBlock)block;
#endif

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated timer with the specified time
 *	  interval.
 *
 * @param fireDate The date at which the timer should fire
 * @param interval The time interval after which to repeat the timer, if it is
 *		   a repeating timer
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param repeats Whether the timer repeats after it has been executed
 * @return An initialized timer
 */
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			 repeats: (bool)repeats;

/**
 * @brief Initializes an already allocated timer with the specified time
 *	  interval.
 *
 * @param fireDate The date at which the timer should fire
 * @param interval The time interval after which to repeat the timer, if it is
 *		   a repeating timer
 * @param target The target on which to call the selector
 * @param selector The selector to call on the target
 * @param object An object to pass when calling the selector on the target
 * @param repeats Whether the timer repeats after it has been executed
 * @return An initialized timer
 */
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (nullable id)object
			 repeats: (bool)repeats;

/**
 * @brief Initializes an already allocated timer with the specified time
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







-
+







 *		  target
 * @param object2 The second object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return An initialized timer
 */
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (nullable id)object1
			  object: (nullable id)object2
			 repeats: (bool)repeats;

/**
393
394
395
396
397
398
399
400

401
402
403
404
405
406
407
393
394
395
396
397
398
399

400
401
402
403
404
405
406
407







-
+







 *		  target
 * @param object3 The third object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return An initialized timer
 */
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (nullable id)object1
			  object: (nullable id)object2
			  object: (nullable id)object3
			 repeats: (bool)repeats;

422
423
424
425
426
427
428
429

430
431
432
433
434
435
436
422
423
424
425
426
427
428

429
430
431
432
433
434
435
436







-
+







 *		  target
 * @param object4 The fourth object to pass when calling the selector on the
 *		  target
 * @param repeats Whether the timer repeats after it has been executed
 * @return An initialized timer
 */
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (nullable id)object1
			  object: (nullable id)object2
			  object: (nullable id)object3
			  object: (nullable id)object4
			 repeats: (bool)repeats;
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
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







-
+

-
+








-
+







 * @param interval The time interval after which to repeat the timer, if it is
 *		   a repeating timer
 * @param repeats Whether the timer repeats after it has been executed
 * @param block The block to invoke when the timer fires
 * @return An initialized timer
 */
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			 repeats: (bool)repeats
			   block: (of_timer_block_t)block;
			   block: (OFTimerBlock)block;
#endif

/**
 * @brief Compares the timer to another timer.
 *
 * @param timer The timer to compare the string to
 * @return The result of the comparison
 */
- (of_comparison_result_t)compare: (OFTimer *)timer;
- (OFComparisonResult)compare: (OFTimer *)timer;

/**
 * @brief Fires the timer, meaning it will execute the specified selector on the
 *	  target.
 */
- (void)fire;

Modified src/OFTimer.m from [a68714fb85] to [c82a64c489].

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







-
+




















-
+







#endif

#import "OFInvalidArgumentException.h"

@implementation OFTimer
@synthesize timeInterval = _interval, repeating = _repeats, valid = _valid;

+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
				       repeats: (bool)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: timeInterval
					    target: target
					  selector: selector
					   repeats: repeats] autorelease];

	[[OFRunLoop currentRunLoop] addTimer: timer];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (id)object
				       repeats: (bool)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval];
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







-
+








	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (id)object1
					object: (id)object2
				       repeats: (bool)repeats
{
	void *pool = objc_autoreleasePoolPush();
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







-
+








	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (id)object1
					object: (id)object2
					object: (id)object3
				       repeats: (bool)repeats
{
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139
125
126
127
128
129
130
131

132
133
134
135
136
137
138
139







-
+








	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
					target: (id)target
				      selector: (SEL)selector
					object: (id)object1
					object: (id)object2
					object: (id)object3
					object: (id)object4
				       repeats: (bool)repeats
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
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







-
+

-
+

















-
+


















-
+




















-
+







	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

#ifdef OF_HAVE_BLOCKS
+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval
				       repeats: (bool)repeats
					 block: (of_timer_block_t)block
					 block: (OFTimerBlock)block
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: timeInterval
					   repeats: repeats
					     block: block] autorelease];

	[[OFRunLoop currentRunLoop] addTimer: timer];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}
#endif

+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			      repeats: (bool)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: timeInterval
					    target: target
					  selector: selector
					   repeats: repeats] autorelease];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (id)object
			      repeats: (bool)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: timeInterval
					    target: target
					  selector: selector
					    object: object
					   repeats: repeats] autorelease];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (id)object1
			       object: (id)object2
			      repeats: (bool)repeats
{
	void *pool = objc_autoreleasePoolPush();
238
239
240
241
242
243
244
245

246
247
248
249
250
251
252
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252







-
+








	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (id)object1
			       object: (id)object2
			       object: (id)object3
			      repeats: (bool)repeats
{
263
264
265
266
267
268
269
270

271
272
273
274
275
276
277
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277







-
+








	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			       target: (id)target
			     selector: (SEL)selector
			       object: (id)object1
			       object: (id)object2
			       object: (id)object3
			       object: (id)object4
			      repeats: (bool)repeats
291
292
293
294
295
296
297
298

299
300

301
302
303
304
305
306
307
291
292
293
294
295
296
297

298
299

300
301
302
303
304
305
306
307







-
+

-
+







	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

#ifdef OF_HAVE_BLOCKS
+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval
+ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval
			      repeats: (bool)repeats
				block: (of_timer_block_t)block
				block: (OFTimerBlock)block
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: timeInterval
					   repeats: repeats
					     block: block] autorelease];
315
316
317
318
319
320
321
322

323
324
325
326
327
328
329
315
316
317
318
319
320
321

322
323
324
325
326
327
328
329







-
+








- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)of_initWithFireDate: (OFDate *)fireDate
			   interval: (of_time_interval_t)interval
			   interval: (OFTimeInterval)interval
			     target: (id)target
			   selector: (SEL)selector
			     object: (id)object1
			     object: (id)object2
			     object: (id)object3
			     object: (id)object4
			  arguments: (unsigned char)arguments
352
353
354
355
356
357
358
359

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
352
353
354
355
356
357
358

359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436

437
438
439
440
441
442
443
444







-
+

















-
+


















-
+



















-
+




















-
+







		@throw e;
	}

	return self;
}

- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			 repeats: (bool)repeats
{
	return [self of_initWithFireDate: fireDate
				interval: interval
				  target: target
				selector: selector
				  object: nil
				  object: nil
				  object: nil
				  object: nil
			       arguments: 0
				 repeats: repeats];
}

- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object
			 repeats: (bool)repeats
{
	return [self of_initWithFireDate: fireDate
				interval: interval
				  target: target
				selector: selector
				  object: object
				  object: nil
				  object: nil
				  object: nil
			       arguments: 1
				 repeats: repeats];
}

- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object1
			  object: (id)object2
			 repeats: (bool)repeats
{
	return [self of_initWithFireDate: fireDate
				interval: interval
				  target: target
				selector: selector
				  object: object1
				  object: object2
				  object: nil
				  object: nil
			       arguments: 2
				 repeats: repeats];
}

- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object1
			  object: (id)object2
			  object: (id)object3
			 repeats: (bool)repeats
{
	return [self of_initWithFireDate: fireDate
				interval: interval
				  target: target
				selector: selector
				  object: object1
				  object: object2
				  object: object3
				  object: nil
			       arguments: 3
				 repeats: repeats];
}

- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object1
			  object: (id)object2
			  object: (id)object3
			  object: (id)object4
			 repeats: (bool)repeats
453
454
455
456
457
458
459
460

461
462

463
464
465
466
467
468
469
453
454
455
456
457
458
459

460
461

462
463
464
465
466
467
468
469







-
+

-
+







				  object: object4
			       arguments: 4
				 repeats: repeats];
}

#ifdef OF_HAVE_BLOCKS
- (instancetype)initWithFireDate: (OFDate *)fireDate
			interval: (of_time_interval_t)interval
			interval: (OFTimeInterval)interval
			 repeats: (bool)repeats
			   block: (of_timer_block_t)block
			   block: (OFTimerBlock)block
{
	self = [super init];

	@try {
		_fireDate = [fireDate retain];
		_interval = interval;
		_repeats = repeats;
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
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







-
+







-
+


-
+







#ifdef OF_HAVE_THREADS
	[_condition release];
#endif

	[super dealloc];
}

- (of_comparison_result_t)compare: (OFTimer *)timer
- (OFComparisonResult)compare: (OFTimer *)timer
{
	if (![timer isKindOfClass: [OFTimer class]])
		@throw [OFInvalidArgumentException exception];

	return [_fireDate compare: timer->_fireDate];
}

- (void)of_setInRunLoop: (OFRunLoop *)runLoop mode: (of_run_loop_mode_t)mode
- (void)of_setInRunLoop: (OFRunLoop *)runLoop mode: (OFRunLoopMode)mode
{
	OFRunLoop *oldInRunLoop = _inRunLoop;
	of_run_loop_mode_t oldInRunLoopMode = _inRunLoopMode;
	OFRunLoopMode oldInRunLoopMode = _inRunLoopMode;

	_inRunLoop = [runLoop retain];
	[oldInRunLoop release];

	_inRunLoopMode = [mode copy];
	[oldInRunLoopMode release];
}
536
537
538
539
540
541
542
543

544
545
546
547
548
549
550
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550







-
+







	id object4 = [[_object4 retain] autorelease];

	OF_ENSURE(_arguments <= 4);

	if (_repeats && _valid) {
		int64_t missedIntervals =
		    -_fireDate.timeIntervalSinceNow / _interval;
		of_time_interval_t newFireDate;
		OFTimeInterval newFireDate;
		OFRunLoop *runLoop;

		/* In case the clock was changed backwards */
		if (missedIntervals < 0)
			missedIntervals = 0;

		newFireDate = _fireDate.timeIntervalSince1970 +

Modified src/OFUDPSocket+Private.h from [de17aba506] to [6c9ef7ed56].

15
16
17
18
19
20
21
22

23
24
25
26
15
16
17
18
19
20
21

22
23
24
25
26







-
+





#import "OFUDPSocket.h"

OF_ASSUME_NONNULL_BEGIN

OF_DIRECT_MEMBERS
@interface OFUDPSocket ()
- (uint16_t)of_bindToAddress: (of_socket_address_t *)address
- (uint16_t)of_bindToAddress: (OFSocketAddress *)address
		   extraType: (int)extraType;
@end

OF_ASSUME_NONNULL_END

Modified src/OFUDPSocket.h from [0c69733f4b] to [7fc9c66432].

28
29
30
31
32
33
34
35
36
37
38
39






40
41
42
43
44
45
46
28
29
30
31
32
33
34





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







-
-
-
-
-
+
+
+
+
+
+







@end

/**
 * @class OFUDPSocket OFUDPSocket.h ObjFW/OFUDPSocket.h
 *
 * @brief A class which provides methods to create and use UDP sockets.
 *
 * Addresses are of type @ref of_socket_address_t. You can use the current
 * thread's @ref OFDNSResolver to create an address for a host / port pair and
 * @ref of_socket_address_ip_string to get the IP string / port pair for an
 * address. If you want to compare two addresses, you can use @ref
 * of_socket_address_equal and you can use @ref of_socket_address_hash to get a
 * Addresses are of type @ref OFSocketAddress. You can use the current thread's
 * @ref OFDNSResolver to create an address for a host / port pair,
 * @ref OFSocketAddressString to get the IP address string for an address and
 * @ref OFSocketAddressPort to get the port for an address. If you want to
 * compare two addresses, you can use
 * @ref OFSocketAddressEqual and you can use @ref OFSocketAddressHash to get a
 * hash to use in e.g. @ref OFMapTable.
 *
 * @warning Even though the OFCopying protocol is implemented, it does *not*
 *	    return an independent copy of the socket, but instead retains it.
 *	    This is so that the socket can be used as a key for a dictionary,
 *	    so context can be associated with a socket. Using a socket in more
 *	    than one thread at the same time is not thread-safe, even if copy

Modified src/OFUDPSocket.m from [ab91d5347a] to [b4763512f7].

37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52
53
54
55

56
57
58
59


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

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





88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144





145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161





162
163
164
165
166
167
168
169
170
171





172
173
174
175
176
177
178
179

180
181
182
183
184
185
186

187
188
189


190
191
192
193
194
195
196
197
37
38
39
40
41
42
43

44
45
46
47

48
49
50
51
52
53

54

55


56
57
58
59

60
61
62
63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78
79





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

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110


111
112
113
114
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136





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





154
155
156
157
158
159
160
161
162
163





164
165
166
167
168
169
170
171
172
173
174
175

176
177
178
179
180
181
182

183
184


185
186
187
188
189
190
191
192
193
194







-
+



-






-
+
-

-
-
+
+


-











-
+








-
-
-
-
-
+
+
+
+
+










-
+









+
+




-
-












-
+













-
-
-
-
-
+
+
+
+
+












-
-
-
-
-
+
+
+
+
+





-
-
-
-
-
+
+
+
+
+







-
+






-
+

-
-
+
+









#import "socket.h"
#import "socket_helpers.h"

@implementation OFUDPSocket
@dynamic delegate;

- (uint16_t)of_bindToAddress: (of_socket_address_t *)address
- (uint16_t)of_bindToAddress: (OFSocketAddress *)address
		   extraType: (int)extraType OF_DIRECT
{
	void *pool = objc_autoreleasePoolPush();
	OFString *host;
	uint16_t port;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
#endif

	if ((_socket = socket(address->sockaddr.sockaddr.sa_family,
	    SOCK_DGRAM | SOCK_CLOEXEC | extraType, 0)) == INVALID_SOCKET) {
	    SOCK_DGRAM | SOCK_CLOEXEC | extraType, 0)) == INVALID_SOCKET)
		host = of_socket_address_ip_string(address, &port);
		@throw [OFBindFailedException
		    exceptionWithHost: host
				 port: port
		    exceptionWithHost: OFSocketAddressString(address)
				 port: OFSocketAddressPort(address)
			       socket: self
				errNo: of_socket_errno()];
	}

	_canBlock = true;

#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	/* {} needed to avoid warning with Clang 10 if next #if is false. */
	if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) {
		fcntl(_socket, F_SETFD, flags | FD_CLOEXEC);
	}
#endif

#if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS)
	if (of_socket_address_get_port(address) != 0) {
	if (OFSocketAddressPort(address) != 0) {
#endif
		if (bind(_socket, &address->sockaddr.sockaddr,
		    address->length) != 0) {
			int errNo = of_socket_errno();

			closesocket(_socket);
			_socket = INVALID_SOCKET;

			host = of_socket_address_ip_string(address, &port);
			@throw [OFBindFailedException exceptionWithHost: host
								   port: port
								 socket: self
								  errNo: errNo];
			@throw [OFBindFailedException
			    exceptionWithHost: OFSocketAddressString(address)
					 port: OFSocketAddressPort(address)
				       socket: self
					errNo: errNo];
		}
#if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS)
	} else {
		for (;;) {
			uint16_t rnd = 0;
			int ret;

			while (rnd < 1024)
				rnd = (uint16_t)rand();

			of_socket_address_set_port(address, rnd);
			OFSocketAddressSetPort(address, rnd);

			if ((ret = bind(_socket, &address->sockaddr.sockaddr,
			    address->length)) == 0) {
				port = rnd;
				break;
			}

			if (of_socket_errno() != EADDRINUSE) {
				int errNo = of_socket_errno();
				OFString *host = OFSocketAddressString(address);
				uint16_t port = OFSocketAddressPort(port);

				closesocket(_socket);
				_socket = INVALID_SOCKET;

				host = of_socket_address_ip_string(
				    address, &port);
				@throw [OFBindFailedException
				    exceptionWithHost: host
						 port: port
					       socket: self
						errNo: errNo];
			}
		}
	}
#endif

	objc_autoreleasePoolPop(pool);

	if ((port = of_socket_address_get_port(address)) > 0)
	if ((port = OFSocketAddressPort(address)) > 0)
		return port;

#if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
	memset(address, 0, sizeof(*address));

	address->length = (socklen_t)sizeof(address->sockaddr);
	if (of_getsockname(_socket, &address->sockaddr.sockaddr,
	    &address->length) != 0) {
		int errNo = of_socket_errno();

		closesocket(_socket);
		_socket = INVALID_SOCKET;

		host = of_socket_address_ip_string(address, &port);
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self
							  errNo: errNo];
		@throw [OFBindFailedException
		    exceptionWithHost: OFSocketAddressString(address)
				 port: OFSocketAddressPort(address)
			       socket: self
				errNo: errNo];
	}

	if (address->sockaddr.sockaddr.sa_family == AF_INET)
		return OF_BSWAP16_IF_LE(address->sockaddr.in.sin_port);
# ifdef OF_HAVE_IPV6
	else if (address->sockaddr.sockaddr.sa_family == AF_INET6)
		return OF_BSWAP16_IF_LE(address->sockaddr.in6.sin6_port);
# endif
	else {
		closesocket(_socket);
		_socket = INVALID_SOCKET;

		host = of_socket_address_ip_string(address, &port);
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self
							  errNo: EAFNOSUPPORT];
		@throw [OFBindFailedException
		    exceptionWithHost: OFSocketAddressString(address)
				 port: OFSocketAddressPort(address)
			       socket: self
				errNo: EAFNOSUPPORT];
	}
#else
	closesocket(_socket);
	_socket = INVALID_SOCKET;

	host = of_socket_address_ip_string(address, &port);
	@throw [OFBindFailedException exceptionWithHost: host
						   port: port
						 socket: self
						  errNo: EADDRNOTAVAIL];
	@throw [OFBindFailedException
	    exceptionWithHost: OFSocketAddressString(address)
			 port: OFSocketAddressPort(address)
		       socket: self
			errNo: EADDRNOTAVAIL];
#endif
}

- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port
{
	void *pool = objc_autoreleasePoolPush();
	OFData *socketAddresses;
	of_socket_address_t address;
	OFSocketAddress address;

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	socketAddresses = [[OFThread DNSResolver]
	    resolveAddressesForHost: host
		      addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY];
		      addressFamily: OFSocketAddressFamilyAny];

	address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0];
	of_socket_address_set_port(&address, port);
	address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0];
	OFSocketAddressSetPort(&address, port);

	port = [self of_bindToAddress: &address extraType: 0];

	objc_autoreleasePoolPop(pool);

	return port;
}
@end

Modified src/OFURL.m from [c6fcf8ea2f] to [67b8d12e14].

97
98
99
100
101
102
103
104

105
106
107
108
109
110
111
97
98
99
100
101
102
103

104
105
106
107
108
109
110
111







-
+







	    [[OFURLQueryKeyValueAllowedCharacterSet alloc] init];
}

OF_DIRECT_MEMBERS
@interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet
{
	OFCharacterSet *_characterSet;
	bool (*_characterIsMember)(id, SEL, of_unichar_t);
	bool (*_characterIsMember)(id, SEL, OFUnichar);
}

- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet;
@end

bool
of_url_is_ipv6_host(OFString *host)
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







-
+







- (unsigned int)retainCount
{
	return OF_RETAIN_COUNT_MAX;
}
@end

@implementation OFURLAllowedCharacterSet
- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character < CHAR_MAX && of_ascii_isalnum(character))
		return true;

	switch (character) {
	case '-':
	case '.':
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
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







-
+
















-
+







	default:
		return false;
	}
}
@end

@implementation OFURLSchemeAllowedCharacterSet
- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character < CHAR_MAX && of_ascii_isalnum(character))
		return true;

	switch (character) {
	case '+':
	case '-':
	case '.':
		return true;
	default:
		return false;
	}
}
@end

@implementation OFURLPathAllowedCharacterSet
- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character < CHAR_MAX && of_ascii_isalnum(character))
		return true;

	switch (character) {
	case '-':
	case '.':
224
225
226
227
228
229
230
231

232
233
234
235
236
237
238
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238







-
+







	default:
		return false;
	}
}
@end

@implementation OFURLQueryOrFragmentAllowedCharacterSet
- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character < CHAR_MAX && of_ascii_isalnum(character))
		return true;

	switch (character) {
	case '-':
	case '.':
257
258
259
260
261
262
263
264

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

264
265
266
267
268
269
270
271







-
+







	default:
		return false;
	}
}
@end

@implementation OFURLQueryKeyValueAllowedCharacterSet
- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	if (character < CHAR_MAX && of_ascii_isalnum(character))
		return true;

	switch (character) {
	case '-':
	case '.':
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
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







-
+

















-
+














-
+







@implementation OFInvertedCharacterSetWithoutPercent
- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet
{
	self = [super init];

	@try {
		_characterSet = [characterSet retain];
		_characterIsMember = (bool (*)(id, SEL, of_unichar_t))
		_characterIsMember = (bool (*)(id, SEL, OFUnichar))
		    [_characterSet methodForSelector:
		    @selector(characterIsMember:)];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_characterSet release];

	[super dealloc];
}

- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	return (character != '%' && !_characterIsMember(_characterSet,
	    @selector(characterIsMember:), character));
}
@end

void
of_url_verify_escaped(OFString *string, OFCharacterSet *characterSet)
{
	void *pool = objc_autoreleasePoolPush();

	characterSet = [[[OFInvertedCharacterSetWithoutPercent alloc]
	    initWithCharacterSet: characterSet] autorelease];

	if ([string indexOfCharacterFromSet: characterSet] != OF_NOT_FOUND)
	if ([string indexOfCharacterFromSet: characterSet] != OFNotFound)
		@throw [OFInvalidFormatException exception];

	objc_autoreleasePoolPop(pool);
}

@implementation OFCharacterSet (URLCharacterSets)
+ (OFCharacterSet *)URLSchemeAllowedCharacterSet
672
673
674
675
676
677
678
679

680
681

682
683

684
685
686
687
688
689
690
672
673
674
675
676
677
678

679
680

681
682

683
684
685
686
687
688
689
690







-
+

-
+

-
+







				    copy];
			else {
				OFMutableString *path = [OFMutableString
				    stringWithString:
				    (URL->_URLEncodedPath != nil
				    ? URL->_URLEncodedPath
				    : @"/")];
				of_range_t range = [path
				OFRange range = [path
				    rangeOfString: @"/"
					  options: OF_STRING_SEARCH_BACKWARDS];
					  options: OFStringSearchBackwards];

				if (range.location == OF_NOT_FOUND)
				if (range.location == OFNotFound)
					@throw [OFInvalidFormatException
					    exception];

				range.location++;
				range.length = path.length - range.location;

				[path replaceCharactersInRange: range
875
876
877
878
879
880
881
882

883
884
885
886
887
888
889
875
876
877
878
879
880
881

882
883
884
885
886
887
888
889







-
+







}

- (OFString *)host
{
	if ([_URLEncodedHost hasPrefix: @"["] &&
	    [_URLEncodedHost hasSuffix: @"]"]) {
		OFString *host = [_URLEncodedHost substringWithRange:
		    of_range(1, _URLEncodedHost.length - 2)];
		    OFMakeRange(1, _URLEncodedHost.length - 2)];

		if (!of_url_is_ipv6_host(host))
			@throw [OFInvalidArgumentException exception];

		return host;
	}

Modified src/OFURLHandler.h from [9ec6927971] to [aebd1b72ac].

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







-
+

-
+









-
-
+







- (OFStream *)openItemAtURL: (OFURL *)URL mode: (OFString *)mode;

/**
 * @brief Returns the attributes for the item at the specified URL.
 *
 * @param URL The URL to return the attributes for
 * @return A dictionary of attributes for the specified URL, with the keys of
 *	   type @ref of_file_attribute_key_t
 *	   type @ref OFFileAttributeKey
 */
- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL;
- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL;

/**
 * @brief Sets the attributes for the item at the specified URL.
 *
 * All attributes not part of the dictionary are left unchanged.
 *
 * @param attributes The attributes to set for the specified URL
 * @param URL The URL of the item to set the attributes for
 */
- (void)setAttributes: (of_file_attributes_t)attributes
	  ofItemAtURL: (OFURL *)URL;
- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL;

/**
 * @brief Checks whether a file exists at the specified URL.
 *
 * @param URL The URL to check
 * @return A boolean whether there is a file at the specified URL
 */

Modified src/OFURLHandler.m from [7996e25454] to [d88aa91e77].

136
137
138
139
140
141
142
143

144
145
146
147
148
149

150
151
152
153
154
155
156
136
137
138
139
140
141
142

143
144
145
146
147


148
149
150
151
152
153
154
155







-
+




-
-
+







}

- (OFStream *)openItemAtURL: (OFURL *)URL mode: (OFString *)mode
{
	OF_UNRECOGNIZED_SELECTOR
}

- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL
- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)setAttributes: (of_file_attributes_t)attributes
	  ofItemAtURL: (OFURL *)URL
- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL
{
	OF_UNRECOGNIZED_SELECTOR
}

- (bool)fileExistsAtURL: (OFURL *)URL
{
	OF_UNRECOGNIZED_SELECTOR

Modified src/OFUTF8String.m from [2057b791a1] to [325d0971b0].

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







-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+













-
+

-
+


-
+







#import "OFInvalidFormatException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"

#import "of_asprintf.h"
#import "unicode.h"

extern const of_char16_t of_iso_8859_2_table[];
extern const OFChar16 of_iso_8859_2_table[];
extern const size_t of_iso_8859_2_table_offset;
extern const of_char16_t of_iso_8859_3_table[];
extern const OFChar16 of_iso_8859_3_table[];
extern const size_t of_iso_8859_3_table_offset;
extern const of_char16_t of_iso_8859_15_table[];
extern const OFChar16 of_iso_8859_15_table[];
extern const size_t of_iso_8859_15_table_offset;
extern const of_char16_t of_windows_1251_table[];
extern const OFChar16 of_windows_1251_table[];
extern const size_t of_windows_1251_table_offset;
extern const of_char16_t of_windows_1252_table[];
extern const OFChar16 of_windows_1252_table[];
extern const size_t of_windows_1252_table_offset;
extern const of_char16_t of_codepage_437_table[];
extern const OFChar16 of_codepage_437_table[];
extern const size_t of_codepage_437_table_offset;
extern const of_char16_t of_codepage_850_table[];
extern const OFChar16 of_codepage_850_table[];
extern const size_t of_codepage_850_table_offset;
extern const of_char16_t of_codepage_858_table[];
extern const OFChar16 of_codepage_858_table[];
extern const size_t of_codepage_858_table_offset;
extern const of_char16_t of_mac_roman_table[];
extern const OFChar16 of_mac_roman_table[];
extern const size_t of_mac_roman_table_offset;
extern const of_char16_t of_koi8_r_table[];
extern const OFChar16 of_koi8_r_table[];
extern const size_t of_koi8_r_table_offset;
extern const of_char16_t of_koi8_u_table[];
extern const OFChar16 of_koi8_u_table[];
extern const size_t of_koi8_u_table_offset;

static inline int
memcasecmp(const char *first, const char *second, size_t length)
{
	for (size_t i = 0; i < length; i++) {
		unsigned char f = first[i];
		unsigned char s = second[i];

		f = of_ascii_toupper(f);
		s = of_ascii_toupper(s);

		if (f > s)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		if (f < s)
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;
	}

	return OF_ORDERED_SAME;
	return OFOrderedSame;
}

int
of_string_utf8_check(const char *UTF8String, size_t UTF8Length, size_t *length)
{
	size_t tmpLength = UTF8Length;
	int isUTF8 = 0;
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
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







-
+





-
+


-
+












-
-
+
+



-
+


















-
+







		@throw e;
	}

	return self;
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)cStringLength
{
	self = [super init];

	@try {
		const of_char16_t *table;
		const OFChar16 *table;
		size_t tableOffset, j;

		if (encoding == OF_STRING_ENCODING_UTF_8 &&
		if (encoding == OFStringEncodingUTF8 &&
		    cStringLength >= 3 &&
		    memcmp(cString, "\xEF\xBB\xBF", 3) == 0) {
			cString += 3;
			cStringLength -= 3;
		}

		_s = &_storage;

		_s->cString = of_alloc(cStringLength + 1, 1);
		_s->cStringLength = cStringLength;
		_s->freeWhenDone = true;

		if (encoding == OF_STRING_ENCODING_UTF_8 ||
		    encoding == OF_STRING_ENCODING_ASCII) {
		if (encoding == OFStringEncodingUTF8 ||
		    encoding == OFStringEncodingASCII) {
			switch (of_string_utf8_check(cString, cStringLength,
			    &_s->length)) {
			case 1:
				if (encoding == OF_STRING_ENCODING_ASCII)
				if (encoding == OFStringEncodingASCII)
					@throw [OFInvalidEncodingException
					    exception];

				_s->isUTF8 = true;
				break;
			case -1:
				@throw [OFInvalidEncodingException exception];
			}

			memcpy(_s->cString, cString, cStringLength);
			_s->cString[cStringLength] = 0;

			return self;
		}

		/* All other encodings we support are single byte encodings */
		_s->length = cStringLength;

		if (encoding == OF_STRING_ENCODING_ISO_8859_1) {
		if (encoding == OFStringEncodingISO8859_1) {
			j = 0;
			for (size_t i = 0; i < cStringLength; i++) {
				char buffer[4];
				size_t bytes;

				if (!(cString[i] & 0x80)) {
					_s->cString[j++] = cString[i];
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
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







-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+









-
+







		switch (encoding) {
#define CASE(encoding, var)				\
		case encoding:				\
			table = var;			\
			tableOffset = var##_offset;	\
			break;
#ifdef HAVE_ISO_8859_2
		CASE(OF_STRING_ENCODING_ISO_8859_2, of_iso_8859_2_table)
		CASE(OFStringEncodingISO8859_2, of_iso_8859_2_table)
#endif
#ifdef HAVE_ISO_8859_3
		CASE(OF_STRING_ENCODING_ISO_8859_3, of_iso_8859_3_table)
		CASE(OFStringEncodingISO8859_3, of_iso_8859_3_table)
#endif
#ifdef HAVE_ISO_8859_15
		CASE(OF_STRING_ENCODING_ISO_8859_15, of_iso_8859_15_table)
		CASE(OFStringEncodingISO8859_15, of_iso_8859_15_table)
#endif
#ifdef HAVE_WINDOWS_1251
		CASE(OF_STRING_ENCODING_WINDOWS_1251, of_windows_1251_table)
		CASE(OFStringEncodingWindows1251, of_windows_1251_table)
#endif
#ifdef HAVE_WINDOWS_1252
		CASE(OF_STRING_ENCODING_WINDOWS_1252, of_windows_1252_table)
		CASE(OFStringEncodingWindows1252, of_windows_1252_table)
#endif
#ifdef HAVE_CODEPAGE_437
		CASE(OF_STRING_ENCODING_CODEPAGE_437, of_codepage_437_table)
		CASE(OFStringEncodingCodepage437, of_codepage_437_table)
#endif
#ifdef HAVE_CODEPAGE_850
		CASE(OF_STRING_ENCODING_CODEPAGE_850, of_codepage_850_table)
		CASE(OFStringEncodingCodepage850, of_codepage_850_table)
#endif
#ifdef HAVE_CODEPAGE_858
		CASE(OF_STRING_ENCODING_CODEPAGE_858, of_codepage_858_table)
		CASE(OFStringEncodingCodepage858, of_codepage_858_table)
#endif
#ifdef HAVE_MAC_ROMAN
		CASE(OF_STRING_ENCODING_MAC_ROMAN, of_mac_roman_table)
		CASE(OFStringEncodingMacRoman, of_mac_roman_table)
#endif
#ifdef HAVE_KOI8_R
		CASE(OF_STRING_ENCODING_KOI8_R, of_koi8_r_table)
		CASE(OFStringEncodingKOI8R, of_koi8_r_table)
#endif
#ifdef HAVE_KOI8_U
		CASE(OF_STRING_ENCODING_KOI8_U, of_koi8_u_table)
		CASE(OFStringEncodingKOI8U, of_koi8_u_table)
#endif
#undef CASE
		default:
			@throw [OFInvalidEncodingException exception];
		}

		j = 0;
		for (size_t i = 0; i < cStringLength; i++) {
			unsigned char character = (unsigned char)cString[i];
			of_unichar_t unichar;
			OFUnichar unichar;
			char buffer[4];
			size_t byteLength;

			if (character < tableOffset) {
				_s->cString[j++] = cString[i];
				continue;
			}
457
458
459
460
461
462
463
464

465
466
467
468
469
470
471
457
458
459
460
461
462
463

464
465
466
467
468
469
470
471







-
+







		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithCharacters: (const of_unichar_t *)characters
- (instancetype)initWithCharacters: (const OFUnichar *)characters
			    length: (size_t)length
{
	self = [super init];

	@try {
		size_t j;

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







-
+

-
+














-
+










-
+








-
+







		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithUTF16String: (const of_char16_t *)string
- (instancetype)initWithUTF16String: (const OFChar16 *)string
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	self = [super init];

	@try {
		size_t j;
		bool swap = false;

		if (length > 0 && *string == 0xFEFF) {
			string++;
			length--;
		} else if (length > 0 && *string == 0xFFFE) {
			swap = true;
			string++;
			length--;
		} else if (byteOrder != OF_BYTE_ORDER_NATIVE)
		} else if (byteOrder != OFByteOrderNative)
			swap = true;

		_s = &_storage;

		_s->cString = of_alloc((length * 4) + 1, 1);
		_s->length = length;
		_s->freeWhenDone = true;

		j = 0;
		for (size_t i = 0; i < length; i++) {
			of_unichar_t character =
			OFUnichar character =
			    (swap ? OF_BSWAP16(string[i]) : string[i]);
			size_t len;

			/* Missing high surrogate */
			if ((character & 0xFC00) == 0xDC00)
				@throw [OFInvalidEncodingException exception];

			if ((character & 0xFC00) == 0xD800) {
				of_char16_t nextCharacter;
				OFChar16 nextCharacter;

				if (length <= i + 1)
					@throw [OFInvalidEncodingException
					    exception];

				nextCharacter = (swap
				    ? OF_BSWAP16(string[i + 1])
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
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







-
+

-
+














-
+







		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithUTF32String: (const of_char32_t *)characters
- (instancetype)initWithUTF32String: (const OFChar32 *)characters
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	self = [super init];

	@try {
		size_t j;
		bool swap = false;

		if (length > 0 && *characters == 0xFEFF) {
			characters++;
			length--;
		} else if (length > 0 && *characters == 0xFFFE0000) {
			swap = true;
			characters++;
			length--;
		} else if (byteOrder != OF_BYTE_ORDER_NATIVE)
		} else if (byteOrder != OFByteOrderNative)
			swap = true;

		_s = &_storage;

		_s->cString = of_alloc((length * 4) + 1, 1);
		_s->length = length;
		_s->freeWhenDone = true;
707
708
709
710
711
712
713
714

715
716
717

718
719
720
721

722
723
724
725
726
727
728
729
730
731
732
733
734
735

736
737
738

739
740
741
742

743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759

760
761
762
763


764
765
766
767
768
769
770
707
708
709
710
711
712
713

714
715
716

717
718
719
720

721
722
723
724
725
726
727
728
729
730
731
732
733
734

735
736
737

738
739
740
741

742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758

759
760
761


762
763
764
765
766
767
768
769
770







-
+


-
+



-
+













-
+


-
+



-
+
















-
+


-
-
+
+







		free(_s->cString);

	[super dealloc];
}

- (size_t)getCString: (char *)cString
	   maxLength: (size_t)maxLength
	    encoding: (of_string_encoding_t)encoding
	    encoding: (OFStringEncoding)encoding
{
	switch (encoding) {
	case OF_STRING_ENCODING_ASCII:
	case OFStringEncodingASCII:
		if (_s->isUTF8)
			@throw [OFInvalidEncodingException exception];
		/* intentional fall-through */
	case OF_STRING_ENCODING_UTF_8:
	case OFStringEncodingUTF8:
		if (_s->cStringLength + 1 > maxLength)
			@throw [OFOutOfRangeException exception];

		memcpy(cString, _s->cString, _s->cStringLength + 1);

		return _s->cStringLength;
	default:
		return [super getCString: cString
			       maxLength: maxLength
				encoding: encoding];
	}
}

- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding
- (const char *)cStringWithEncoding: (OFStringEncoding)encoding
{
	switch (encoding) {
	case OF_STRING_ENCODING_ASCII:
	case OFStringEncodingASCII:
		if (_s->isUTF8)
			@throw [OFInvalidEncodingException exception];
		/* intentional fall-through */
	case OF_STRING_ENCODING_UTF_8:
	case OFStringEncodingUTF8:
		return _s->cString;
	default:
		return [super cStringWithEncoding: encoding];
	}
}

- (const char *)UTF8String
{
	return _s->cString;
}

- (size_t)length
{
	return _s->length;
}

- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding
- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding
{
	switch (encoding) {
	case OF_STRING_ENCODING_UTF_8:
	case OF_STRING_ENCODING_ASCII:
	case OFStringEncodingUTF8:
	case OFStringEncodingASCII:
		return _s->cStringLength;
	default:
		return [super cStringLengthWithEncoding: encoding];
	}
}

- (size_t)UTF8StringLength
795
796
797
798
799
800
801
802

803
804
805
806
807
808

809
810
811
812
813
814
815
816
817
818
819
820

821
822
823


824
825
826
827

828
829

830
831
832

833
834
835
836
837
838
839
840
841
842

843
844
845
846
847
848
849
850
851
852
853
854
855
856

857
858
859


860
861
862
863

864
865

866
867
868
869
870
871
872

873
874
875
876
877
878
879
880
881
882
883
884

885
886
887
888
889
890
891
892

893
894
895
896
897
898
899
900

901
902

903
904
905
906
907
908
909

910
911

912
913
914

915
916
917
918
919
920
921
922
923
924
925
926
927

928
929
930
931
932
933
934
795
796
797
798
799
800
801

802
803
804
805
806
807

808
809
810
811
812
813
814
815
816
817
818
819

820
821


822
823
824
825
826

827
828

829
830
831

832
833
834
835
836
837
838
839
840
841

842
843
844
845
846
847
848
849
850
851
852
853
854
855

856
857


858
859
860
861
862

863
864

865
866
867
868
869
870
871

872
873
874
875
876
877
878
879
880
881
882
883

884
885
886
887
888
889
890
891

892
893
894
895
896
897
898
899

900
901

902
903
904
905
906
907
908

909
910

911
912
913

914
915
916
917
918
919
920
921
922
923
924
925
926

927
928
929
930
931
932
933
934







-
+





-
+











-
+

-
-
+
+



-
+

-
+


-
+









-
+













-
+

-
-
+
+



-
+

-
+






-
+











-
+







-
+







-
+

-
+






-
+

-
+


-
+












-
+








	if (strcmp(_s->cString, string.UTF8String) != 0)
		return false;

	return true;
}

- (of_comparison_result_t)compare: (OFString *)string
- (OFComparisonResult)compare: (OFString *)string
{
	size_t otherCStringLength, minimumCStringLength;
	int compare;

	if (string == self)
		return OF_ORDERED_SAME;
		return OFOrderedSame;

	if (![string isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];

	otherCStringLength = string.UTF8StringLength;
	minimumCStringLength = (_s->cStringLength > otherCStringLength
	    ? otherCStringLength : _s->cStringLength);

	if ((compare = memcmp(_s->cString, string.UTF8String,
	    minimumCStringLength)) == 0) {
		if (_s->cStringLength > otherCStringLength)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		if (_s->cStringLength < otherCStringLength)
			return OF_ORDERED_ASCENDING;
		return OF_ORDERED_SAME;
			return OFOrderedAscending;
		return OFOrderedSame;
	}

	if (compare > 0)
		return OF_ORDERED_DESCENDING;
		return OFOrderedDescending;
	else
		return OF_ORDERED_ASCENDING;
		return OFOrderedAscending;
}

- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)string
- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string
{
	const char *otherCString;
	size_t otherCStringLength, minimumCStringLength;
#ifdef OF_HAVE_UNICODE_TABLES
	size_t i, j;
#endif
	int compare;

	if (string == self)
		return OF_ORDERED_SAME;
		return OFOrderedSame;

	otherCString = string.UTF8String;
	otherCStringLength = string.UTF8StringLength;

#ifdef OF_HAVE_UNICODE_TABLES
	if (!_s->isUTF8) {
#endif
		minimumCStringLength = (_s->cStringLength > otherCStringLength
		    ? otherCStringLength : _s->cStringLength);

		if ((compare = memcasecmp(_s->cString, otherCString,
		    minimumCStringLength)) == 0) {
			if (_s->cStringLength > otherCStringLength)
				return OF_ORDERED_DESCENDING;
				return OFOrderedDescending;
			if (_s->cStringLength < otherCStringLength)
				return OF_ORDERED_ASCENDING;
			return OF_ORDERED_SAME;
				return OFOrderedAscending;
			return OFOrderedSame;
		}

		if (compare > 0)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		else
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;
#ifdef OF_HAVE_UNICODE_TABLES
	}

	i = j = 0;

	while (i < _s->cStringLength && j < otherCStringLength) {
		of_unichar_t c1, c2;
		OFUnichar c1, c2;
		ssize_t l1, l2;

		l1 = of_string_utf8_decode(_s->cString + i,
		    _s->cStringLength - i, &c1);
		l2 = of_string_utf8_decode(otherCString + j,
		    otherCStringLength - j, &c2);

		if (l1 <= 0 || l2 <= 0 || c1 > 0x10FFFF || c2 > 0x10FFFF)
			@throw [OFInvalidEncodingException exception];

		if (c1 >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) {
			of_unichar_t tc =
			OFUnichar tc =
			    of_unicode_casefolding_table[c1 >> 8][c1 & 0xFF];

			if (tc)
				c1 = tc;
		}

		if (c2 >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) {
			of_unichar_t tc =
			OFUnichar tc =
			    of_unicode_casefolding_table[c2 >> 8][c2 & 0xFF];

			if (tc)
				c2 = tc;
		}

		if (c1 > c2)
			return OF_ORDERED_DESCENDING;
			return OFOrderedDescending;
		if (c1 < c2)
			return OF_ORDERED_ASCENDING;
			return OFOrderedAscending;

		i += l1;
		j += l2;
	}

	if (_s->cStringLength - i > otherCStringLength - j)
		return OF_ORDERED_DESCENDING;
		return OFOrderedDescending;
	else if (_s->cStringLength - i < otherCStringLength - j)
		return OF_ORDERED_ASCENDING;
		return OFOrderedAscending;
#endif

	return OF_ORDERED_SAME;
	return OFOrderedSame;
}

- (unsigned long)hash
{
	uint32_t hash;

	if (_s->hashed)
		return _s->hash;

	OF_HASH_INIT(hash);

	for (size_t i = 0; i < _s->cStringLength; i++) {
		of_unichar_t c;
		OFUnichar c;
		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);
942
943
944
945
946
947
948
949

950
951

952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968

969
970
971
972

973
974
975
976
977
978
979

980
981
982
983
984
985
986



987
988
989
990
991
992
993
942
943
944
945
946
947
948

949
950

951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967

968
969
970
971

972
973
974
975
976
977
978

979
980
981
982
983



984
985
986
987
988
989
990
991
992
993







-
+

-
+
















-
+



-
+






-
+




-
-
-
+
+
+








	_s->hash = hash;
	_s->hashed = true;

	return hash;
}

- (of_unichar_t)characterAtIndex: (size_t)idx
- (OFUnichar)characterAtIndex: (size_t)idx
{
	of_unichar_t character;
	OFUnichar character;

	if (idx >= _s->length)
		@throw [OFOutOfRangeException exception];

	if (!_s->isUTF8)
		return _s->cString[idx];

	idx = of_string_utf8_get_position(_s->cString, idx, _s->cStringLength);

	if (of_string_utf8_decode(_s->cString + idx,
	    _s->cStringLength - idx, &character) <= 0)
		@throw [OFInvalidEncodingException exception];

	return character;
}

- (void)getCharacters: (of_unichar_t *)buffer inRange: (of_range_t)range
- (void)getCharacters: (OFUnichar *)buffer inRange: (OFRange)range
{
	/* TODO: Could be slightly optimized */
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = self.characters;
	const OFUnichar *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));
	    range.length * sizeof(OFUnichar));

	objc_autoreleasePoolPop(pool);
}

- (of_range_t)rangeOfString: (OFString *)string
		    options: (int)options
		      range: (of_range_t)range
- (OFRange)rangeOfString: (OFString *)string
		 options: (OFStringSearchOptions)options
		   range: (OFRange)range
{
	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)
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
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







-
+


-
+

-
+












-
+














-
+




















-
+







		    _s->cStringLength - rangeLocation);
	} else {
		rangeLocation = range.location;
		rangeLength = range.length;
	}

	if (cStringLength == 0)
		return of_range(0, 0);
		return OFMakeRange(0, 0);

	if (cStringLength > rangeLength)
		return of_range(OF_NOT_FOUND, 0);
		return OFMakeRange(OFNotFound, 0);

	if (options & OF_STRING_SEARCH_BACKWARDS) {
	if (options & OFStringSearchBackwards) {
		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;

				return range;
			}

			/* Did not match and we're at the last char */
			if (i == 0)
				return of_range(OF_NOT_FOUND, 0);
				return OFMakeRange(OFNotFound, 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;

				return range;
			}
		}
	}

	return of_range(OF_NOT_FOUND, 0);
	return OFMakeRange(OFNotFound, 0);
}

- (bool)containsString: (OFString *)string
{
	const char *cString = string.UTF8String;
	size_t cStringLength = string.UTF8StringLength;

	if (cStringLength == 0)
		return true;

	if (cStringLength > _s->cStringLength)
		return false;

	for (size_t i = 0; i <= _s->cStringLength - cStringLength; i++)
		if (memcmp(_s->cString + i, cString, cStringLength) == 0)
			return true;

	return false;
}

- (OFString *)substringWithRange: (of_range_t)range
- (OFString *)substringWithRange: (OFRange)range
{
	size_t start = range.location;
	size_t end = range.location + range.length;

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

1096
1097
1098
1099
1100
1101
1102
1103

1104
1105
1106
1107
1108
1109

1110
1111
1112
1113
1114
1115
1116
1096
1097
1098
1099
1100
1101
1102

1103
1104
1105
1106
1107
1108

1109
1110
1111
1112
1113
1114
1115
1116







-
+





-
+







		return false;

	return (memcmp(_s->cString + (_s->cStringLength - cStringLength),
	    suffix.UTF8String, cStringLength) == 0);
}

- (OFArray *)componentsSeparatedByString: (OFString *)delimiter
				 options: (int)options
				 options: (OFStringSeparationOptions)options
{
	void *pool;
	OFMutableArray *array;
	const char *cString;
	size_t cStringLength;
	bool skipEmpty = (options & OF_STRING_SKIP_EMPTY);
	bool skipEmpty = (options & OFStringSkipEmptyComponents);
	size_t last;
	OFString *component;

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

	if (delimiter.length == 0)
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
1220
1221
1222
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
1220
1221
1222







-
+

-
+



-
+
















-
+



-
+

-
+



-
+










-
+










-
+




-
+







	[array makeImmutable];

	objc_autoreleasePoolPop(pool);

	return array;
}

- (const of_unichar_t *)characters
- (const OFUnichar *)characters
{
	of_unichar_t *buffer = of_alloc(_s->length, sizeof(of_unichar_t));
	OFUnichar *buffer = of_alloc(_s->length, sizeof(OFUnichar));
	size_t i = 0, j = 0;

	while (i < _s->cStringLength) {
		of_unichar_t c;
		OFUnichar c;
		ssize_t cLen;

		cLen = of_string_utf8_decode(_s->cString + i,
		    _s->cStringLength - i, &c);

		if (cLen <= 0 || c > 0x10FFFF) {
			free(buffer);
			@throw [OFInvalidEncodingException exception];
		}

		buffer[j++] = c;
		i += cLen;
	}

	return [[OFData dataWithItemsNoCopy: buffer
				      count: _s->length
				   itemSize: sizeof(of_unichar_t)
				   itemSize: sizeof(OFUnichar)
			       freeWhenDone: true] items];
}

- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder
{
	of_char32_t *buffer = of_alloc(_s->length + 1, sizeof(of_char32_t));
	OFChar32 *buffer = of_alloc(_s->length + 1, sizeof(OFChar32));
	size_t i = 0, j = 0;

	while (i < _s->cStringLength) {
		of_char32_t c;
		OFChar32 c;
		ssize_t cLen;

		cLen = of_string_utf8_decode(_s->cString + i,
		    _s->cStringLength - i, &c);

		if (cLen <= 0 || c > 0x10FFFF) {
			free(buffer);
			@throw [OFInvalidEncodingException exception];
		}

		if (byteOrder != OF_BYTE_ORDER_NATIVE)
		if (byteOrder != OFByteOrderNative)
			buffer[j++] = OF_BSWAP32(c);
		else
			buffer[j++] = c;

		i += cLen;
	}
	buffer[j] = 0;

	return [[OFData dataWithItemsNoCopy: buffer
				      count: _s->length + 1
				   itemSize: sizeof(of_char32_t)
				   itemSize: sizeof(OFChar32)
			       freeWhenDone: true] items];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block
{
	void *pool;
	const char *cString = _s->cString;
	const char *last = cString;
	bool stop = false, lastCarriageReturn = false;

	while (!stop && *cString != 0) {

Modified src/OFValue.h from [938b5927a6] to [df3acd707a].

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







-
+

-
+

-
+


-
+

-
+

-
+


-
+

-
+

-
+


-
+

-
+

-
+







 * @brief The value as a non-retained object.
 *
 * If the value is not pointer-sized, @ref OFOutOfRangeException is thrown.
 */
@property (readonly, nonatomic) id nonretainedObjectValue;

/**
 * @brief The value as a range.
 * @brief The value as an OFRange.
 *
 * If the value is not range-sized, @ref OFOutOfRangeException is thrown.
 * If the value is not OFRange-sized, @ref OFOutOfRangeException is thrown.
 */
@property (readonly, nonatomic) of_range_t rangeValue;
@property (readonly, nonatomic) OFRange rangeValue;

/**
 * @brief The value as a point.
 * @brief The value as an OFPoint.
 *
 * If the value is not point-sized, @ref OFOutOfRangeException is thrown.
 * If the value is not OFPoint-sized, @ref OFOutOfRangeException is thrown.
 */
@property (readonly, nonatomic) of_point_t pointValue;
@property (readonly, nonatomic) OFPoint pointValue;

/**
 * @brief The value as a dimension.
 * @brief The value as an OFSize.
 *
 * If the value is not dimension-sized, @ref OFOutOfRangeException is thrown.
 * If the value is not OFSize-sized, @ref OFOutOfRangeException is thrown.
 */
@property (readonly, nonatomic) of_dimension_t dimensionValue;
@property (readonly, nonatomic) OFSize sizeValue;

/**
 * @brief The value as a rectangle.
 * @brief The value as a OFRect.
 *
 * If the value is not rectangle-sized, @ref OFOutOfRangeException is thrown.
 * If the value is not OFRect-sized, @ref OFOutOfRangeException is thrown.
 */
@property (readonly, nonatomic) of_rectangle_t rectangleValue;
@property (readonly, nonatomic) OFRect rectValue;

/**
 * @brief Creates a new, autorelease OFValue with the specified bytes of the
 *	  specified type.
 *
 * @param bytes The bytes containing the value
 * @param objCType The ObjC type encoding for the value
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
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







-
+







-
+


-
+
-

-
+


-
+





-
+


-
+








/**
 * @brief Creates a new, autoreleased OFValue containing the specified range.
 *
 * @param range The range the OFValue should contain
 * @return A new, autoreleased OFValue
 */
+ (instancetype)valueWithRange: (of_range_t)range;
+ (instancetype)valueWithRange: (OFRange)range;

/**
 * @brief Creates a new, autoreleased OFValue containing the specified point.
 *
 * @param point The point the OFValue should contain
 * @return A new, autoreleased OFValue
 */
+ (instancetype)valueWithPoint: (of_point_t)point;
+ (instancetype)valueWithPoint: (OFPoint)point;

/**
 * @brief Creates a new, autoreleased OFValue containing the specified
 * @brief Creates a new, autoreleased OFValue containing the specified size.
 *	  dimension.
 *
 * @param dimension The dimension the OFValue should contain
 * @param size The size the OFValue should contain
 * @return A new, autoreleased OFValue
 */
+ (instancetype)valueWithDimension: (of_dimension_t)dimension;
+ (instancetype)valueWithSize: (OFSize)size;

/**
 * @brief Creates a new, autoreleased OFValue containing the specified
 *	  rectangle.
 *
 * @param rectangle The rectangle the OFValue should contain
 * @param rect The rectangle the OFValue should contain
 * @return A new, autoreleased OFValue
 */
+ (instancetype)valueWithRectangle: (of_rectangle_t)rectangle;
+ (instancetype)valueWithRect: (OFRect)rect;

/**
 * @brief Initializes an already allocated OFValue with the specified bytes of
 *	  the specified type.
 *
 * @param bytes The bytes containing the value
 * @param objCType The ObjC type encoding for the value

Modified src/OFValue.m from [57c5a42ed5] to [712005bdcf].

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


25
26
27
28
29
30
31
11
12
13
14
15
16
17

18
19
20
21
22

23
24
25
26
27
28
29
30
31







-





-
+
+







 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFValue.h"
#import "OFBytesValue.h"
#import "OFDimensionValue.h"
#import "OFMethodSignature.h"
#import "OFNonretainedObjectValue.h"
#import "OFPointValue.h"
#import "OFPointerValue.h"
#import "OFRangeValue.h"
#import "OFRectangleValue.h"
#import "OFRectValue.h"
#import "OFSizeValue.h"
#import "OFString.h"

#import "OFOutOfMemoryException.h"

@implementation OFValue
+ (instancetype)alloc
{
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
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







-
+




-
+




-
+

-
+
-


-
+

-
+
-








+ (instancetype)valueWithNonretainedObject: (id)object
{
	return [[[OFNonretainedObjectValue alloc]
	    initWithNonretainedObject: object] autorelease];
}

+ (instancetype)valueWithRange: (of_range_t)range
+ (instancetype)valueWithRange: (OFRange)range
{
	return [[[OFRangeValue alloc] initWithRange: range] autorelease];
}

+ (instancetype)valueWithPoint: (of_point_t)point
+ (instancetype)valueWithPoint: (OFPoint)point
{
	return [[[OFPointValue alloc] initWithPoint: point] autorelease];
}

+ (instancetype)valueWithDimension: (of_dimension_t)dimension
+ (instancetype)valueWithSize: (OFSize)size
{
	return [[[OFDimensionValue alloc]
	return [[[OFSizeValue alloc] initWithSize: size] autorelease];
	    initWithDimension: dimension] autorelease];
}

+ (instancetype)valueWithRectangle: (of_rectangle_t)rectangle
+ (instancetype)valueWithRect: (OFRect)rect
{
	return [[[OFRectangleValue alloc]
	return [[[OFRectValue alloc] initWithRect: rect] autorelease];
	    initWithRectangle: rectangle] autorelease];
}

- (instancetype)initWithBytes: (const void *)bytes
		     objCType: (const char *)objCType
{
	OF_INVALID_INIT_METHOD
}
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
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







-
+

+
+
+
+
+
+
+
-
+




-
+

-
+




-
-
-
-
-
-
-
+
-

-
+







- (id)nonretainedObjectValue
{
	id ret;
	[self getValue: &ret size: sizeof(ret)];
	return ret;
}

- (of_range_t)rangeValue
- (OFRange)rangeValue
{
	OFRange ret;
	[self getValue: &ret size: sizeof(ret)];
	return ret;
}

- (OFPoint)pointValue
{
	of_range_t ret;
	OFPoint ret;
	[self getValue: &ret size: sizeof(ret)];
	return ret;
}

- (of_point_t)pointValue
- (OFSize)sizeValue
{
	of_point_t ret;
	OFSize ret;
	[self getValue: &ret size: sizeof(ret)];
	return ret;
}

- (of_dimension_t)dimensionValue
{
	of_dimension_t ret;
	[self getValue: &ret size: sizeof(ret)];
	return ret;
}

- (OFRect)rectValue
- (of_rectangle_t)rectangleValue
{
	of_rectangle_t ret;
	OFRect ret;
	[self getValue: &ret size: sizeof(ret)];
	return ret;
}

- (OFString *)description
{
	OFMutableString *ret =

Modified src/OFWin32ConsoleStdIOStream.h from [2abff1d7d9] to [c105a8c0f2].

19
20
21
22
23
24
25
26

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

26
27
28
29
30
31
32







-
+







OF_ASSUME_NONNULL_BEGIN

@interface OFWin32ConsoleStdIOStream: OFStdIOStream
{
	HANDLE _handle;
	WORD _attributes;
	of_char16_t _incompleteUTF16Surrogate;
	OFChar16 _incompleteUTF16Surrogate;
	char _incompleteUTF8Surrogate[4];
	size_t _incompleteUTF8SurrogateLen;
}
@end

OF_ASSUME_NONNULL_END

Modified src/OFWin32ConsoleStdIOStream.m from [0662c30238] to [52d54dbd3b].

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







-
+




-
+

-
+

-
+

-
+

-
+







#import "OFInvalidEncodingException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#include <windows.h>

static of_string_encoding_t
static OFStringEncoding
codepageToEncoding(UINT codepage)
{
	switch (codepage) {
	case 437:
		return OF_STRING_ENCODING_CODEPAGE_437;
		return OFStringEncodingCodepage437;
	case 850:
		return OF_STRING_ENCODING_CODEPAGE_850;
		return OFStringEncodingCodepage850;
	case 858:
		return OF_STRING_ENCODING_CODEPAGE_858;
		return OFStringEncodingCodepage858;
	case 1251:
		return OF_STRING_ENCODING_WINDOWS_1251;
		return OFStringEncodingWindows1251;
	case 1252:
		return OF_STRING_ENCODING_WINDOWS_1252;
		return OFStringEncodingWindows1252;
	default:
		@throw [OFInvalidEncodingException exception];
	}
}

@implementation OFWin32ConsoleStdIOStream
+ (void)load
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
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







-
+





-
+













-
+







	return self;
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer_ length: (size_t)length
{
	void *pool = objc_autoreleasePoolPush();
	char *buffer = buffer_;
	of_char16_t *UTF16;
	OFChar16 *UTF16;
	size_t j = 0;

	if (length > UINT32_MAX)
		@throw [OFOutOfRangeException exception];

	UTF16 = of_alloc(length, sizeof(of_char16_t));
	UTF16 = of_alloc(length, sizeof(OFChar16));
	@try {
		DWORD UTF16Len;
		OFMutableData *rest = nil;
		size_t i = 0;

		if ([OFSystemInfo isWindowsNT]) {
			if (!ReadConsoleW(_handle, UTF16, (DWORD)length,
			    &UTF16Len, NULL))
				@throw [OFReadFailedException
				    exceptionWithObject: self
					requestedLength: length * 2
						  errNo: EIO];
		} else {
			of_string_encoding_t encoding;
			OFStringEncoding encoding;
			OFString *string;
			size_t stringLen;

			if (!ReadConsoleA(_handle, (char *)UTF16, (DWORD)length,
			    &UTF16Len, NULL))
				@throw [OFReadFailedException
				    exceptionWithObject: self
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







-
+







				@throw [OFOutOfRangeException exception];

			UTF16Len = (DWORD)stringLen;
			memcpy(UTF16, string.UTF16String, stringLen);
		}

		if (UTF16Len > 0 && _incompleteUTF16Surrogate != 0) {
			of_unichar_t c =
			OFUnichar c =
			    (((_incompleteUTF16Surrogate & 0x3FF) << 10) |
			    (UTF16[0] & 0x3FF)) + 0x10000;
			char UTF8[4];
			size_t UTF8Len;

			if ((UTF8Len = of_string_utf8_encode(c, UTF8)) == 0)
				@throw [OFInvalidEncodingException exception];
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208

209
210
211
212
213
214
215
216







-
+








-
+







			}

			_incompleteUTF16Surrogate = 0;
			i++;
		}

		for (; i < UTF16Len; i++) {
			of_unichar_t c = UTF16[i];
			OFUnichar c = UTF16[i];
			char UTF8[4];
			size_t UTF8Len;

			/* Missing high surrogate */
			if ((c & 0xFC00) == 0xDC00)
				@throw [OFInvalidEncodingException exception];

			if ((c & 0xFC00) == 0xD800) {
				of_char16_t next;
				OFChar16 next;

				if (UTF16Len <= i + 1) {
					_incompleteUTF16Surrogate = c;

					if (rest != nil) {
						const char *items = rest.items;
						size_t count = rest.count;
260
261
262
263
264
265
266
267

268
269
270
271
272
273
274
275


276
277
278
279
280
281
282
260
261
262
263
264
265
266

267
268
269
270
271
272
273


274
275
276
277
278
279
280
281
282







-
+






-
-
+
+








	return j;
}

- (size_t)lowlevelWriteBuffer: (const void *)buffer_ length: (size_t)length
{
	const char *buffer = buffer_;
	of_char16_t *tmp;
	OFChar16 *tmp;
	size_t i = 0, j = 0;

	if (length > SIZE_MAX / 2)
		@throw [OFOutOfRangeException exception];

	if (_incompleteUTF8SurrogateLen > 0) {
		of_unichar_t c;
		of_char16_t UTF16[2];
		OFUnichar c;
		OFChar16 UTF16[2];
		ssize_t UTF8Len;
		size_t toCopy;
		DWORD UTF16Len, bytesWritten;

		UTF8Len = -of_string_utf8_decode(
		    _incompleteUTF8Surrogate, _incompleteUTF8SurrogateLen, &c);

322
323
324
325
326
327
328
329

330
331
332
333
334
335
336
322
323
324
325
326
327
328

329
330
331
332
333
334
335
336







-
+







					   bytesWritten: bytesWritten * 2
						  errNo: EIO];
		} else {
			void *pool = objc_autoreleasePoolPush();
			OFString *string = [OFString
			    stringWithUTF16String: UTF16
					   length: UTF16Len];
			of_string_encoding_t encoding =
			OFStringEncoding encoding =
			    codepageToEncoding(GetConsoleOutputCP());
			size_t nativeLen = [string
			    cStringLengthWithEncoding: encoding];

			if (nativeLen > UINT32_MAX)
				@throw [OFOutOfRangeException exception];

353
354
355
356
357
358
359
360

361
362
363
364
365

366
367
368
369
370
371
372
353
354
355
356
357
358
359

360
361
362
363
364

365
366
367
368
369
370
371
372







-
+




-
+







				   bytesWritten: bytesWritten * 2
					  errNo: 0];

		_incompleteUTF8SurrogateLen = 0;
		i += toCopy;
	}

	tmp = of_alloc(length * 2, sizeof(of_char16_t));
	tmp = of_alloc(length * 2, sizeof(OFChar16));
	@try {
		DWORD bytesWritten;

		while (i < length) {
			of_unichar_t c;
			OFUnichar c;
			ssize_t UTF8Len;

			UTF8Len = of_string_utf8_decode(buffer + i, length - i,
			    &c);

			if (UTF8Len < 0 && UTF8Len >= -4) {
				OF_ENSURE(length - i < 4);
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







-
+







					requestedLength: j * 2
					   bytesWritten: bytesWritten * 2
						  errNo: EIO];
		} else {
			void *pool = objc_autoreleasePoolPush();
			OFString *string = [OFString stringWithUTF16String: tmp
								    length: j];
			of_string_encoding_t encoding =
			OFStringEncoding encoding =
			    codepageToEncoding(GetConsoleOutputCP());
			size_t nativeLen = [string
			    cStringLengthWithEncoding: encoding];

			if (nativeLen > UINT32_MAX)
				@throw [OFOutOfRangeException exception];

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







-
+







-
+












		return;

	csbi.dwCursorPosition.X = column;

	SetConsoleCursorPosition(_handle, csbi.dwCursorPosition);
}

- (void)setCursorPosition: (of_point_t)position
- (void)setCursorPosition: (OFPoint)position
{
	if (position.x < 0 || position.y < 0)
		@throw [OFInvalidArgumentException exception];

	SetConsoleCursorPosition(_handle, (COORD){ position.x, position.y });
}

- (void)setRelativeCursorPosition: (of_point_t)position
- (void)setRelativeCursorPosition: (OFPoint)position
{
	CONSOLE_SCREEN_BUFFER_INFO csbi;

	if (!GetConsoleScreenBufferInfo(_handle, &csbi))
		return;

	csbi.dwCursorPosition.X += position.x;
	csbi.dwCursorPosition.Y += position.y;

	SetConsoleCursorPosition(_handle, csbi.dwCursorPosition);
}
@end

Modified src/OFWindowsRegistryKey.m from [8c15fe2a75] to [c8ce2ece61].

283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
283
284
285
286
287
288
289

290
291
292
293
294
295
296
297







-
+







	if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_LINK)
		@throw [OFInvalidEncodingException exception];

	if (data.itemSize != 1)
		@throw [OFInvalidFormatException exception];

	if ([OFSystemInfo isWindowsNT]) {
		const of_char16_t *UTF16String = data.items;
		const OFChar16 *UTF16String = data.items;
		size_t length = data.count;

		if (length % 2 == 1)
			@throw [OFInvalidFormatException exception];

		length /= 2;

347
348
349
350
351
352
353
354

355
356

357
358
359
360
361
362
363
347
348
349
350
351
352
353

354
355

356
357
358
359
360
361
362
363







-
+

-
+







{
	void *pool = objc_autoreleasePoolPush();
	OFData *data;

	if ([OFSystemInfo isWindowsNT])
		data = [OFData dataWithItems: string.UTF16String
				       count: string.UTF16StringLength + 1
				    itemSize: sizeof(of_char16_t)];
				    itemSize: sizeof(OFChar16)];
	else {
		of_string_encoding_t encoding = [OFLocale encoding];
		OFStringEncoding encoding = [OFLocale encoding];
		const char *cString = [string cStringWithEncoding: encoding];
		size_t length = [string cStringLengthWithEncoding: encoding];

		data = [OFData dataWithItems: cString count: length + 1];
	}

	[self setData: data forValueNamed: name type: type];

Modified src/OFXMLElement+Serialization.m from [e82061841d] to [805366e391].

28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
28
29
30
31
32
33
34

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







-
+












- (id)objectByDeserializing
{
	void *pool = objc_autoreleasePoolPush();
	Class class;
	id object;

	if ((class = objc_getClass([_name cStringWithEncoding:
	    OF_STRING_ENCODING_ASCII])) == Nil)
	    OFStringEncodingASCII])) == Nil)
		@throw [OFInvalidArgumentException exception];

	if (![class conformsToProtocol: @protocol(OFSerialization)])
		@throw [OFInvalidArgumentException exception];

	object = [[class alloc] initWithSerialization: self];

	objc_autoreleasePoolPop(pool);

	return [object autorelease];
}
@end

Modified src/OFXMLParser.h from [2b3552397a] to [88a3556818].

163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177







-
+







	OFString *_Nullable _attributeName, *_Nullable _attributePrefix;
	char _delimiter;
	OFMutableArray OF_GENERIC(OFString *) *_previous;
	size_t _level;
	bool _acceptProlog;
	size_t _lineNumber;
	bool _lastCarriageReturn, _finishedParsing;
	of_string_encoding_t _encoding;
	OFStringEncoding _encoding;
	size_t _depthLimit;
}

/**
 * @brief The delegate that is used by the XML parser.
 */
@property OF_NULLABLE_PROPERTY (assign, nonatomic)

Modified src/OFXMLParser.m from [02a95773a3] to [0ad1be565e].

87
88
89
90
91
92
93
94

95
96

97
98
99
100
101
102
103
87
88
89
90
91
92
93

94
95

96
97
98
99
100
101
102
103







-
+

-
+







	[OF_XMLPARSER_IN_COMMENT_1] = inCommentState1,
	[OF_XMLPARSER_IN_COMMENT_2] = inCommentState2,
	[OF_XMLPARSER_IN_DOCTYPE] = inDOCTYPEState
};

static OF_INLINE void
appendToBuffer(OFMutableData *buffer, const char *string,
    of_string_encoding_t encoding, size_t length)
    OFStringEncoding encoding, size_t length)
{
	if OF_LIKELY(encoding == OF_STRING_ENCODING_UTF_8)
	if OF_LIKELY(encoding == OFStringEncodingUTF8)
		[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];
207
208
209
210
211
212
213
214

215
216
217
218
219
220
221
207
208
209
210
211
212
213

214
215
216
217
218
219
220
221







-
+







		dict = [OFMutableDictionary dictionaryWithKeysAndObjects:
		    @"xml", @"http://www.w3.org/XML/1998/namespace",
		    @"xmlns", @"http://www.w3.org/2000/xmlns/", nil];
		[_namespaces addObject: dict];

		_acceptProlog = true;
		_lineNumber = 1;
		_encoding = OF_STRING_ENCODING_UTF_8;
		_encoding = OFStringEncodingUTF8;
		_depthLimit = 32;

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}
446
447
448
449
450
451
452
453

454
455
456
457
458
459
460
446
447
448
449
450
451
452

453
454
455
456
457
458
459
460







-
+








				hasVersion = true;
			}

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

			last = i + 1;
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
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







-
+









-
+







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

		whitespaceCS = [OFCharacterSet
		    characterSetWithCharactersInString: @" \r\n\r"];
		pos = [PI indexOfCharacterFromSet: whitespaceCS];
		if (pos != OF_NOT_FOUND) {
		if (pos != OFNotFound) {
			target = [PI substringToIndex: pos];
			data = [[PI substringFromIndex: pos + 1]
			    stringByDeletingEnclosingWhitespaces];

			if (data.length == 0)
				data = nil;
		} else
			target = PI;

		if ([target caseInsensitiveCompare: @"xml"] == OF_ORDERED_SAME)
		if ([target caseInsensitiveCompare: @"xml"] == OFOrderedSame)
			if (!parseXMLProcessingInstruction(self, data))
				@throw [OFMalformedXMLException
				    exceptionWithParser: self];

		if ([self->_delegate respondsToSelector: @selector(
		    parser:foundProcessingInstructionWithTarget:data:)])
			[self->_delegate parser: self

Modified src/OFZIPArchive.m from [4c67ad00cf] to [57930654e1].

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







-
+







	_centralDirectoryEntries = [_stream readLittleEndianInt16];
	_centralDirectorySize = [_stream readLittleEndianInt32];
	_centralDirectoryOffset = [_stream readLittleEndianInt32];

	commentLength = [_stream readLittleEndianInt16];
	_archiveComment = [[_stream
	    readStringWithLength: commentLength
			encoding: OF_STRING_ENCODING_CODEPAGE_437] copy];
			encoding: OFStringEncodingCodepage437] copy];

	if (_diskNumber == 0xFFFF ||
	    _centralDirectoryDisk == 0xFFFF ||
	    _centralDirectoryEntriesInDisk == 0xFFFF ||
	    _centralDirectoryEntries == 0xFFFF ||
	    _centralDirectorySize == 0xFFFFFFFF ||
	    _centralDirectoryOffset == 0xFFFFFFFF) {
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
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







-
+

















-
+
-










-
+


-
-
+
+







{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMutableData *extraField = nil;
		uint16_t fileNameLength, extraFieldLength;
		of_string_encoding_t encoding;
		OFStringEncoding encoding;
		size_t ZIP64Index;
		uint16_t ZIP64Size;

		if ([stream readLittleEndianInt32] != 0x04034B50)
			@throw [OFInvalidFormatException exception];

		_minVersionNeeded = [stream readLittleEndianInt16];
		_generalPurposeBitFlag = [stream readLittleEndianInt16];
		_compressionMethod = [stream readLittleEndianInt16];
		_lastModifiedFileTime = [stream readLittleEndianInt16];
		_lastModifiedFileDate = [stream readLittleEndianInt16];
		_CRC32 = [stream readLittleEndianInt32];
		_compressedSize = [stream readLittleEndianInt32];
		_uncompressedSize = [stream readLittleEndianInt32];
		fileNameLength = [stream readLittleEndianInt16];
		extraFieldLength = [stream readLittleEndianInt16];
		encoding = (_generalPurposeBitFlag & (1u << 11)
		    ? OF_STRING_ENCODING_UTF_8
		    ? OFStringEncodingUTF8 : OFStringEncodingCodepage437);
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[stream readStringWithLength: fileNameLength
						 encoding: encoding] copy];
		if (extraFieldLength > 0)
			extraField = [[[stream readDataWithCount:
			    extraFieldLength] mutableCopy] autorelease];

		ZIP64Index = of_zip_archive_entry_extra_field_find(extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size);

		if (ZIP64Index != OF_NOT_FOUND) {
		if (ZIP64Index != OFNotFound) {
			const uint8_t *ZIP64 =
			    [extraField itemAtIndex: ZIP64Index];
			of_range_t range =
			    of_range(ZIP64Index - 4, ZIP64Size + 4);
			OFRange range =
			    OFMakeRange(ZIP64Index - 4, ZIP64Size + 4);

			if (_uncompressedSize == 0xFFFFFFFF)
				_uncompressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);
			if (_compressedSize == 0xFFFFFFFF)
				_compressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);

Modified src/OFZIPArchiveEntry.h from [2df45ec20c] to [3bbdaa40a9].

246
247
248
249
250
251
252
253

254
255
256
257
258
259
260
261
262
263
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260
261
262
263







-
+










 *	  specified tag.
 *
 * @param extraField The extra field to search for an extensible data field with
 *		     the specified tag
 * @param tag The tag to look for
 * @param size A pointer to an uint16_t that should be set to the size
 * @return The index at which the extra field content starts in the OFData, or
 *	   OF_NOT_FOUND
 *	   `OFNotFound`
 */
extern size_t of_zip_archive_entry_extra_field_find(OFData *extraField,
    uint16_t tag, uint16_t *size);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

#import "OFMutableZIPArchiveEntry.h"

Modified src/OFZIPArchiveEntry.m from [1b0f865f32] to [7b9fab9725].

166
167
168
169
170
171
172
173

174
175
176
177
178
179
180
166
167
168
169
170
171
172

173
174
175
176
177
178
179
180







-
+







			return i + 4;
		}

		i += 4 + currentSize;
	}

	*size = 0;
	return OF_NOT_FOUND;
	return OFNotFound;
}

@implementation OFZIPArchiveEntry
+ (instancetype)entryWithFileName: (OFString *)fileName
{
	return [[[self alloc] initWithFileName: fileName] autorelease];
}
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
209
210
211
212
213
214
215

216
217
218
219
220
221
222
223







-
+







{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMutableData *extraField = nil;
		uint16_t fileNameLength, extraFieldLength, fileCommentLength;
		of_string_encoding_t encoding;
		OFStringEncoding encoding;
		size_t ZIP64Index;
		uint16_t ZIP64Size;

		if ([stream readLittleEndianInt32] != 0x02014B50)
			@throw [OFInvalidFormatException exception];

		_versionMadeBy = [stream readLittleEndianInt16];
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
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







-
+
-














-
+


-
-
+
+







		fileCommentLength = [stream readLittleEndianInt16];
		_startDiskNumber = [stream readLittleEndianInt16];
		_internalAttributes = [stream readLittleEndianInt16];
		_versionSpecificAttributes = [stream readLittleEndianInt32];
		_localFileHeaderOffset = [stream readLittleEndianInt32];

		encoding = (_generalPurposeBitFlag & (1u << 11)
		    ? OF_STRING_ENCODING_UTF_8
		    ? OFStringEncodingUTF8 : OFStringEncodingCodepage437);
		    : OF_STRING_ENCODING_CODEPAGE_437);

		_fileName = [[stream readStringWithLength: fileNameLength
						 encoding: encoding] copy];
		if (extraFieldLength > 0)
			extraField = [[[stream readDataWithCount:
			    extraFieldLength] mutableCopy] autorelease];
		if (fileCommentLength > 0)
			_fileComment = [[stream
			    readStringWithLength: fileCommentLength
					encoding: encoding] copy];

		ZIP64Index = of_zip_archive_entry_extra_field_find(extraField,
		    OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size);

		if (ZIP64Index != OF_NOT_FOUND) {
		if (ZIP64Index != OFNotFound) {
			const uint8_t *ZIP64 =
			    [extraField itemAtIndex: ZIP64Index];
			of_range_t range =
			    of_range(ZIP64Index - 4, ZIP64Size + 4);
			OFRange range =
			    OFMakeRange(ZIP64Index - 4, ZIP64Size + 4);

			if (_uncompressedSize == 0xFFFFFFFF)
				_uncompressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);
			if (_compressedSize == 0xFFFFFFFF)
				_compressedSize = of_zip_archive_read_field64(
				    &ZIP64, &ZIP64Size);

Modified src/base64.m from [895a169025] to [06a2cd6d95].

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







-
+










-
+












-
+








		tb[0] = of_base64_encode_table[(sb & 0xFC0000) >> 18];
		tb[1] = of_base64_encode_table[(sb & 0x03F000) >> 12];
		tb[2] = of_base64_encode_table[(sb & 0x000FC0) >> 6];
		tb[3] = of_base64_encode_table[sb & 0x00003F];

		[ret appendCString: tb
			  encoding: OF_STRING_ENCODING_ASCII
			  encoding: OFStringEncodingASCII
			    length: 4];
	}

	switch (rest) {
	case 1:
		tb[0] = of_base64_encode_table[buffer[i] >> 2];
		tb[1] = of_base64_encode_table[(buffer[i] & 3) << 4];
		tb[2] = tb[3] = '=';

		[ret appendCString: tb
			  encoding: OF_STRING_ENCODING_ASCII
			  encoding: OFStringEncodingASCII
			    length: 4];

		break;
	case 2:
		sb = (buffer[i] << 16) | (buffer[i + 1] << 8);

		tb[0] = of_base64_encode_table[(sb & 0xFC0000) >> 18];
		tb[1] = of_base64_encode_table[(sb & 0x03F000) >> 12];
		tb[2] = of_base64_encode_table[(sb & 0x000FC0) >> 6];
		tb[3] = '=';

		[ret appendCString: tb
			  encoding: OF_STRING_ENCODING_ASCII
			  encoding: OFStringEncodingASCII
			    length: 4];

		break;
	}

	[ret makeImmutable];

Modified src/condition.h from [61428a9c46] to [0d9f4192a1].

18
19
20
21
22
23
24
25

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

25
26
27
28
29
30
31
32







-
+







#include "platform.h"

#if !defined(OF_HAVE_THREADS) || \
    (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS))
# error No conditions available!
#endif

/* For of_time_interval_t */
/* For OFTimeInterval */
#import "OFObject.h"

#import "mutex.h"

#if defined(OF_HAVE_PTHREADS)
# include <pthread.h>
typedef pthread_cond_t of_condition_t;
51
52
53
54
55
56
57
58

59
60
61
62
63

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

58
59
60
61
62

63
64
65
66
67
68







-
+




-
+





extern "C" {
#endif
extern int of_condition_new(of_condition_t *condition);
extern int of_condition_signal(of_condition_t *condition);
extern int of_condition_broadcast(of_condition_t *condition);
extern int of_condition_wait(of_condition_t *condition, of_mutex_t *mutex);
extern int of_condition_timed_wait(of_condition_t *condition,
    of_mutex_t *mutex, of_time_interval_t timeout);
    of_mutex_t *mutex, OFTimeInterval timeout);
#ifdef OF_AMIGAOS
extern int of_condition_wait_or_signal(of_condition_t *condition,
    of_mutex_t *mutex, ULONG *signalMask);
extern int of_condition_timed_wait_or_signal(of_condition_t *condition,
    of_mutex_t *mutex, of_time_interval_t timeout, ULONG *signalMask);
    of_mutex_t *mutex, OFTimeInterval timeout, ULONG *signalMask);
#endif
extern int of_condition_free(of_condition_t *condition);
#ifdef __cplusplus
}
#endif

Modified src/encodings/codepage-437.m from [e06381bb1c] to [e4e7c7d238].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_codepage_437_table[] = {
const OFChar16 of_codepage_437_table[] = {
	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
	0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
	0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
125
126
127
128
129
130
131
132

133
134
135
136

137
138
139
140
141
142
143
125
126
127
128
129
130
131

132
133
134
135

136
137
138
139
140
141
142
143







-
+



-
+







	0xDE, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xFE
};
static const uint8_t page25Start = 0x00;

bool
of_unicode_to_codepage_437(const of_unichar_t *input, unsigned char *output,
of_unicode_to_codepage_437(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/codepage-850.m from [3c49f43469] to [749e880312].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_codepage_850_table[] = {
const OFChar16 of_codepage_850_table[] = {
	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
	0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
	0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
101
102
103
104
105
106
107
108

109
110
111
112

113
114
115
116
117
118
119
101
102
103
104
105
106
107

108
109
110
111

112
113
114
115
116
117
118
119







-
+



-
+







	0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xFE
};
static const uint8_t page25Start = 0x00;

bool
of_unicode_to_codepage_850(const of_unichar_t *input, unsigned char *output,
of_unicode_to_codepage_850(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/codepage-858.m from [3ce6d4c463] to [713f34e1a5].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_codepage_858_table[] = {
const OFChar16 of_codepage_858_table[] = {
	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
	0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
	0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
107
108
109
110
111
112
113
114

115
116
117
118

119
120
121
122
123
124
125
107
108
109
110
111
112
113

114
115
116
117

118
119
120
121
122
123
124
125







-
+



-
+







	0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xFE
};
static const uint8_t page25Start = 0x00;

bool
of_unicode_to_codepage_858(const of_unichar_t *input, unsigned char *output,
of_unicode_to_codepage_858(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/iso-8859-15.m from [66f31de0ef] to [4e7f7697f6].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_iso_8859_15_table[] = {
const OFChar16 of_iso_8859_15_table[] = {
	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7,
	0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7,
	0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF,
	0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
	0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
	0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
56
57
58
59
60
61
62
63

64
65
66
67

68
69
70
71
72
73
74
56
57
58
59
60
61
62

63
64
65
66

67
68
69
70
71
72
73
74







-
+



-
+








static const unsigned char page20[] = {
	0xA4
};
static const uint8_t page20Start = 0xAC;

bool
of_unicode_to_iso_8859_15(const of_unichar_t *input, unsigned char *output,
of_unicode_to_iso_8859_15(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/iso-8859-2.m from [3fe77cae41] to [9e8609b7f9].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_iso_8859_2_table[] = {
const OFChar16 of_iso_8859_2_table[] = {
	0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
	0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
	0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
	0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
	0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
	0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
	0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
76
77
78
79
80
81
82
83

84
85
86
87

88
89
90
91
92
93
94
76
77
78
79
80
81
82

83
84
85
86

87
88
89
90
91
92
93
94







-
+



-
+







	0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0xA2, 0xFF, 0x00, 0xB2, 0x00, 0xBD
};
static const uint8_t page2Start = 0xC7;

bool
of_unicode_to_iso_8859_2(const of_unichar_t *input, unsigned char *output,
of_unicode_to_iso_8859_2(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/iso-8859-3.m from [b571fab6a6] to [0df871c6b9].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_iso_8859_3_table[] = {
const OFChar16 of_iso_8859_3_table[] = {
	0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFF, 0x0124, 0x00A7,
	0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFF, 0x017B,
	0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7,
	0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFF, 0x017C,
	0x00C0, 0x00C1, 0x00C2, 0xFFFF, 0x00C4, 0x010A, 0x0108, 0x00C7,
	0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
	0xFFFF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7,
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







-
+



-
+








static const unsigned char page2[] = {
	0xA2, 0xFF
};
static const uint8_t page2Start = 0xD8;

bool
of_unicode_to_iso_8859_3(const of_unichar_t *input, unsigned char *output,
of_unicode_to_iso_8859_3(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/koi8-r.m from [b612dc985f] to [e0fb41e40c].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_koi8_r_table[] = {
const OFChar16 of_koi8_r_table[] = {
	0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
	0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
	0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
	0x2264,	0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
	0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556,
	0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E,
	0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565,
111
112
113
114
115
116
117
118

119
120
121
122

123
124
125
126
127
128
129
111
112
113
114
115
116
117

118
119
120
121

122
123
124
125
126
127
128
129







-
+



-
+







	0x8F, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x94
};
static const uint8_t page25Start = 0x00;

bool
of_unicode_to_koi8_r(const of_unichar_t *input, unsigned char *output,
of_unicode_to_koi8_r(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/koi8-u.m from [bc833d67fc] to [6a1434b3fd].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_koi8_u_table[] = {
const OFChar16 of_koi8_u_table[] = {
	0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
	0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
	0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
	0x2264,	0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
	0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457,
	0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E,
	0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407,
119
120
121
122
123
124
125
126

127
128
129
130

131
132
133
134
135
136
137
119
120
121
122
123
124
125

126
127
128
129

130
131
132
133
134
135
136
137







-
+



-
+







	0x8F, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x94
};
static const uint8_t page25Start = 0x00;

bool
of_unicode_to_koi8_u(const of_unichar_t *input, unsigned char *output,
of_unicode_to_koi8_u(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/mac-roman.m from [db14d68482] to [c331a2e488].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_mac_roman_table[] = {
const OFChar16 of_mac_roman_table[] = {
	0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
	0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
	0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
	0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
	0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
	0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
	0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
145
146
147
148
149
150
151
152

153
154
155
156

157
158
159
160
161
162
163
145
146
147
148
149
150
151

152
153
154
155

156
157
158
159
160
161
162
163







-
+



-
+








static const unsigned char pageFB[] = {
	0xDE, 0xDF
};
static const uint8_t pageFBStart = 0x01;

bool
of_unicode_to_mac_roman(const of_unichar_t *input, unsigned char *output,
of_unicode_to_mac_roman(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/windows-1251.m from [baa2d5d34b] to [23d0ff0ab8].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_windows_1251_table[] = {
const OFChar16 of_windows_1251_table[] = {
	0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
	0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
	0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
	0xFFFF, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
	0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
	0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
	0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
98
99
100
101
102
103
104
105

106
107
108
109

110
111
112
113
114
115
116
98
99
100
101
102
103
104

105
106
107
108

109
110
111
112
113
114
115
116







-
+



-
+







static const unsigned char page21[] = {
	0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x99
};
static const uint8_t page21Start = 0x16;

bool
of_unicode_to_windows_1251(const of_unichar_t *input, unsigned char *output,
of_unicode_to_windows_1251(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/encodings/windows-1252.m from [d5fc246852] to [0483911e0f].

15
16
17
18
19
20
21
22

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

22
23
24
25
26
27
28
29







-
+








#include "config.h"

#import "OFString.h"

#import "common.h"

const of_char16_t of_windows_1252_table[] = {
const OFChar16 of_windows_1252_table[] = {
	0x20AC, 0xFFFF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
	0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFF, 0x017D, 0xFFFF,
	0xFFFF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
	0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFF, 0x017E, 0x0178,
	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
	0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
94
95
96
97
98
99
100
101

102
103
104
105

106
107
108
109
110
111
112
94
95
96
97
98
99
100

101
102
103
104

105
106
107
108
109
110
111
112







-
+



-
+








static const unsigned char page21[] = {
	0x99
};
static const uint8_t page21Start = 0x22;

bool
of_unicode_to_windows_1252(const of_unichar_t *input, unsigned char *output,
of_unicode_to_windows_1252(const OFUnichar *input, unsigned char *output,
    size_t length, bool lossy)
{
	for (size_t i = 0; i < length; i++) {
		of_unichar_t c = input[i];
		OFUnichar c = input[i];

		if OF_UNLIKELY (c > 0x7F) {
			uint8_t idx;

			if OF_UNLIKELY (c > 0xFFFF) {
				if (lossy) {
					output[i] = '?';

Modified src/exceptions/OFResolveHostFailedException.h from [48c5873ef6] to [25768e6bdb].

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







-
+











-
+
















-
+












-
+




 *	  OFResolveHostFailedException.h ObjFW/OFResolveHostFailedException.h
 *
 * @brief An exception indicating that resolving a host failed.
 */
@interface OFResolveHostFailedException: OFException
{
	OFString *_host;
	of_socket_address_family_t _addressFamily;
	OFSocketAddressFamily _addressFamily;
	of_dns_resolver_error_t _error;
}

/**
 * @brief The host which could not be resolved.
 */
@property (readonly, nonatomic) OFString *host;

/**
 * @brief The address family for which the host could not be resolved.
 */
@property (readonly, nonatomic) of_socket_address_family_t addressFamily;
@property (readonly, nonatomic) OFSocketAddressFamily addressFamily;

/**
 * @brief The error from the resolver.
 */
@property (readonly, nonatomic) of_dns_resolver_error_t error;

/**
 * @brief Creates a new, autoreleased resolve host failed exception.
 *
 * @param host The host which could not be resolved
 * @param addressFamily The address family for which the host could not be
 *			resolved
 * @param error The error from the resolver
 * @return A new, autoreleased address translation failed exception
 */
+ (instancetype)exceptionWithHost: (OFString *)host
		    addressFamily: (of_socket_address_family_t)addressFamily
		    addressFamily: (OFSocketAddressFamily)addressFamily
			    error: (of_dns_resolver_error_t)error;

/**
 * @brief Initializes an already allocated resolve host failed exception.
 *
 * @param host The host which could not be resolved
 * @param addressFamily The address family for which the host could not be
 *			resolved
 * @param error The error from the resolver
 * @return An initialized address translation failed exception
 */
- (instancetype)initWithHost: (OFString *)host
	       addressFamily: (of_socket_address_family_t)addressFamily
	       addressFamily: (OFSocketAddressFamily)addressFamily
		       error: (of_dns_resolver_error_t)error;
@end

OF_ASSUME_NONNULL_END

Modified src/exceptions/OFResolveHostFailedException.m from [5ef786dbbc] to [4a19318a81].

19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42







-
+








-
+







#import "OFDNSQueryFailedException.h"
#import "OFString.h"

@implementation OFResolveHostFailedException
@synthesize host = _host, addressFamily = _addressFamily, error = _error;

+ (instancetype)exceptionWithHost: (OFString *)host
		    addressFamily: (of_socket_address_family_t)addressFamily
		    addressFamily: (OFSocketAddressFamily)addressFamily
			    error: (of_dns_resolver_error_t)error
{
	return [[[self alloc] initWithHost: host
			     addressFamily: addressFamily
				     error: error] autorelease];
}

- (instancetype)initWithHost: (OFString *)host
	       addressFamily: (of_socket_address_family_t)addressFamily
	       addressFamily: (OFSocketAddressFamily)addressFamily
		       error: (of_dns_resolver_error_t)error
{
	self = [super init];

	@try {
		_host = [host copy];
		_addressFamily = addressFamily;

Modified src/exceptions/OFSetItemAttributesFailedException.h from [d9ce8daea6] to [82396088b1].

26
27
28
29
30
31
32
33
34


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

52
53
54
55
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


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


90
91
92
93
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


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


88
89
90
91
92
93







-
-
+
+
















-
+




-
+














-
-
+
+















-
-
+
+




 *	  ObjFW/OFSetItemAttributesFailedException.h
 *
 * @brief An exception indicating an item's attributes could not be set.
 */
@interface OFSetItemAttributesFailedException: OFException
{
	OFURL *_URL;
	of_file_attributes_t _attributes;
	of_file_attribute_key_t _failedAttribute;
	OFFileAttributes _attributes;
	OFFileAttributeKey _failedAttribute;
	int _errNo;
}

/**
 * @brief The URL of the item whose attributes could not be set.
 */
@property (readonly, nonatomic) OFURL *URL;

/**
 * @brief The errno of the error that occurred.
 */
@property (readonly, nonatomic) int errNo;

/**
 * @brief The attributes that should have been set.
 */
@property (readonly, nonatomic) of_file_attributes_t attributes;
@property (readonly, nonatomic) OFFileAttributes attributes;

/**
 * @brief The first attribute that could not be set.
 */
@property (readonly, nonatomic) of_file_attribute_key_t failedAttribute;
@property (readonly, nonatomic) OFFileAttributeKey failedAttribute;

+ (instancetype)exception OF_UNAVAILABLE;

/**
 * @brief Creates a new, autoreleased set item attributes failed exception.
 *
 * @param URL The URL of the item whose attributes could not be set
 * @param attributes The attributes that should have been set for the specified
 *		     item.
 * @param failedAttribute The first attribute that could not be set
 * @param errNo The errno of the error that occurred
 * @return A new, autoreleased set item attributes failed exception
 */
+ (instancetype)exceptionWithURL: (OFURL *)URL
		      attributes: (of_file_attributes_t)attributes
		 failedAttribute: (of_file_attribute_key_t)failedAttribute
		      attributes: (OFFileAttributes)attributes
		 failedAttribute: (OFFileAttributeKey)failedAttribute
			   errNo: (int)errNo;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated set item attributes failed exception.
 *
 * @param URL The URL of the item whose attributes could not be set
 * @param attributes The attributes that should have been set for the specified
 *		     item.
 * @param failedAttribute The first attribute that could not be set
 * @param errNo The errno of the error that occurred
 * @return An initialized set item attributes failed exception
 */
- (instancetype)initWithURL: (OFURL *)URL
		 attributes: (of_file_attributes_t)attributes
	    failedAttribute: (of_file_attribute_key_t)failedAttribute
		 attributes: (OFFileAttributes)attributes
	    failedAttribute: (OFFileAttributeKey)failedAttribute
		      errNo: (int)errNo OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Modified src/exceptions/OFSetItemAttributesFailedException.m from [86a87692ad] to [868fc58c92].

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







-
-
+
+














-
-
+
+








+ (instancetype)exception
{
	OF_UNRECOGNIZED_SELECTOR
}

+ (instancetype)exceptionWithURL: (OFURL *)URL
		      attributes: (of_file_attributes_t)attributes
		 failedAttribute: (of_file_attribute_key_t)failedAttribute
		      attributes: (OFFileAttributes)attributes
		 failedAttribute: (OFFileAttributeKey)failedAttribute
			   errNo: (int)errNo
{
	return [[[self alloc] initWithURL: URL
			       attributes: attributes
			  failedAttribute: failedAttribute
				    errNo: errNo] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithURL: (OFURL *)URL
		 attributes: (of_file_attributes_t)attributes
	    failedAttribute: (of_file_attribute_key_t)failedAttribute
		 attributes: (OFFileAttributes)attributes
	    failedAttribute: (OFFileAttributeKey)failedAttribute
		      errNo: (int)errNo
{
	self = [super init];

	@try {
		_URL = [URL copy];
		_attributes = [attributes copy];

Modified src/macros.h from [77087818b9] to [4a71564d16].

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
98
99
100
101
102
103
104






105
106
107
108
109
110
111







-
-
-
-
-
-







# define OF_LIKELY(cond) (cond)
# define OF_UNLIKELY(cond) (cond)
# define OF_CONST_FUNC
# define OF_NO_RETURN_FUNC
# define OF_WEAK_REF(sym)
#endif

#ifdef OF_BIG_ENDIAN
# define OF_BYTE_ORDER_NATIVE OF_BYTE_ORDER_BIG_ENDIAN
#else
# define OF_BYTE_ORDER_NATIVE OF_BYTE_ORDER_LITTLE_ENDIAN
#endif

#if __STDC_VERSION__ >= 201112L
# define OF_ALIGNOF(type) _Alignof(type)
# define OF_ALIGNAS(type) _Alignas(type)
#else
# define OF_ALIGNOF(type) __alignof__(type)
# define OF_ALIGNAS(type) __attribute__((__aligned__(__alignof__(type))))
#endif
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
346
347
348
349
350
351
352

353
354
355
356
357
358
359







-







#    define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
#   endif
#  endif
# endif
#endif

#define OF_RETAIN_COUNT_MAX UINT_MAX
#define OF_NOT_FOUND SIZE_MAX

#ifdef OBJC_COMPILING_RUNTIME
# define OF_ENSURE(cond)						\
	do {								\
		if OF_UNLIKELY (!(cond))				\
			objc_error("ObjFWRT @ " __FILE__ ":"		\
			    OF_STRINGIFY(__LINE__),			\

Modified src/of_asprintf.m from [d2e16772ed] to [32debbce88].

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







-
+
















-
-
+
+







			return false;

		ctx->subformat[ctx->subformatLen - 1] = 's';

		{
			char buffer[5];
			size_t len = of_string_utf8_encode(
			    va_arg(ctx->arguments, of_unichar_t), buffer);
			    va_arg(ctx->arguments, OFUnichar), buffer);

			if (len == 0)
				return false;

			buffer[len] = 0;
			tmpLen = asprintf(&tmp, ctx->subformat, buffer);
		}

		break;
	case 'S':
		if (ctx->lengthModifier != LENGTH_MODIFIER_NONE)
			return false;

		ctx->subformat[ctx->subformatLen - 1] = 's';

		{
			const of_unichar_t *arg =
			    va_arg(ctx->arguments, const of_unichar_t *);
			const OFUnichar *arg =
			    va_arg(ctx->arguments, const OFUnichar *);
			size_t j, len = of_string_utf32_length(arg);
			char *buffer;

			if (SIZE_MAX / 4 < len || (SIZE_MAX / 4) - len < 1)
				return false;

			if ((buffer = malloc((len * 4) + 1)) == NULL)

Modified src/platform/amiga/OFString+PathAdditions.m from [173be0674b] to [52b79caac6].

115
116
117
118
119
120
121
122
123


124
125
126
127
128
129
130
115
116
117
118
119
120
121


122
123
124
125
126
127
128
129
130







-
-
+
+







{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringFromIndex: pos + 1];

	[ret retain];
151
152
153
154
155
156
157
158

159
160
161
162
163
164
165
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165







-
+







		}

		objc_autoreleasePoolPop(pool);
		return @"";
	}

	components = [components objectsInRange:
	    of_range(0, components.count - 1)];
	    OFMakeRange(0, components.count - 1)];
	ret = [OFString pathWithComponents: components];

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

174
175
176
177
178
179
180
181
182


183
184
185
186
187
188
189
174
175
176
177
178
179
180


181
182
183
184
185
186
187
188
189







-
-
+
+







		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringToIndex: pos];
	[components replaceObjectAtIndex: components.count - 1
			      withObject: fileName];
231
232
233
234
235
236
237
238

239
240
241
242
243
244
245
231
232
233
234
235
236
237

238
239
240
241
242
243
244
245







-
+







				done = false;
				break;
			}

			if ([component isEqual: @"/"] &&
			    parent != nil && ![parent isEqual: @"/"]) {
				[array removeObjectsInRange:
				    of_range(i - 1, 2)];
				    OFMakeRange(i - 1, 2)];

				done = false;
				break;
			}
		}
	}

Modified src/platform/amiga/condition.m from [fd8eb39931] to [dc620431f9].

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







-
+









-
+







	Permit();

	return error;
}

int
of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex,
    of_time_interval_t timeout)
    OFTimeInterval timeout)
{
	ULONG signalMask = 0;

	return of_condition_timed_wait_or_signal(condition, mutex, timeout,
	    &signalMask);
}

int
of_condition_timed_wait_or_signal(of_condition_t *condition, of_mutex_t *mutex,
    of_time_interval_t timeout, ULONG *signalMask)
    OFTimeInterval timeout, ULONG *signalMask)
{
	struct of_condition_waiting_task waitingTask = {
		.task = FindTask(NULL),
		.sigBit = AllocSignal(-1)
	};
	struct MsgPort port = {
		.mp_Node = {

Modified src/platform/libfat/OFString+PathAdditions.m from [420e4f330e] to [cf135b33f9].

149
150
151
152
153
154
155
156
157


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


156
157
158
159
160
161
162
163
164







-
-
+
+







{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringFromIndex: pos + 1];

	[ret retain];
219
220
221
222
223
224
225
226
227


228
229
230
231
232
233
234
219
220
221
222
223
224
225


226
227
228
229
230
231
232
233
234







-
-
+
+







		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringToIndex: pos];
	[components replaceObjectAtIndex: components.count - 1
			      withObject: fileName];
277
278
279
280
281
282
283
284

285
286
287
288
289
290
291
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291







-
+







				done = false;
				break;
			}

			if ([component isEqual: @".."] &&
			    parent != nil && ![parent isEqual: @".."]) {
				[array removeObjectsInRange:
				    of_range(i - 1, 2)];
				    OFMakeRange(i - 1, 2)];

				done = false;
				break;
			}
		}
	}

Modified src/platform/posix/OFString+PathAdditions.m from [456ec4e1f3] to [721ad2b22b].

142
143
144
145
146
147
148
149
150


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


149
150
151
152
153
154
155
156
157







-
-
+
+







{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringFromIndex: pos + 1];

	[ret retain];
211
212
213
214
215
216
217
218
219


220
221
222
223
224
225
226
211
212
213
214
215
216
217


218
219
220
221
222
223
224
225
226







-
-
+
+







		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringToIndex: pos];
	[components replaceObjectAtIndex: [components count] - 1
			      withObject: fileName];
273
274
275
276
277
278
279
280

281
282
283
284
285
286
287
273
274
275
276
277
278
279

280
281
282
283
284
285
286
287







-
+







				done = false;
				break;
			}

			if ([component isEqual: @".."] &&
			    parent != nil && ![parent isEqual: @".."]) {
				[array removeObjectsInRange:
				    of_range(i - 1, 2)];
				    OFMakeRange(i - 1, 2)];

				done = false;
				break;
			}
		}
	}

Modified src/platform/posix/OFSubprocess.m from [d13ad2c4b0] to [4e071fc7f6].

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







-
+


















-
+








- (void)of_getArgv: (char ***)argv
    forProgramName: (OFString *)programName
      andArguments: (OFArray *)arguments
{
	OFString *const *objects = arguments.objects;
	size_t i, count = arguments.count;
	of_string_encoding_t encoding;
	OFStringEncoding encoding;

	*argv = of_alloc(count + 2, sizeof(char *));

	encoding = [OFLocale encoding];

	(*argv)[0] = (char *)[programName cStringWithEncoding: encoding];

	for (i = 0; i < count; i++)
		(*argv)[i + 1] =
		    (char *)[objects[i] cStringWithEncoding: encoding];

	(*argv)[i + 1] = NULL;
}

- (char **)of_environmentForDictionary: (OFDictionary *)environment
{
	char **envp;
	size_t count;
	of_string_encoding_t encoding;
	OFStringEncoding encoding;

	if (environment == nil)
		return NULL;

	encoding = [OFLocale encoding];

	count = environment.count;

Modified src/platform/posix/condition.m from [118d5cf68b] to [7ce4083f77].

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







-
+







of_condition_wait(of_condition_t *condition, of_mutex_t *mutex)
{
	return pthread_cond_wait(condition, mutex);
}

int
of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex,
    of_time_interval_t timeout)
    OFTimeInterval timeout)
{
	struct timespec ts;

	ts.tv_sec = (time_t)timeout;
	ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000);

	return pthread_cond_timedwait(condition, mutex, &ts);

Modified src/platform/windows/OFString+PathAdditions.m from [41e0a20445] to [257fbc0423].

153
154
155
156
157
158
159
160
161


162
163
164
165
166
167
168
153
154
155
156
157
158
159


160
161
162
163
164
165
166
167
168







-
-
+
+







{
	void *pool = objc_autoreleasePoolPush();
	OFString *ret, *fileName;
	size_t pos;

	fileName = self.lastPathComponent;
	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return @"";
	}

	ret = [fileName substringFromIndex: pos + 1];

	[ret retain];
199
200
201
202
203
204
205
206

207
208
209
210
211
212
213
199
200
201
202
203
204
205

206
207
208
209
210
211
212
213







-
+







		}

		objc_autoreleasePoolPop(pool);
		return @".";
	}

	components = [components objectsInRange:
	    of_range(0, components.count - 1)];
	    OFMakeRange(0, components.count - 1)];
	ret = [OFString pathWithComponents: components];

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

222
223
224
225
226
227
228
229
230


231
232
233
234
235
236
237
222
223
224
225
226
227
228


229
230
231
232
233
234
235
236
237







-
-
+
+







		return [[self copy] autorelease];

	pool = objc_autoreleasePoolPush();
	components = [[self.pathComponents mutableCopy] autorelease];
	fileName = components.lastObject;

	pos = [fileName rangeOfString: @"."
			      options: OF_STRING_SEARCH_BACKWARDS].location;
	if (pos == OF_NOT_FOUND || pos == 0) {
			      options: OFStringSearchBackwards].location;
	if (pos == OFNotFound || pos == 0) {
		objc_autoreleasePoolPop(pool);
		return [[self copy] autorelease];
	}

	fileName = [fileName substringToIndex: pos];
	[components replaceObjectAtIndex: components.count - 1
			      withObject: fileName];
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298







-
+







			if ([component isEqual: @".."] && parent != nil &&
			    ![parent isEqual: @".."] &&
			    ![parent hasSuffix: @":"] &&
			    ![parent hasSuffix: @":\\"] &&
			    ![parent hasSuffix: @"://"] &&
			    (![parent hasPrefix: @"\\"] || i != 1)) {
				[array removeObjectsInRange:
				    of_range(i - 1, 2)];
				    OFMakeRange(i - 1, 2)];

				done = false;
				break;
			}
		}
	}

335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
335
336
337
338
339
340
341

342
343
344
345
346
347
348
349







-
+







		if (components.count < 2)
			@throw [OFInvalidFormatException exception];

		*URLEncodedHost = [[components objectAtIndex: 1]
		     stringByURLEncodingWithAllowedCharacters:
		     [OFCharacterSet URLHostAllowedCharacterSet]];
		path = [OFString pathWithComponents: [components
		    objectsInRange: of_range(2, components.count - 2)]];
		    objectsInRange: OFMakeRange(2, components.count - 2)]];
	}

	path = [path stringByReplacingOccurrencesOfString: @"\\"
					       withString: @"/"];
	path = [path stringByPrependingString: @"/"];

	return path;

Modified src/platform/windows/OFSubprocess.m from [be45f52a11] to [a5a0197d4c].

31
32
33
34
35
36
37
38

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

38
39
40
41
42
43
44
45







-
+







#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#include <windows.h>

@interface OFSubprocess ()
- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary;
- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary;
- (char *)of_environmentForDictionary: (OFDictionary *)environment;
@end

@implementation OFSubprocess
+ (instancetype)subprocessWithProgram: (OFString *)program
{
	return [[[self alloc] initWithProgram: program] autorelease];
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
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







-
+











-
+














-
+








			if (containsSpaces)
				[argumentsString appendString: @"\""];
		}

		if ([OFSystemInfo isWindowsNT]) {
			size_t length;
			of_char16_t *argumentsCopy;
			OFChar16 *argumentsCopy;
			STARTUPINFOW si;

			memset(&si, 0, sizeof(si));
			si.cb = sizeof(si);
			si.hStdInput = _writePipe[0];
			si.hStdOutput = _readPipe[1];
			si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
			si.dwFlags |= STARTF_USESTDHANDLES;

			length = argumentsString.UTF16StringLength;
			argumentsCopy = of_alloc(length + 1,
			    sizeof(of_char16_t));
			    sizeof(OFChar16));
			memcpy(argumentsCopy, argumentsString.UTF16String,
			    (length + 1) * 2);
			@try {
				if (!CreateProcessW(program.UTF16String,
				    argumentsCopy, NULL, NULL, TRUE,
				    CREATE_UNICODE_ENVIRONMENT,
				    [self of_wideEnvironmentForDictionary:
				    environment], NULL, &si, &pi))
					@throw [OFInitializationFailedException
					    exceptionWithClass: self.class];
			} @finally {
				free(argumentsCopy);
			}
		} else {
			of_string_encoding_t encoding = [OFLocale encoding];
			OFStringEncoding encoding = [OFLocale encoding];
			STARTUPINFO si;

			memset(&si, 0, sizeof(si));
			si.cb = sizeof(si);
			si.hStdInput = _writePipe[0];
			si.hStdOutput = _readPipe[1];
			si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
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
286
287
288
289
290
291
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
286
287
288
289
290
291







-
+




-
-
+
+




-
+


















-
+







{
	if (_readPipe[0] != NULL)
		[self close];

	[super dealloc];
}

- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)environment
- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)environment
{
	OFMutableData *env;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	OFString *key, *object;
	const of_char16_t equal = '=';
	const of_char16_t zero[2] = { 0, 0 };
	const OFChar16 equal = '=';
	const OFChar16 zero[2] = { 0, 0 };

	if (environment == nil)
		return NULL;

	env = [OFMutableData dataWithItemSize: sizeof(of_char16_t)];
	env = [OFMutableData dataWithItemSize: sizeof(OFChar16)];

	keyEnumerator = [environment keyEnumerator];
	objectEnumerator = [environment objectEnumerator];
	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		[env addItems: key.UTF16String count: key.UTF16StringLength];
		[env addItems: &equal count: 1];
		[env addItems: object.UTF16String
			count: object.UTF16StringLength];
		[env addItems: &zero count: 1];
	}
	[env addItems: zero count: 2];

	return env.mutableItems;
}

- (char *)of_environmentForDictionary: (OFDictionary *)environment
{
	of_string_encoding_t encoding = [OFLocale encoding];
	OFStringEncoding encoding = [OFLocale encoding];
	OFMutableData *env;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	OFString *key, *object;

	if (environment == nil)
		return NULL;

Modified src/platform/windows/condition.m from [cc03ce6342] to [595cdc3d8b].

92
93
94
95
96
97
98
99

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

99
100
101
102
103
104
105
106







-
+







	default:
		OF_ENSURE(0);
	}
}

int
of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex,
    of_time_interval_t timeout)
    OFTimeInterval timeout)
{
	int error;
	DWORD status;

	if ((error = of_mutex_unlock(mutex)) != 0)
		return error;

Modified src/socket.h from [354df70c5d] to [5c14e5d604].

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







-
+

-
+

















-
+

-
+

-
+

-
+

-
-
+
+







#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS)
# import "tlskey.h"
#endif

OF_ASSUME_NONNULL_BEGIN

#ifndef OF_WINDOWS
typedef int of_socket_t;
typedef int OFSocketHandle;
#else
typedef SOCKET of_socket_t;
typedef SOCKET OFSocketHandle;
#endif

#ifdef OF_WII
typedef u8 sa_family_t;
#endif

#ifdef OF_MORPHOS
typedef long socklen_t;
typedef u_char sa_family_t;
typedef u_short in_port_t;
#endif

/**
 * @brief A socket address family.
 */
typedef enum {
	/** An unknown address family. */
	OF_SOCKET_ADDRESS_FAMILY_UNKNOWN,
	OFSocketAddressFamilyUnknown,
	/** IPv4 */
	OF_SOCKET_ADDRESS_FAMILY_IPV4,
	OFSocketAddressFamilyIPv4,
	/** IPv6 */
	OF_SOCKET_ADDRESS_FAMILY_IPV6,
	OFSocketAddressFamilyIPv6,
	/** IPX */
	OF_SOCKET_ADDRESS_FAMILY_IPX,
	OFSocketAddressFamilyIPX,
	/** Any address family */
	OF_SOCKET_ADDRESS_FAMILY_ANY = 255
} of_socket_address_family_t;
	OFSocketAddressFamilyAny = 255
} OFSocketAddressFamily;

#ifndef OF_HAVE_IPV6
struct sockaddr_in6 {
	sa_family_t sin6_family;
	in_port_t sin6_port;
	uint32_t sin6_flowinfo;
	struct in6_addr {
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
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
286
287
288
289
290
291

292
293
294
295
296
297
298
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
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
286
287
288
289
290







-
+



-
+







-
+








-
+





-
+
+



-
+

-
-
+


-
+



-
+

-
-
+


-
+



-
+

-
-
+








-
+




-
+





-
-
-
+
+


-
+


-
+

-
-
+
+


-
+


-
-


-
-
+
+


-
+





-
+



-
+





-
-
+


-
+




-
-
+
+


-
+




-
-
+
+


-
+




-
-
+



-
+




-
-
+








-
+







# define sipx_family sa_family
# define sipx_network sa_netnum
# define sipx_node sa_nodenum
# define sipx_port sa_socket
#endif

/**
 * @struct of_socket_address_t socket.h ObjFW/socket.h
 * @struct OFSocketAddress socket.h ObjFW/socket.h
 *
 * @brief A struct which represents a host / port pair for a socket.
 */
struct OF_BOXABLE of_socket_address_t {
struct OF_BOXABLE OFSocketAddress {
	/*
	 * Even though struct sockaddr contains the family, we need to use our
	 * own family, as we need to support storing an IPv6 address on systems
	 * that don't support IPv6. These may not have AF_INET6 defined and we
	 * can't just define it, as the value is system-dependent and might
	 * clash with an existing value.
	 */
	of_socket_address_family_t family;
	OFSocketAddressFamily family;
	union {
		struct sockaddr sockaddr;
		struct sockaddr_in in;
		struct sockaddr_in6 in6;
		struct sockaddr_ipx ipx;
	} sockaddr;
	socklen_t length;
};
typedef struct of_socket_address_t of_socket_address_t;
typedef struct OFSocketAddress OFSocketAddress;

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief Parses the specified IP and port into an of_socket_address_t.
 * @brief Parses the specified IP (either v4 or v6) and port into an
 *	  @ref OFSocketAddress.
 *
 * @param IP The IP to parse
 * @param port The port to use
 * @return The parsed IP and port as an of_socket_address_t
 * @return The parsed IP and port as an OFSocketAddress
 */
extern of_socket_address_t of_socket_address_parse_ip(
    OFString *IP, uint16_t port);
extern OFSocketAddress OFSocketAddressParseIP(OFString *IP, uint16_t port);

/**
 * @brief Parses the specified IPv4 and port into an of_socket_address_t.
 * @brief Parses the specified IPv4 and port into an @ref OFSocketAddress.
 *
 * @param IP The IPv4 to parse
 * @param port The port to use
 * @return The parsed IPv4 and port as an of_socket_address_t
 * @return The parsed IPv4 and port as an OFSocketAddress
 */
extern of_socket_address_t of_socket_address_parse_ipv4(
    OFString *IP, uint16_t port);
extern OFSocketAddress OFSocketAddressParseIPv4(OFString *IP, uint16_t port);

/**
 * @brief Parses the specified IPv6 and port into an of_socket_address_t.
 * @brief Parses the specified IPv6 and port into an @ref OFSocketAddress.
 *
 * @param IP The IPv6 to parse
 * @param port The port to use
 * @return The parsed IPv6 and port as an of_socket_address_t
 * @return The parsed IPv6 and port as an OFSocketAddress
 */
extern of_socket_address_t of_socket_address_parse_ipv6(
    OFString *IP, uint16_t port);
extern OFSocketAddress OFSocketAddressParseIPv6(OFString *IP, uint16_t port);

/**
 * @brief Creates an IPX address for the specified network, node and port.
 *
 * @param node The node in the IPX network
 * @param network The IPX network
 * @param port The IPX port (sometimes called socket number) on the node
 */
extern of_socket_address_t of_socket_address_ipx(
extern OFSocketAddress OFSocketAddressMakeIPX(
    const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network,
    uint16_t port);

/**
 * @brief Compares two of_socket_address_t for equality.
 * @brief Compares two OFSocketAddress for equality.
 *
 * @param address1 The address to compare with the second address
 * @param address2 The second address
 * @return Whether the two addresses are equal
 */
extern bool of_socket_address_equal(
    const of_socket_address_t *_Nonnull address1,
    const of_socket_address_t *_Nonnull address2);
extern bool OFSocketAddressEqual(const OFSocketAddress *_Nonnull address1,
    const OFSocketAddress *_Nonnull address2);

/**
 * @brief Returns the hash for the specified of_socket_address_t.
 * @brief Returns the hash for the specified @ref OFSocketAddress.
 *
 * @param address The address to hash
 * @return The hash for the specified of_socket_address_t
 * @return The hash for the specified OFSocketAddress
 */
extern unsigned long of_socket_address_hash(
    const of_socket_address_t *_Nonnull address);
extern unsigned long OFSocketAddressHash(
    const OFSocketAddress *_Nonnull address);

/**
 * @brief Converts the specified of_socket_address_t to an IP string and port.
 * @brief Converts the specified @ref OFSocketAddress to a string.
 *
 * @param address The address to convert to a string
 * @param port A pointer to an uint16_t which should be set to the port of the
 *	       address or NULL if the port is not needed
 * @return The address as an IP string
 */
extern OFString *_Nonnull of_socket_address_ip_string(
    const of_socket_address_t *_Nonnull address, uint16_t *_Nullable port);
extern OFString *_Nonnull OFSocketAddressString(
    const OFSocketAddress *_Nonnull address);

/**
 * @brief Sets the port of the specified of_socket_address_t, independent of
 * @brief Sets the port of the specified @ref OFSocketAddress, independent of
 *	  the address family used.
 *
 * @param address The address on which to set the port
 * @param port The port to set on the address
 */
extern void of_socket_address_set_port(of_socket_address_t *_Nonnull address,
extern void OFSocketAddressSetPort(OFSocketAddress *_Nonnull address,
    uint16_t port);

/**
 * @brief Returns the port of the specified of_socket_address_t, independent of
 * @brief Returns the port of the specified @ref OFSocketAddress, independent of
 *	  the address family used.
 *
 * @param address The address on which to get the port
 * @return The port of the address
 */
extern uint16_t of_socket_address_get_port(
    const of_socket_address_t *_Nonnull address);
extern uint16_t OFSocketAddressPort(const OFSocketAddress *_Nonnull address);

/**
 * @brief Sets the IPX network of the specified of_socket_address_t.
 * @brief Sets the IPX network of the specified @ref OFSocketAddress.
 *
 * @param address The address on which to set the IPX network
 * @param network The IPX network to set on the address
 */
extern void of_socket_address_set_ipx_network(
    of_socket_address_t *_Nonnull address, uint32_t network);
extern void OFSocketAddressSetIPXNetwork(OFSocketAddress *_Nonnull address,
    uint32_t network);

/**
 * @brief Returns the IPX network of the specified of_socket_address_t.
 * @brief Returns the IPX network of the specified @ref OFSocketAddress.
 *
 * @param address The address on which to get the IPX network
 * @return The IPX network of the address
 */
extern uint32_t of_socket_address_get_ipx_network(
    const of_socket_address_t *_Nonnull address);
extern uint32_t OFSocketAddressIPXNetwork(
    const OFSocketAddress *_Nonnull address);

/**
 * @brief Sets the IPX node of the specified of_socket_address_t.
 * @brief Sets the IPX node of the specified @ref OFSocketAddress.
 *
 * @param address The address on which to set the IPX node
 * @param node The IPX node to set on the address
 */
extern void of_socket_address_set_ipx_node(
    of_socket_address_t *_Nonnull address,
extern void OFSocketAddressSetIPXNode(OFSocketAddress *_Nonnull address,
    const unsigned char node[_Nonnull IPX_NODE_LEN]);

/**
 * @brief Gets the IPX node of the specified of_socket_address_t.
 * @brief Gets the IPX node of the specified @ref OFSocketAddress.
 *
 * @param address The address on which to get the IPX node
 * @param node A byte array to store the IPX node of the address
 */
extern void of_socket_address_get_ipx_node(
    const of_socket_address_t *_Nonnull address,
extern void OFSocketAddressIPXNode(const OFSocketAddress *_Nonnull address,
    unsigned char node[_Nonnull IPX_NODE_LEN]);

extern bool of_socket_init(void);
#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS)
extern void of_socket_deinit(void);
#endif
extern int of_socket_errno(void);
#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
extern int of_getsockname(of_socket_t sock, struct sockaddr *restrict addr,
extern int of_getsockname(OFSocketHandle sock, struct sockaddr *restrict addr,
    socklen_t *restrict addrLen);
#endif

#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS)
extern of_tlskey_t of_socket_base_key;
# ifdef OF_AMIGAOS4
extern of_tlskey_t of_socket_interface_key;

Modified src/socket.m from [21df00d3c4] to [35ea54e031].

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







-
+
















-
-
+
+




-
+





-
+







#else
	return errno;
#endif
}

#ifndef OF_WII
int
of_getsockname(of_socket_t sock, struct sockaddr *restrict addr,
of_getsockname(OFSocketHandle sock, struct sockaddr *restrict addr,
    socklen_t *restrict addrLen)
{
	int ret;

# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS))
	[mutex lock];
# endif
	ret = getsockname(sock, addr, addrLen);
# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS))
	[mutex unlock];
# endif

	return ret;
}
#endif

of_socket_address_t
of_socket_address_parse_ipv4(OFString *IPv4, uint16_t port)
OFSocketAddress
OFSocketAddressParseIPv4(OFString *IPv4, uint16_t port)
{
	void *pool = objc_autoreleasePoolPush();
	OFCharacterSet *whitespaceCharacterSet =
	    [OFCharacterSet whitespaceCharacterSet];
	of_socket_address_t ret;
	OFSocketAddress ret;
	struct sockaddr_in *addrIn = &ret.sockaddr.in;
	OFArray OF_GENERIC(OFString *) *components;
	uint32_t addr;

	memset(&ret, '\0', sizeof(ret));
	ret.family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
	ret.family = OFSocketAddressFamilyIPv4;
#if defined(OF_WII) || defined(OF_NINTENDO_3DS)
	ret.length = 8;
#else
	ret.length = sizeof(ret.sockaddr.in);
#endif

	addrIn->sin_family = AF_INET;
383
384
385
386
387
388
389
390

391
392
393
394
395
396
397
383
384
385
386
387
388
389

390
391
392
393
394
395
396
397







-
+







	for (OFString *component in components) {
		unsigned long long number;

		if (component.length == 0)
			@throw [OFInvalidFormatException exception];

		if ([component indexOfCharacterFromSet:
		    whitespaceCharacterSet] != OF_NOT_FOUND)
		    whitespaceCharacterSet] != OFNotFound)
			@throw [OFInvalidFormatException exception];

		number = component.unsignedLongLongValue;

		if (number > UINT8_MAX)
			@throw [OFInvalidFormatException exception];

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







-
+










-
-
+
+


-
+




-
+











-
+








static uint16_t
parseIPv6Component(OFString *component)
{
	unsigned long long number;

	if ([component indexOfCharacterFromSet:
	    [OFCharacterSet whitespaceCharacterSet]] != OF_NOT_FOUND)
	    [OFCharacterSet whitespaceCharacterSet]] != OFNotFound)
		@throw [OFInvalidFormatException exception];

	number = [component unsignedLongLongValueWithBase: 16];

	if (number > UINT16_MAX)
		@throw [OFInvalidFormatException exception];

	return (uint16_t)number;
}

of_socket_address_t
of_socket_address_parse_ipv6(OFString *IPv6, uint16_t port)
OFSocketAddress
OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port)
{
	void *pool = objc_autoreleasePoolPush();
	of_socket_address_t ret;
	OFSocketAddress ret;
	struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6;
	size_t doubleColon;

	memset(&ret, '\0', sizeof(ret));
	ret.family = OF_SOCKET_ADDRESS_FAMILY_IPV6;
	ret.family = OFSocketAddressFamilyIPv6;
	ret.length = sizeof(ret.sockaddr.in6);

#ifdef AF_INET6
	addrIn6->sin6_family = AF_INET6;
#else
	addrIn6->sin6_family = AF_UNSPEC;
#endif
	addrIn6->sin6_port = OF_BSWAP16_IF_LE(port);

	doubleColon = [IPv6 rangeOfString: @"::"].location;

	if (doubleColon != OF_NOT_FOUND) {
	if (doubleColon != OFNotFound) {
		OFString *left = [IPv6 substringToIndex: doubleColon];
		OFString *right = [IPv6 substringFromIndex: doubleColon + 2];
		OFArray OF_GENERIC(OFString *) *leftComponents;
		OFArray OF_GENERIC(OFString *) *rightComponents;
		size_t i;

		if ([right hasPrefix: @":"] || [right containsString: @"::"])
497
498
499
500
501
502
503
504
505


506
507

508
509
510

511
512

513
514
515
516
517
518
519


520
521
522

523
524
525

526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544


545
546
547
548
549
550
551
552
553
554

555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573

574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589

590
591
592
593
594
595
596
497
498
499
500
501
502
503


504
505
506

507
508
509

510
511

512
513
514
515
516
517


518
519
520
521

522
523
524

525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542


543
544
545
546
547
548
549
550
551
552
553

554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572

573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
596







-
-
+
+

-
+


-
+

-
+





-
-
+
+


-
+


-
+

















-
-
+
+









-
+


















-
+















-
+







	}

	objc_autoreleasePoolPop(pool);

	return ret;
}

of_socket_address_t
of_socket_address_parse_ip(OFString *IP, uint16_t port)
OFSocketAddress
OFSocketAddressParseIP(OFString *IP, uint16_t port)
{
	of_socket_address_t ret;
	OFSocketAddress ret;

	@try {
		ret = of_socket_address_parse_ipv6(IP, port);
		ret = OFSocketAddressParseIPv6(IP, port);
	} @catch (OFInvalidFormatException *e) {
		ret = of_socket_address_parse_ipv4(IP, port);
		ret = OFSocketAddressParseIPv4(IP, port);
	}

	return ret;
}

of_socket_address_t
of_socket_address_ipx(const unsigned char node[IPX_NODE_LEN], uint32_t network,
OFSocketAddress
OFSocketAddressMakeIPX(const unsigned char node[IPX_NODE_LEN], uint32_t network,
    uint16_t port)
{
	of_socket_address_t ret;
	OFSocketAddress ret;

	memset(&ret, '\0', sizeof(ret));
	ret.family = OF_SOCKET_ADDRESS_FAMILY_IPX;
	ret.family = OFSocketAddressFamilyIPX;
	ret.length = sizeof(ret.sockaddr.ipx);

#ifdef AF_IPX
	ret.sockaddr.ipx.sipx_family = AF_IPX;
#else
	ret.sockaddr.ipx.sipx_family = AF_UNSPEC;
#endif
	memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN);
	network = OF_BSWAP32_IF_LE(network);
	memcpy(&ret.sockaddr.ipx.sipx_network, &network,
	    sizeof(ret.sockaddr.ipx.sipx_network));
	ret.sockaddr.ipx.sipx_port = OF_BSWAP16_IF_LE(port);

	return ret;
}

bool
of_socket_address_equal(const of_socket_address_t *address1,
    const of_socket_address_t *address2)
OFSocketAddressEqual(const OFSocketAddress *address1,
    const OFSocketAddress *address2)
{
	const struct sockaddr_in *addrIn1, *addrIn2;
	const struct sockaddr_in6 *addrIn6_1, *addrIn6_2;
	const struct sockaddr_ipx *addrIPX1, *addrIPX2;

	if (address1->family != address2->family)
		return false;

	switch (address1->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
	case OFSocketAddressFamilyIPv4:
#if defined(OF_WII) || defined(OF_NINTENDO_3DS)
		if (address1->length < 8 || address2->length < 8)
			@throw [OFInvalidArgumentException exception];
#else
		if (address1->length < (socklen_t)sizeof(struct sockaddr_in) ||
		    address2->length < (socklen_t)sizeof(struct sockaddr_in))
			@throw [OFInvalidArgumentException exception];
#endif

		addrIn1 = &address1->sockaddr.in;
		addrIn2 = &address2->sockaddr.in;

		if (addrIn1->sin_port != addrIn2->sin_port)
			return false;
		if (addrIn1->sin_addr.s_addr != addrIn2->sin_addr.s_addr)
			return false;

		break;
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
	case OFSocketAddressFamilyIPv6:
		if (address1->length < (socklen_t)sizeof(struct sockaddr_in6) ||
		    address2->length < (socklen_t)sizeof(struct sockaddr_in6))
			@throw [OFInvalidArgumentException exception];

		addrIn6_1 = &address1->sockaddr.in6;
		addrIn6_2 = &address2->sockaddr.in6;

		if (addrIn6_1->sin6_port != addrIn6_2->sin6_port)
			return false;
		if (memcmp(addrIn6_1->sin6_addr.s6_addr,
		    addrIn6_2->sin6_addr.s6_addr,
		    sizeof(addrIn6_1->sin6_addr.s6_addr)) != 0)
			return false;

		break;
	case OF_SOCKET_ADDRESS_FAMILY_IPX:
	case OFSocketAddressFamilyIPX:
		if (address1->length < (socklen_t)sizeof(struct sockaddr_ipx) ||
		    address2->length < (socklen_t)sizeof(struct sockaddr_ipx))
			@throw [OFInvalidArgumentException exception];

		addrIPX1 = &address1->sockaddr.ipx;
		addrIPX2 = &address2->sockaddr.ipx;

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







-
+







-
+
















-
+












-
+







		@throw [OFInvalidArgumentException exception];
	}

	return true;
}

unsigned long
of_socket_address_hash(const of_socket_address_t *address)
OFSocketAddressHash(const OFSocketAddress *address)
{
	uint32_t hash;

	OF_HASH_INIT(hash);
	OF_HASH_ADD(hash, address->family);

	switch (address->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
	case OFSocketAddressFamilyIPv4:
#if defined(OF_WII) || defined(OF_NINTENDO_3DS)
		if (address->length < 8)
			@throw [OFInvalidArgumentException exception];
#else
		if (address->length < (socklen_t)sizeof(struct sockaddr_in))
			@throw [OFInvalidArgumentException exception];
#endif

		OF_HASH_ADD(hash, address->sockaddr.in.sin_port >> 8);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_port);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 24);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 16);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 8);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr);

		break;
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
	case OFSocketAddressFamilyIPv6:
		if (address->length < (socklen_t)sizeof(struct sockaddr_in6))
			@throw [OFInvalidArgumentException exception];

		OF_HASH_ADD(hash, address->sockaddr.in6.sin6_port >> 8);
		OF_HASH_ADD(hash, address->sockaddr.in6.sin6_port);

		for (size_t i = 0;
		    i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++)
			OF_HASH_ADD(hash,
			    address->sockaddr.in6.sin6_addr.s6_addr[i]);

		break;
	case OF_SOCKET_ADDRESS_FAMILY_IPX:;
	case OFSocketAddressFamilyIPX:;
		unsigned char network[
		    sizeof(address->sockaddr.ipx.sipx_network)];

		if (address->length < (socklen_t)sizeof(struct sockaddr_ipx))
			@throw [OFInvalidArgumentException exception];

		OF_HASH_ADD(hash, address->sockaddr.ipx.sipx_port >> 8);
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
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







-
+









-
-
-




-
+








	OF_HASH_FINALIZE(hash);

	return hash;
}

static OFString *
IPv4String(const of_socket_address_t *address, uint16_t *port)
IPv4String(const OFSocketAddress *address)
{
	const struct sockaddr_in *addrIn = &address->sockaddr.in;
	uint32_t addr = OF_BSWAP32_IF_LE(addrIn->sin_addr.s_addr);
	OFString *string;

	string = [OFString stringWithFormat: @"%u.%u.%u.%u",
	    (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16,
	    (addr & 0x0000FF00) >>  8, addr & 0x000000FF];

	if (port != NULL)
		*port = OF_BSWAP16_IF_LE(addrIn->sin_port);

	return string;
}

static OFString *
IPv6String(const of_socket_address_t *address, uint16_t *port)
IPv6String(const OFSocketAddress *address)
{
	OFMutableString *string = [OFMutableString string];
	const struct sockaddr_in6 *addrIn6 = &address->sockaddr.in6;
	int_fast8_t zerosStart = -1, maxZerosStart = -1;
	uint_fast8_t zerosCount = 0, maxZerosCount = 0;
	bool first = true;

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

771
772
773
774
775
776




777
778
779
780
781
782
783

784
785
786

787
788
789

790
791
792

793
794
795
796
797
798
799
800
801

802
803
804

805
806

807
808

809
810
811
812
813
814
815
816
817

818
819

820
821
822
823
824
825
826
827
828

829
830
831
832

833
834
835
836
837
838
839
840
841

842
843
844

845
846
847
848
849
850
851

852
853
854

855
856
857
858
753
754
755
756
757
758
759



760
761
762
763

764
765
766




767
768
769
770
771
772
773
774
775
776

777
778
779

780
781
782

783
784
785

786
787
788
789
790
791
792
793
794

795
796
797

798
799

800
801

802
803
804
805
806
807
808
809


810
811

812
813
814
815
816
817
818
819
820

821
822
823
824

825
826
827
828
829
830
831
832
833

834
835
836

837
838
839
840
841
842
843

844
845
846

847
848
849
850
851







-
-
-




-
+


-
-
-
-
+
+
+
+






-
+


-
+


-
+


-
+








-
+


-
+

-
+

-
+







-
-
+

-
+








-
+



-
+








-
+


-
+






-
+


-
+




			    addrIn6->sin6_addr.s6_addr[i + 1]];
			first = false;
		}
	}

	[string makeImmutable];

	if (port != NULL)
		*port = OF_BSWAP16_IF_LE(addrIn6->sin6_port);

	return string;
}

OFString *
of_socket_address_ip_string(const of_socket_address_t *address, uint16_t *port)
OFSocketAddressString(const OFSocketAddress *address)
{
	switch (address->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
		return IPv4String(address, port);
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
		return IPv6String(address, port);
	case OFSocketAddressFamilyIPv4:
		return IPv4String(address);
	case OFSocketAddressFamilyIPv6:
		return IPv6String(address);
	default:
		@throw [OFInvalidArgumentException exception];
	}
}

void
of_socket_address_set_port(of_socket_address_t *address, uint16_t port)
OFSocketAddressSetPort(OFSocketAddress *address, uint16_t port)
{
	switch (address->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
	case OFSocketAddressFamilyIPv4:
		address->sockaddr.in.sin_port = OF_BSWAP16_IF_LE(port);
		break;
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
	case OFSocketAddressFamilyIPv6:
		address->sockaddr.in6.sin6_port = OF_BSWAP16_IF_LE(port);
		break;
	case OF_SOCKET_ADDRESS_FAMILY_IPX:
	case OFSocketAddressFamilyIPX:
		address->sockaddr.ipx.sipx_port = OF_BSWAP16_IF_LE(port);
		break;
	default:
		@throw [OFInvalidArgumentException exception];
	}
}

uint16_t
of_socket_address_get_port(const of_socket_address_t *address)
OFSocketAddressPort(const OFSocketAddress *address)
{
	switch (address->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
	case OFSocketAddressFamilyIPv4:
		return OF_BSWAP16_IF_LE(address->sockaddr.in.sin_port);
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
	case OFSocketAddressFamilyIPv6:
		return OF_BSWAP16_IF_LE(address->sockaddr.in6.sin6_port);
	case OF_SOCKET_ADDRESS_FAMILY_IPX:
	case OFSocketAddressFamilyIPX:
		return OF_BSWAP16_IF_LE(address->sockaddr.ipx.sipx_port);
	default:
		@throw [OFInvalidArgumentException exception];
	}
}

void
of_socket_address_set_ipx_network(of_socket_address_t *address,
    uint32_t network)
OFSocketAddressSetIPXNetwork(OFSocketAddress *address, uint32_t network)
{
	if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX)
	if (address->family != OFSocketAddressFamilyIPX)
		@throw [OFInvalidArgumentException exception];

	network = OF_BSWAP32_IF_LE(network);
	memcpy(&address->sockaddr.ipx.sipx_network, &network,
	    sizeof(address->sockaddr.ipx.sipx_network));
}

uint32_t
of_socket_address_get_ipx_network(const of_socket_address_t *address)
OFSocketAddressIPXNetwork(const OFSocketAddress *address)
{
	uint32_t network;

	if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX)
	if (address->family != OFSocketAddressFamilyIPX)
		@throw [OFInvalidArgumentException exception];

	memcpy(&network, &address->sockaddr.ipx.sipx_network, sizeof(network));

	return OF_BSWAP32_IF_LE(network);
}

void
of_socket_address_set_ipx_node(of_socket_address_t *address,
OFSocketAddressSetIPXNode(OFSocketAddress *address,
    const unsigned char node[IPX_NODE_LEN])
{
	if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX)
	if (address->family != OFSocketAddressFamilyIPX)
		@throw [OFInvalidArgumentException exception];

	memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN);
}

void
of_socket_address_get_ipx_node(const of_socket_address_t *address,
OFSocketAddressIPXNode(const OFSocketAddress *address,
    unsigned char node[IPX_NODE_LEN])
{
	if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX)
	if (address->family != OFSocketAddressFamilyIPX)
		@throw [OFInvalidArgumentException exception];

	memcpy(node, address->sockaddr.ipx.sipx_node, IPX_NODE_LEN);
}

Modified src/unicode.h from [2ed16f1d09] to [713ec05b75].

21
22
23
24
25
26
27
28

29
30

31
32

33
34

35
36
37
38
39
40
41
42
21
22
23
24
25
26
27

28
29

30
31

32
33

34
35
36
37
38
39
40
41
42







-
+

-
+

-
+

-
+








#define OF_UNICODE_CASEFOLDING_TABLE_SIZE 0x1EA
#define OF_UNICODE_DECOMPOSITION_TABLE_SIZE 0x2FB
#define OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE 0x2FB

#ifdef __cplusplus
extern "C" {
#endif
extern const of_unichar_t *const _Nonnull
extern const OFUnichar *const _Nonnull
    of_unicode_uppercase_table[OF_UNICODE_UPPERCASE_TABLE_SIZE];
extern const of_unichar_t *const _Nonnull
extern const OFUnichar *const _Nonnull
    of_unicode_lowercase_table[OF_UNICODE_LOWERCASE_TABLE_SIZE];
extern const of_unichar_t *const _Nonnull
extern const OFUnichar *const _Nonnull
    of_unicode_titlecase_table[OF_UNICODE_TITLECASE_TABLE_SIZE];
extern const of_unichar_t *const _Nonnull
extern const OFUnichar *const _Nonnull
    of_unicode_casefolding_table[OF_UNICODE_CASEFOLDING_TABLE_SIZE];
extern const char *const _Nullable *const _Nonnull
    of_unicode_decomposition_table[OF_UNICODE_DECOMPOSITION_TABLE_SIZE];
extern const char *const _Nullable *const _Nonnull
    of_unicode_decomposition_compat_table[OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE];
#ifdef __cplusplus
}
#endif

Modified src/unicode.m from [bb9481f3ae] to [5fc3ae74f1].

13
14
15
16
17
18
19
20

21
22
23

24
25
26
27
28
29
30
13
14
15
16
17
18
19

20
21
22

23
24
25
26
27
28
29
30







-
+


-
+







 * file.
 */

#include "config.h"

#import "OFString.h"

static const of_unichar_t emptyPage[0x100] = { 0 };
static const OFUnichar emptyPage[0x100] = { 0 };
static const char *emptyDecompositionPage[0x100] = { NULL };

static const of_unichar_t uppercasePage0[0x100] = {
static const OFUnichar uppercasePage0[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65
51
52
53
54
55
56
57

58
59
60
61
62
63
64
65







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	192, 193, 194, 195, 196, 197, 198, 199,
	200, 201, 202, 203, 204, 205, 206, 207,
	208, 209, 210, 211, 212, 213, 214, 0,
	216, 217, 218, 219, 220, 221, 222, 376,
};

static const of_unichar_t uppercasePage1[0x100] = {
static const OFUnichar uppercasePage1[0x100] = {
	0, 256, 0, 258, 0, 260, 0, 262,
	0, 264, 0, 266, 0, 268, 0, 270,
	0, 272, 0, 274, 0, 276, 0, 278,
	0, 280, 0, 282, 0, 284, 0, 286,
	0, 288, 0, 290, 0, 292, 0, 294,
	0, 296, 0, 298, 0, 300, 0, 302,
	0, 73, 0, 306, 0, 308, 0, 310,
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







-
+







	471, 0, 473, 0, 475, 398, 0, 478,
	0, 480, 0, 482, 0, 484, 0, 486,
	0, 488, 0, 490, 0, 492, 0, 494,
	0, 0, 497, 497, 0, 500, 0, 0,
	0, 504, 0, 506, 0, 508, 0, 510,
};

static const of_unichar_t uppercasePage2[0x100] = {
static const OFUnichar uppercasePage2[0x100] = {
	0, 512, 0, 514, 0, 516, 0, 518,
	0, 520, 0, 522, 0, 524, 0, 526,
	0, 528, 0, 530, 0, 532, 0, 534,
	0, 536, 0, 538, 0, 540, 0, 542,
	0, 0, 0, 546, 0, 548, 0, 550,
	0, 552, 0, 554, 0, 556, 0, 558,
	0, 560, 0, 562, 0, 0, 0, 0,
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage3[0x100] = {
static const OFUnichar uppercasePage3[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170







-
+







	0, 984, 0, 986, 0, 988, 0, 990,
	0, 992, 0, 994, 0, 996, 0, 998,
	0, 1000, 0, 1002, 0, 1004, 0, 1006,
	922, 929, 1017, 895, 0, 917, 0, 0,
	1015, 0, 0, 1018, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage4[0x100] = {
static const OFUnichar uppercasePage4[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047,
191
192
193
194
195
196
197
198

199
200
201
202
203
204
205
191
192
193
194
195
196
197

198
199
200
201
202
203
204
205







-
+







	0, 1240, 0, 1242, 0, 1244, 0, 1246,
	0, 1248, 0, 1250, 0, 1252, 0, 1254,
	0, 1256, 0, 1258, 0, 1260, 0, 1262,
	0, 1264, 0, 1266, 0, 1268, 0, 1270,
	0, 1272, 0, 1274, 0, 1276, 0, 1278,
};

static const of_unichar_t uppercasePage5[0x100] = {
static const OFUnichar uppercasePage5[0x100] = {
	0, 1280, 0, 1282, 0, 1284, 0, 1286,
	0, 1288, 0, 1290, 0, 1292, 0, 1294,
	0, 1296, 0, 1298, 0, 1300, 0, 1302,
	0, 1304, 0, 1306, 0, 1308, 0, 1310,
	0, 1312, 0, 1314, 0, 1316, 0, 1318,
	0, 1320, 0, 1322, 0, 1324, 0, 1326,
	0, 0, 0, 0, 0, 0, 0, 0,
226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
226
227
228
229
230
231
232

233
234
235
236
237
238
239
240







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage16[0x100] = {
static const OFUnichar uppercasePage16[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
261
262
263
264
265
266
267

268
269
270
271
272
273
274
275







-
+







	7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327,
	7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335,
	7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343,
	7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351,
	7352, 7353, 7354, 0, 0, 7357, 7358, 7359,
};

static const of_unichar_t uppercasePage19[0x100] = {
static const OFUnichar uppercasePage19[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
296
297
298
299
300
301
302
303

304
305
306
307
308
309
310
296
297
298
299
300
301
302

303
304
305
306
307
308
309
310







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	5104, 5105, 5106, 5107, 5108, 5109, 0, 0,
};

static const of_unichar_t uppercasePage28[0x100] = {
static const OFUnichar uppercasePage28[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
331
332
333
334
335
336
337
338

339
340
341
342
343
344
345
331
332
333
334
335
336
337

338
339
340
341
342
343
344
345







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage29[0x100] = {
static const OFUnichar uppercasePage29[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
366
367
368
369
370
371
372
373

374
375
376
377
378
379
380
366
367
368
369
370
371
372

373
374
375
376
377
378
379
380







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage30[0x100] = {
static const OFUnichar uppercasePage30[0x100] = {
	0, 7680, 0, 7682, 0, 7684, 0, 7686,
	0, 7688, 0, 7690, 0, 7692, 0, 7694,
	0, 7696, 0, 7698, 0, 7700, 0, 7702,
	0, 7704, 0, 7706, 0, 7708, 0, 7710,
	0, 7712, 0, 7714, 0, 7716, 0, 7718,
	0, 7720, 0, 7722, 0, 7724, 0, 7726,
	0, 7728, 0, 7730, 0, 7732, 0, 7734,
401
402
403
404
405
406
407
408

409
410
411
412
413
414
415
401
402
403
404
405
406
407

408
409
410
411
412
413
414
415







-
+







	0, 7896, 0, 7898, 0, 7900, 0, 7902,
	0, 7904, 0, 7906, 0, 7908, 0, 7910,
	0, 7912, 0, 7914, 0, 7916, 0, 7918,
	0, 7920, 0, 7922, 0, 7924, 0, 7926,
	0, 7928, 0, 7930, 0, 7932, 0, 7934,
};

static const of_unichar_t uppercasePage31[0x100] = {
static const OFUnichar uppercasePage31[0x100] = {
	7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951,
	0, 0, 0, 0, 0, 0, 0, 0,
	7960, 7961, 7962, 7963, 7964, 7965, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983,
	0, 0, 0, 0, 0, 0, 0, 0,
	7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999,
436
437
438
439
440
441
442
443

444
445
446
447
448
449
450
436
437
438
439
440
441
442

443
444
445
446
447
448
449
450







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	8168, 8169, 0, 0, 0, 8172, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 8188, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage33[0x100] = {
static const OFUnichar uppercasePage33[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
471
472
473
474
475
476
477
478

479
480
481
482
483
484
485
471
472
473
474
475
476
477

478
479
480
481
482
483
484
485







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage36[0x100] = {
static const OFUnichar uppercasePage36[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
506
507
508
509
510
511
512
513

514
515
516
517
518
519
520
506
507
508
509
510
511
512

513
514
515
516
517
518
519
520







-
+







	9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413,
	9414, 9415, 9416, 9417, 9418, 9419, 9420, 9421,
	9422, 9423, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage44[0x100] = {
static const OFUnichar uppercasePage44[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271,
541
542
543
544
545
546
547
548

549
550
551
552
553
554
555
541
542
543
544
545
546
547

548
549
550
551
552
553
554
555







-
+







	0, 11480, 0, 11482, 0, 11484, 0, 11486,
	0, 11488, 0, 11490, 0, 0, 0, 0,
	0, 0, 0, 0, 11499, 0, 11501, 0,
	0, 0, 0, 11506, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage45[0x100] = {
static const OFUnichar uppercasePage45[0x100] = {
	4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263,
	4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271,
	4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279,
	4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287,
	4288, 4289, 4290, 4291, 4292, 4293, 0, 4295,
	0, 0, 0, 0, 0, 4301, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
576
577
578
579
580
581
582
583

584
585
586
587
588
589
590
576
577
578
579
580
581
582

583
584
585
586
587
588
589
590







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage166[0x100] = {
static const OFUnichar uppercasePage166[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
611
612
613
614
615
616
617
618

619
620
621
622
623
624
625
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage167[0x100] = {
static const OFUnichar uppercasePage167[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 42786, 0, 42788, 0, 42790,
	0, 42792, 0, 42794, 0, 42796, 0, 42798,
	0, 0, 0, 42802, 0, 42804, 0, 42806,
646
647
648
649
650
651
652
653

654
655
656
657
658
659
660
646
647
648
649
650
651
652

653
654
655
656
657
658
659
660







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 42997, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage171[0x100] = {
static const OFUnichar uppercasePage171[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
681
682
683
684
685
686
687
688

689
690
691
692
693
694
695
681
682
683
684
685
686
687

688
689
690
691
692
693
694
695







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage255[0x100] = {
static const OFUnichar uppercasePage255[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
716
717
718
719
720
721
722
723

724
725
726
727
728
729
730
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage260[0x100] = {
static const OFUnichar uppercasePage260[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	66560, 66561, 66562, 66563, 66564, 66565, 66566, 66567,
	66568, 66569, 66570, 66571, 66572, 66573, 66574, 66575,
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







-
+







	66736, 66737, 66738, 66739, 66740, 66741, 66742, 66743,
	66744, 66745, 66746, 66747, 66748, 66749, 66750, 66751,
	66752, 66753, 66754, 66755, 66756, 66757, 66758, 66759,
	66760, 66761, 66762, 66763, 66764, 66765, 66766, 66767,
	66768, 66769, 66770, 66771, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage268[0x100] = {
static const OFUnichar uppercasePage268[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
786
787
788
789
790
791
792
793

794
795
796
797
798
799
800
786
787
788
789
790
791
792

793
794
795
796
797
798
799
800







-
+







	68760, 68761, 68762, 68763, 68764, 68765, 68766, 68767,
	68768, 68769, 68770, 68771, 68772, 68773, 68774, 68775,
	68776, 68777, 68778, 68779, 68780, 68781, 68782, 68783,
	68784, 68785, 68786, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage280[0x100] = {
static const OFUnichar uppercasePage280[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
821
822
823
824
825
826
827
828

829
830
831
832
833
834
835
821
822
823
824
825
826
827

828
829
830
831
832
833
834
835







-
+







	71864, 71865, 71866, 71867, 71868, 71869, 71870, 71871,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage366[0x100] = {
static const OFUnichar uppercasePage366[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
856
857
858
859
860
861
862
863

864
865
866
867
868
869
870
856
857
858
859
860
861
862

863
864
865
866
867
868
869
870







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t uppercasePage489[0x100] = {
static const OFUnichar uppercasePage489[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 125184, 125185, 125186, 125187, 125188, 125189,
	125190, 125191, 125192, 125193, 125194, 125195, 125196, 125197,
	125198, 125199, 125200, 125201, 125202, 125203, 125204, 125205,
891
892
893
894
895
896
897
898

899
900
901
902
903
904
905
891
892
893
894
895
896
897

898
899
900
901
902
903
904
905







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage0[0x100] = {
static const OFUnichar lowercasePage0[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
926
927
928
929
930
931
932
933

934
935
936
937
938
939
940
926
927
928
929
930
931
932

933
934
935
936
937
938
939
940







-
+







	248, 249, 250, 251, 252, 253, 254, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage1[0x100] = {
static const OFUnichar lowercasePage1[0x100] = {
	257, 0, 259, 0, 261, 0, 263, 0,
	265, 0, 267, 0, 269, 0, 271, 0,
	273, 0, 275, 0, 277, 0, 279, 0,
	281, 0, 283, 0, 285, 0, 287, 0,
	289, 0, 291, 0, 293, 0, 295, 0,
	297, 0, 299, 0, 301, 0, 303, 0,
	105, 0, 307, 0, 309, 0, 311, 0,
961
962
963
964
965
966
967
968

969
970
971
972
973
974
975
961
962
963
964
965
966
967

968
969
970
971
972
973
974
975







-
+







	0, 474, 0, 476, 0, 0, 479, 0,
	481, 0, 483, 0, 485, 0, 487, 0,
	489, 0, 491, 0, 493, 0, 495, 0,
	0, 499, 499, 0, 501, 0, 405, 447,
	505, 0, 507, 0, 509, 0, 511, 0,
};

static const of_unichar_t lowercasePage2[0x100] = {
static const OFUnichar lowercasePage2[0x100] = {
	513, 0, 515, 0, 517, 0, 519, 0,
	521, 0, 523, 0, 525, 0, 527, 0,
	529, 0, 531, 0, 533, 0, 535, 0,
	537, 0, 539, 0, 541, 0, 543, 0,
	414, 0, 547, 0, 549, 0, 551, 0,
	553, 0, 555, 0, 557, 0, 559, 0,
	561, 0, 563, 0, 0, 0, 0, 0,
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







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage3[0x100] = {
static const OFUnichar lowercasePage3[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1031
1032
1033
1034
1035
1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1031
1032
1033
1034
1035
1036
1037

1038
1039
1040
1041
1042
1043
1044
1045







-
+







	985, 0, 987, 0, 989, 0, 991, 0,
	993, 0, 995, 0, 997, 0, 999, 0,
	1001, 0, 1003, 0, 1005, 0, 1007, 0,
	0, 0, 0, 0, 952, 0, 0, 1016,
	0, 1010, 1019, 0, 0, 891, 892, 893,
};

static const of_unichar_t lowercasePage4[0x100] = {
static const OFUnichar lowercasePage4[0x100] = {
	1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
	1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119,
	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,
	0, 0, 0, 0, 0, 0, 0, 0,
1066
1067
1068
1069
1070
1071
1072
1073

1074
1075
1076
1077
1078
1079
1080
1066
1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
1080







-
+







	1241, 0, 1243, 0, 1245, 0, 1247, 0,
	1249, 0, 1251, 0, 1253, 0, 1255, 0,
	1257, 0, 1259, 0, 1261, 0, 1263, 0,
	1265, 0, 1267, 0, 1269, 0, 1271, 0,
	1273, 0, 1275, 0, 1277, 0, 1279, 0,
};

static const of_unichar_t lowercasePage5[0x100] = {
static const OFUnichar lowercasePage5[0x100] = {
	1281, 0, 1283, 0, 1285, 0, 1287, 0,
	1289, 0, 1291, 0, 1293, 0, 1295, 0,
	1297, 0, 1299, 0, 1301, 0, 1303, 0,
	1305, 0, 1307, 0, 1309, 0, 1311, 0,
	1313, 0, 1315, 0, 1317, 0, 1319, 0,
	1321, 0, 1323, 0, 1325, 0, 1327, 0,
	0, 1377, 1378, 1379, 1380, 1381, 1382, 1383,
1101
1102
1103
1104
1105
1106
1107
1108

1109
1110
1111
1112
1113
1114
1115
1101
1102
1103
1104
1105
1106
1107

1108
1109
1110
1111
1112
1113
1114
1115







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage16[0x100] = {
static const OFUnichar lowercasePage16[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1136
1137
1138
1139
1140
1141
1142
1143

1144
1145
1146
1147
1148
1149
1150
1136
1137
1138
1139
1140
1141
1142

1143
1144
1145
1146
1147
1148
1149
1150







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage19[0x100] = {
static const OFUnichar lowercasePage19[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1171
1172
1173
1174
1175
1176
1177
1178

1179
1180
1181
1182
1183
1184
1185
1171
1172
1173
1174
1175
1176
1177

1178
1179
1180
1181
1182
1183
1184
1185







-
+







	43944, 43945, 43946, 43947, 43948, 43949, 43950, 43951,
	43952, 43953, 43954, 43955, 43956, 43957, 43958, 43959,
	43960, 43961, 43962, 43963, 43964, 43965, 43966, 43967,
	5112, 5113, 5114, 5115, 5116, 5117, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage28[0x100] = {
static const OFUnichar lowercasePage28[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1206
1207
1208
1209
1210
1211
1212
1213

1214
1215
1216
1217
1218
1219
1220
1206
1207
1208
1209
1210
1211
1212

1213
1214
1215
1216
1217
1218
1219
1220







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage30[0x100] = {
static const OFUnichar lowercasePage30[0x100] = {
	7681, 0, 7683, 0, 7685, 0, 7687, 0,
	7689, 0, 7691, 0, 7693, 0, 7695, 0,
	7697, 0, 7699, 0, 7701, 0, 7703, 0,
	7705, 0, 7707, 0, 7709, 0, 7711, 0,
	7713, 0, 7715, 0, 7717, 0, 7719, 0,
	7721, 0, 7723, 0, 7725, 0, 7727, 0,
	7729, 0, 7731, 0, 7733, 0, 7735, 0,
1241
1242
1243
1244
1245
1246
1247
1248

1249
1250
1251
1252
1253
1254
1255
1241
1242
1243
1244
1245
1246
1247

1248
1249
1250
1251
1252
1253
1254
1255







-
+







	7897, 0, 7899, 0, 7901, 0, 7903, 0,
	7905, 0, 7907, 0, 7909, 0, 7911, 0,
	7913, 0, 7915, 0, 7917, 0, 7919, 0,
	7921, 0, 7923, 0, 7925, 0, 7927, 0,
	7929, 0, 7931, 0, 7933, 0, 7935, 0,
};

static const of_unichar_t lowercasePage31[0x100] = {
static const OFUnichar lowercasePage31[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943,
	0, 0, 0, 0, 0, 0, 0, 0,
	7952, 7953, 7954, 7955, 7956, 7957, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975,
	0, 0, 0, 0, 0, 0, 0, 0,
1276
1277
1278
1279
1280
1281
1282
1283

1284
1285
1286
1287
1288
1289
1290
1276
1277
1278
1279
1280
1281
1282

1283
1284
1285
1286
1287
1288
1289
1290







-
+







	8144, 8145, 8054, 8055, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	8160, 8161, 8058, 8059, 8165, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	8056, 8057, 8060, 8061, 8179, 0, 0, 0,
};

static const of_unichar_t lowercasePage33[0x100] = {
static const OFUnichar lowercasePage33[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 969, 0,
	0, 0, 107, 229, 0, 0, 0, 0,
	0, 0, 8526, 0, 0, 0, 0, 0,
1311
1312
1313
1314
1315
1316
1317
1318

1319
1320
1321
1322
1323
1324
1325
1311
1312
1313
1314
1315
1316
1317

1318
1319
1320
1321
1322
1323
1324
1325







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage36[0x100] = {
static const OFUnichar lowercasePage36[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1346
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357
1358
1359
1360
1346
1347
1348
1349
1350
1351
1352

1353
1354
1355
1356
1357
1358
1359
1360







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage44[0x100] = {
static const OFUnichar lowercasePage44[0x100] = {
	11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319,
	11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327,
	11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335,
	11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343,
	11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351,
	11352, 11353, 11354, 11355, 11356, 11357, 11358, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1381
1382
1383
1384
1385
1386
1387
1388

1389
1390
1391
1392
1393
1394
1395
1381
1382
1383
1384
1385
1386
1387

1388
1389
1390
1391
1392
1393
1394
1395







-
+







	11481, 0, 11483, 0, 11485, 0, 11487, 0,
	11489, 0, 11491, 0, 0, 0, 0, 0,
	0, 0, 0, 11500, 0, 11502, 0, 0,
	0, 0, 11507, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage166[0x100] = {
static const OFUnichar lowercasePage166[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1416
1417
1418
1419
1420
1421
1422
1423

1424
1425
1426
1427
1428
1429
1430
1416
1417
1418
1419
1420
1421
1422

1423
1424
1425
1426
1427
1428
1429
1430







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage167[0x100] = {
static const OFUnichar lowercasePage167[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 42787, 0, 42789, 0, 42791, 0,
	42793, 0, 42795, 0, 42797, 0, 42799, 0,
	0, 0, 42803, 0, 42805, 0, 42807, 0,
1451
1452
1453
1454
1455
1456
1457
1458

1459
1460
1461
1462
1463
1464
1465
1451
1452
1453
1454
1455
1456
1457

1458
1459
1460
1461
1462
1463
1464
1465







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 42998, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage255[0x100] = {
static const OFUnichar lowercasePage255[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 65345, 65346, 65347, 65348, 65349, 65350, 65351,
	65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359,
	65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367,
1486
1487
1488
1489
1490
1491
1492
1493

1494
1495
1496
1497
1498
1499
1500
1486
1487
1488
1489
1490
1491
1492

1493
1494
1495
1496
1497
1498
1499
1500







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage260[0x100] = {
static const OFUnichar lowercasePage260[0x100] = {
	66600, 66601, 66602, 66603, 66604, 66605, 66606, 66607,
	66608, 66609, 66610, 66611, 66612, 66613, 66614, 66615,
	66616, 66617, 66618, 66619, 66620, 66621, 66622, 66623,
	66624, 66625, 66626, 66627, 66628, 66629, 66630, 66631,
	66632, 66633, 66634, 66635, 66636, 66637, 66638, 66639,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1521
1522
1523
1524
1525
1526
1527
1528

1529
1530
1531
1532
1533
1534
1535
1521
1522
1523
1524
1525
1526
1527

1528
1529
1530
1531
1532
1533
1534
1535







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage268[0x100] = {
static const OFUnichar lowercasePage268[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1556
1557
1558
1559
1560
1561
1562
1563

1564
1565
1566
1567
1568
1569
1570
1556
1557
1558
1559
1560
1561
1562

1563
1564
1565
1566
1567
1568
1569
1570







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage280[0x100] = {
static const OFUnichar lowercasePage280[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1591
1592
1593
1594
1595
1596
1597
1598

1599
1600
1601
1602
1603
1604
1605
1591
1592
1593
1594
1595
1596
1597

1598
1599
1600
1601
1602
1603
1604
1605







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage366[0x100] = {
static const OFUnichar lowercasePage366[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1626
1627
1628
1629
1630
1631
1632
1633

1634
1635
1636
1637
1638
1639
1640
1626
1627
1628
1629
1630
1631
1632

1633
1634
1635
1636
1637
1638
1639
1640







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t lowercasePage489[0x100] = {
static const OFUnichar lowercasePage489[0x100] = {
	125218, 125219, 125220, 125221, 125222, 125223, 125224, 125225,
	125226, 125227, 125228, 125229, 125230, 125231, 125232, 125233,
	125234, 125235, 125236, 125237, 125238, 125239, 125240, 125241,
	125242, 125243, 125244, 125245, 125246, 125247, 125248, 125249,
	125250, 125251, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1661
1662
1663
1664
1665
1666
1667
1668

1669
1670
1671
1672
1673
1674
1675
1661
1662
1663
1664
1665
1666
1667

1668
1669
1670
1671
1672
1673
1674
1675







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t titlecasePage1[0x100] = {
static const OFUnichar titlecasePage1[0x100] = {
	0, 256, 0, 258, 0, 260, 0, 262,
	0, 264, 0, 266, 0, 268, 0, 270,
	0, 272, 0, 274, 0, 276, 0, 278,
	0, 280, 0, 282, 0, 284, 0, 286,
	0, 288, 0, 290, 0, 292, 0, 294,
	0, 296, 0, 298, 0, 300, 0, 302,
	0, 73, 0, 306, 0, 308, 0, 310,
1696
1697
1698
1699
1700
1701
1702
1703

1704
1705
1706
1707
1708
1709
1710
1696
1697
1698
1699
1700
1701
1702

1703
1704
1705
1706
1707
1708
1709
1710







-
+







	471, 0, 473, 0, 475, 398, 0, 478,
	0, 480, 0, 482, 0, 484, 0, 486,
	0, 488, 0, 490, 0, 492, 0, 494,
	0, 498, 498, 498, 0, 500, 0, 0,
	0, 504, 0, 506, 0, 508, 0, 510,
};

static const of_unichar_t titlecasePage16[0x100] = {
static const OFUnichar titlecasePage16[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1731
1732
1733
1734
1735
1736
1737
1738

1739
1740
1741
1742
1743
1744
1745
1731
1732
1733
1734
1735
1736
1737

1738
1739
1740
1741
1742
1743
1744
1745







-
+







	4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319,
	4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327,
	4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335,
	4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343,
	4344, 4345, 4346, 0, 0, 4349, 4350, 4351,
};

static const of_unichar_t casefoldingPage0[0x100] = {
static const OFUnichar casefoldingPage0[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1766
1767
1768
1769
1770
1771
1772
1773

1774
1775
1776
1777
1778
1779
1780
1766
1767
1768
1769
1770
1771
1772

1773
1774
1775
1776
1777
1778
1779
1780







-
+







	248, 249, 250, 251, 252, 253, 254, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t casefoldingPage1[0x100] = {
static const OFUnichar casefoldingPage1[0x100] = {
	257, 0, 259, 0, 261, 0, 263, 0,
	265, 0, 267, 0, 269, 0, 271, 0,
	273, 0, 275, 0, 277, 0, 279, 0,
	281, 0, 283, 0, 285, 0, 287, 0,
	289, 0, 291, 0, 293, 0, 295, 0,
	297, 0, 299, 0, 301, 0, 303, 0,
	0, 0, 307, 0, 309, 0, 311, 0,
1801
1802
1803
1804
1805
1806
1807
1808

1809
1810
1811
1812
1813
1814
1815
1801
1802
1803
1804
1805
1806
1807

1808
1809
1810
1811
1812
1813
1814
1815







-
+







	0, 474, 0, 476, 0, 0, 479, 0,
	481, 0, 483, 0, 485, 0, 487, 0,
	489, 0, 491, 0, 493, 0, 495, 0,
	0, 499, 499, 0, 501, 0, 405, 447,
	505, 0, 507, 0, 509, 0, 511, 0,
};

static const of_unichar_t casefoldingPage3[0x100] = {
static const OFUnichar casefoldingPage3[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1836
1837
1838
1839
1840
1841
1842
1843

1844
1845
1846
1847
1848
1849
1850
1836
1837
1838
1839
1840
1841
1842

1843
1844
1845
1846
1847
1848
1849
1850







-
+







	985, 0, 987, 0, 989, 0, 991, 0,
	993, 0, 995, 0, 997, 0, 999, 0,
	1001, 0, 1003, 0, 1005, 0, 1007, 0,
	954, 961, 0, 0, 952, 949, 0, 1016,
	0, 1010, 1019, 0, 0, 891, 892, 893,
};

static const of_unichar_t casefoldingPage19[0x100] = {
static const OFUnichar casefoldingPage19[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1871
1872
1873
1874
1875
1876
1877
1878

1879
1880
1881
1882
1883
1884
1885
1871
1872
1873
1874
1875
1876
1877

1878
1879
1880
1881
1882
1883
1884
1885







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	5104, 5105, 5106, 5107, 5108, 5109, 0, 0,
};

static const of_unichar_t casefoldingPage28[0x100] = {
static const OFUnichar casefoldingPage28[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
1906
1907
1908
1909
1910
1911
1912
1913

1914
1915
1916
1917
1918
1919
1920
1906
1907
1908
1909
1910
1911
1912

1913
1914
1915
1916
1917
1918
1919
1920







-
+







	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
};

static const of_unichar_t casefoldingPage30[0x100] = {
static const OFUnichar casefoldingPage30[0x100] = {
	7681, 0, 7683, 0, 7685, 0, 7687, 0,
	7689, 0, 7691, 0, 7693, 0, 7695, 0,
	7697, 0, 7699, 0, 7701, 0, 7703, 0,
	7705, 0, 7707, 0, 7709, 0, 7711, 0,
	7713, 0, 7715, 0, 7717, 0, 7719, 0,
	7721, 0, 7723, 0, 7725, 0, 7727, 0,
	7729, 0, 7731, 0, 7733, 0, 7735, 0,
1941
1942
1943
1944
1945
1946
1947
1948

1949
1950
1951
1952
1953
1954
1955
1941
1942
1943
1944
1945
1946
1947

1948
1949
1950
1951
1952
1953
1954
1955







-
+







	7897, 0, 7899, 0, 7901, 0, 7903, 0,
	7905, 0, 7907, 0, 7909, 0, 7911, 0,
	7913, 0, 7915, 0, 7917, 0, 7919, 0,
	7921, 0, 7923, 0, 7925, 0, 7927, 0,
	7929, 0, 7931, 0, 7933, 0, 7935, 0,
};

static const of_unichar_t casefoldingPage31[0x100] = {
static const OFUnichar casefoldingPage31[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943,
	0, 0, 0, 0, 0, 0, 0, 0,
	7952, 7953, 7954, 7955, 7956, 7957, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975,
	0, 0, 0, 0, 0, 0, 0, 0,
1976
1977
1978
1979
1980
1981
1982
1983

1984
1985
1986
1987
1988
1989
1990
1976
1977
1978
1979
1980
1981
1982

1983
1984
1985
1986
1987
1988
1989
1990







-
+







	8144, 8145, 8054, 8055, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	8160, 8161, 8058, 8059, 8165, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	8056, 8057, 8060, 8061, 8179, 0, 0, 0,
};

static const of_unichar_t casefoldingPage171[0x100] = {
static const OFUnichar casefoldingPage171[0x100] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
12360
12361
12362
12363
12364
12365
12366
12367

12368
12369
12370
12371
12372
12373
12374
12360
12361
12362
12363
12364
12365
12366

12367
12368
12369
12370
12371
12372
12373
12374







-
+







	"\x36", "\x37",
	"\x38", "\x39",
	NULL, NULL,
	NULL, NULL,
	NULL, NULL,
};

const of_unichar_t *const of_unicode_uppercase_table[0x1EA] = {
const OFUnichar *const of_unicode_uppercase_table[0x1EA] = {
	uppercasePage0, uppercasePage1, uppercasePage2, uppercasePage3,
	uppercasePage4, uppercasePage5, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	uppercasePage16, emptyPage, emptyPage, uppercasePage19,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
12486
12487
12488
12489
12490
12491
12492
12493

12494
12495
12496
12497
12498
12499
12500
12486
12487
12488
12489
12490
12491
12492

12493
12494
12495
12496
12497
12498
12499
12500







-
+







	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, uppercasePage489
};

const of_unichar_t *const of_unicode_lowercase_table[0x1EA] = {
const OFUnichar *const of_unicode_lowercase_table[0x1EA] = {
	lowercasePage0, lowercasePage1, lowercasePage2, lowercasePage3,
	lowercasePage4, lowercasePage5, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	lowercasePage16, emptyPage, emptyPage, lowercasePage19,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
12612
12613
12614
12615
12616
12617
12618
12619

12620
12621
12622
12623
12624
12625
12626
12612
12613
12614
12615
12616
12617
12618

12619
12620
12621
12622
12623
12624
12625
12626







-
+







	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, lowercasePage489
};

const of_unichar_t *const of_unicode_titlecase_table[0x1EA] = {
const OFUnichar *const of_unicode_titlecase_table[0x1EA] = {
	uppercasePage0, titlecasePage1, uppercasePage2, uppercasePage3,
	uppercasePage4, uppercasePage5, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	titlecasePage16, emptyPage, emptyPage, uppercasePage19,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
12738
12739
12740
12741
12742
12743
12744
12745

12746
12747
12748
12749
12750
12751
12752
12738
12739
12740
12741
12742
12743
12744

12745
12746
12747
12748
12749
12750
12751
12752







-
+







	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage, emptyPage,
	emptyPage, uppercasePage489
};

const of_unichar_t *const of_unicode_casefolding_table[0x1EA] = {
const OFUnichar *const of_unicode_casefolding_table[0x1EA] = {
	casefoldingPage0, casefoldingPage1, lowercasePage2,
	casefoldingPage3, lowercasePage4, lowercasePage5,
	emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage,
	emptyPage, emptyPage, emptyPage,
	emptyPage, lowercasePage16, emptyPage,
	emptyPage, casefoldingPage19, emptyPage,

Modified tests/OFArrayTests.m from [578f78bc93] to [6905bf8867].

178
179
180
181
182
183
184
185

186
187
188
189
190
191
192
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192







-
+








	TEST(@"-[indexOfObject:]", [a[0] indexOfObject: c_ary[1]] == 1)

	TEST(@"-[indexOfObjectIdenticalTo:]",
	    [a[1] indexOfObjectIdenticalTo: c_ary[1]] == 1)

	TEST(@"-[objectsInRange:]",
	    [[a[0] objectsInRange: of_range(1, 2)] isEqual:
	    [[a[0] objectsInRange: OFMakeRange(1, 2)] isEqual:
	    [arrayClass arrayWithObjects: c_ary[1], c_ary[2], nil]])

	TEST(@"-[replaceObject:withObject:]",
	    R([m[0] replaceObject: c_ary[1] withObject: c_ary[0]]) &&
	    [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] &&
	    [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] &&
	    [[m[0] objectAtIndex: 2] isEqual: c_ary[2]])
211
212
213
214
215
216
217
218

219
220
221
222
223
224
225
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225







-
+








	m[1] = [[a[0] mutableCopy] autorelease];
	TEST(@"-[removeObjectAtIndex:]", R([m[1] removeObjectAtIndex: 1]) &&
	    m[1].count == 2 && [[m[1] objectAtIndex: 1] isEqual: c_ary[2]])

	m[1] = [[a[0] mutableCopy] autorelease];
	TEST(@"-[removeObjectsInRange:]",
	    R([m[1] removeObjectsInRange: of_range(0, 2)]) &&
	    R([m[1] removeObjectsInRange: OFMakeRange(0, 2)]) &&
	    m[1].count == 1 && [[m[1] objectAtIndex: 0] isEqual: c_ary[2]])

	m[1] = [[a[0] mutableCopy] autorelease];
	[m[1] addObject: @"qux"];
	[m[1] addObject: @"last"];
	TEST(@"-[reverse]",
	    R([m[1] reverse]) && [m[1] isEqual: [arrayClass arrayWithObjects:
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
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







-
+








-
+










+
-
-
+
+







	m[1] = [[a[0] mutableCopy] autorelease];
	[m[1] addObject: @"0"];
	[m[1] addObject: @"z"];
	TEST(@"-[sortedArray]",
	    [[m[1] sortedArray] isEqual: [arrayClass arrayWithObjects:
	    @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] &&
	    [[m[1] sortedArrayUsingSelector: @selector(compare:)
				    options: OF_ARRAY_SORT_DESCENDING]
				    options: OFArraySortDescending]
	    isEqual: [arrayClass arrayWithObjects:
	    @"z", @"Foo", @"Baz", @"Bar", @"0", nil]])

	EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]",
	    OFOutOfRangeException, [a[0] objectAtIndex: a[0].count])

	EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]",
	    OFOutOfRangeException, [m[0] removeObjectsInRange:
		of_range(0, m[0].count + 1)])
		OFMakeRange(0, m[0].count + 1)])

	TEST(@"-[componentsJoinedByString:]",
	    (a[1] = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c",
	    nil]) &&
	    [[a[1] componentsJoinedByString: @" "] isEqual: @" a b c"] &&
	    (a[1] = [arrayClass arrayWithObject: @"foo"]) &&
	    [[a[1] componentsJoinedByString: @" "] isEqual: @"foo"])

	TEST(@"-[componentsJoinedByString:options]",
	    (a[1] = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", @"bar",
	    @"", nil]) &&
	    @"", nil]) && [[a[1] componentsJoinedByString: @" "
						  options: OF_ARRAY_SKIP_EMPTY]
	    [[a[1] componentsJoinedByString: @" "
				    options: OFArraySkipEmptyComponents]
	    isEqual: @"foo bar"])

	m[0] = [[a[0] mutableCopy] autorelease];
	ok = true;
	i = 0;

	TEST(@"-[objectEnumerator]", (enumerator = [m[0] objectEnumerator]))

Modified tests/OFCharacterSetTests.m from [7038831ad1] to [ee18bcb821].

23
24
25
26
27
28
29
30

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

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

66
67
68
69
70
71
72
73
74
75
76
77


78
79
80
81

82
83
84
85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
23
24
25
26
27
28
29

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

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

65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81

82
83
84
85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
100







-
+

















-
+
















-
+











-
+
+



-
+










-
+








static OFString *module = nil;

@interface SimpleCharacterSet: OFCharacterSet
@end

@implementation SimpleCharacterSet
- (bool)characterIsMember: (of_unichar_t)character
- (bool)characterIsMember: (OFUnichar)character
{
	return (character % 2 == 0);
}
@end

@implementation TestsAppDelegate (OFCharacterSetTests)
- (void)characterSetTests
{
	void *pool = objc_autoreleasePoolPush();
	OFCharacterSet *cs, *ics;
	bool ok;

	module = @"OFCharacterSet";

	cs = [[[SimpleCharacterSet alloc] init] autorelease];

	ok = true;
	for (of_unichar_t c = 0; c < 65536; c++) {
	for (OFUnichar c = 0; c < 65536; c++) {
		if (c % 2 == 0) {
			if (![cs characterIsMember: c])
				ok = false;
		} else if ([cs characterIsMember: c])
			ok = false;
	}
	TEST(@"-[characterIsMember:]", ok);

	module = @"OFBitSetCharacterSet";

	TEST(@"+[characterSetWithCharactersInString:]",
	    (cs = [OFCharacterSet characterSetWithCharactersInString:
	    @"0123456789"]) &&
	    [cs isKindOfClass: [OFBitSetCharacterSet class]])

	ok = true;
	for (of_unichar_t c = 0; c < 65536; c++) {
	for (OFUnichar c = 0; c < 65536; c++) {
		if (c >= '0' && c <= '9') {
			if (![cs characterIsMember: c])
				ok = false;
		} else if ([cs characterIsMember: c])
			ok = false;
	}
	TEST(@"-[characterIsMember:]", ok);

	module = @"OFRangeCharacterSet";

	TEST(@"+[characterSetWithRange:]",
	    (cs = [OFCharacterSet characterSetWithRange: of_range('0', 10)]) &&
	    (cs = [OFCharacterSet
	    characterSetWithRange: OFMakeRange('0', 10)]) &&
	    [cs isKindOfClass: [OFRangeCharacterSet class]])

	ok = true;
	for (of_unichar_t c = 0; c < 65536; c++) {
	for (OFUnichar c = 0; c < 65536; c++) {
		if (c >= '0' && c <= '9') {
			if (![cs characterIsMember: c])
				ok = false;
		} else if ([cs characterIsMember: c])
			ok = false;
	}
	TEST(@"-[characterIsMember:]", ok);

	ok = true;
	ics = cs.invertedSet;
	for (of_unichar_t c = 0; c < 65536; c++) {
	for (OFUnichar c = 0; c < 65536; c++) {
		if (c >= '0' && c <= '9') {
			if ([ics characterIsMember: c])
				ok = false;
		} else if (![ics characterIsMember: c])
			ok = false;
	}
	TEST(@"-[invertedSet]", ok);

Modified tests/OFDataTests.m from [145ac3ede5] to [c6fec11f60].

25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39







-
+







@implementation TestsAppDelegate (OFDataTests)
- (void)dataTests
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableData *mutable;
	OFData *immutable;
	void *raw[2];
	of_range_t range;
	OFRange range;

	TEST(@"+[dataWithItemSize:]",
	    (mutable = [OFMutableData dataWithItemSize: 4096]))

	raw[0] = of_alloc(1, 4096);
	raw[1] = of_alloc(1, 4096);
	memset(raw[0], 0xFF, 4096);
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
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







-
-
+
+

-
+









-
+














-
+






-
-
+
+







-
+






-
-
+
+








-
+





-
-
+
+










-
+








-
+


-
+



-
+




-
+
+


-
+
+








	TEST(@"-[mutableCopy]",
	    (mutable = [[immutable mutableCopy] autorelease]) &&
	    [mutable isEqual: immutable])

	TEST(@"-[compare]", [mutable compare: immutable] == 0 &&
	    R([mutable removeLastItem]) &&
	    [immutable compare: mutable] == OF_ORDERED_DESCENDING &&
	    [mutable compare: immutable] == OF_ORDERED_ASCENDING &&
	    [immutable compare: mutable] == OFOrderedDescending &&
	    [mutable compare: immutable] == OFOrderedAscending &&
	    [[OFData dataWithItems: "aa" count: 2] compare:
	    [OFData dataWithItems: "z" count: 1]] == OF_ORDERED_ASCENDING)
	    [OFData dataWithItems: "z" count: 1]] == OFOrderedAscending)

	TEST(@"-[hash]", immutable.hash == 0x634A529F)

	mutable = [OFMutableData dataWithItems: "abcdef" count: 6];

	TEST(@"-[removeLastItem]", R([mutable removeLastItem]) &&
	    mutable.count == 5 && memcmp(mutable.items, "abcde", 5) == 0)

	TEST(@"-[removeItemsInRange:]",
	    R([mutable removeItemsInRange: of_range(1, 2)]) &&
	    R([mutable removeItemsInRange: OFMakeRange(1, 2)]) &&
	    mutable.count == 3 && memcmp(mutable.items, "ade", 3) == 0)

	TEST(@"-[insertItems:atIndex:count:]",
	    R([mutable insertItems: "bc" atIndex: 1 count: 2]) &&
	    mutable.count == 5 && memcmp(mutable.items, "abcde", 5) == 0)

	immutable = [OFData dataWithItems: "aaabaccdacaabb"
				    count: 7
				 itemSize: 2];

	range = [immutable rangeOfData: [OFData dataWithItems: "aa"
							count: 1
						     itemSize: 2]
			       options: 0
				 range: of_range(0, 7)];
				 range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #1",
	    range.location == 0 && range.length == 1)

	range = [immutable rangeOfData: [OFData dataWithItems: "aa"
							count: 1
						     itemSize: 2]
			       options: OF_DATA_SEARCH_BACKWARDS
				 range: of_range(0, 7)];
			       options: OFDataSearchBackwards
				 range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #2",
	    range.location == 5 && range.length == 1)

	range = [immutable rangeOfData: [OFData dataWithItems: "ac"
							count: 1
						     itemSize: 2]
			       options: 0
				 range: of_range(0, 7)];
				 range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #3",
	    range.location == 2 && range.length == 1)

	range = [immutable rangeOfData: [OFData dataWithItems: "aabb"
							count: 2
						     itemSize: 2]
						      options: 0
							range: of_range(0, 7)];
			       options: 0
				 range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #4",
	    range.location == 5 && range.length == 2)

	TEST(@"-[rangeOfData:options:range:] #5",
	    R(range = [immutable rangeOfData: [OFData dataWithItems: "aa"
							      count: 1
							   itemSize: 2]
				     options: 0
				       range: of_range(1, 6)]) &&
				       range: OFMakeRange(1, 6)]) &&
	    range.location == 5 && range.length == 1)

	range = [immutable rangeOfData: [OFData dataWithItems: "aa"
							count: 1
						     itemSize: 2]
			       options: OF_DATA_SEARCH_BACKWARDS
				 range: of_range(0, 5)];
			       options: OFDataSearchBackwards
				 range: OFMakeRange(0, 5)];
	TEST(@"-[rangeOfData:options:range:] #6",
	    range.location == 0 && range.length == 1)

	EXPECT_EXCEPTION(
	    @"-[rangeOfData:options:range:] failing on different itemSize",
	    OFInvalidArgumentException,
	    [immutable rangeOfData: [OFData dataWithItems: "aaa"
						    count: 1
						 itemSize: 3]
			   options: 0
			     range: of_range(0, 1)])
			     range: OFMakeRange(0, 1)])

	EXPECT_EXCEPTION(
	    @"-[rangeOfData:options:range:] failing on out of range",
	    OFOutOfRangeException,
	    [immutable rangeOfData: [OFData dataWithItems: ""
						    count: 0
						 itemSize: 2]
			   options: 0
			     range: of_range(8, 1)])
			     range: OFMakeRange(8, 1)])

	TEST(@"-[subdataWithRange:]",
	    [[immutable subdataWithRange: of_range(2, 4)]
	    [[immutable subdataWithRange: OFMakeRange(2, 4)]
	    isEqual: [OFData dataWithItems: "accdacaa"
				     count: 4
				  itemSize: 2]] &&
	    [[mutable subdataWithRange: of_range(2, 3)]
	    [[mutable subdataWithRange: OFMakeRange(2, 3)]
	    isEqual: [OFData dataWithItems: "cde"
				     count: 3]])

	EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #1",
	    OFOutOfRangeException, [immutable subdataWithRange: of_range(7, 1)])
	    OFOutOfRangeException,
	    [immutable subdataWithRange: OFMakeRange(7, 1)])

	EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #2",
	    OFOutOfRangeException, [mutable subdataWithRange: of_range(6, 1)])
	    OFOutOfRangeException,
	    [mutable subdataWithRange: OFMakeRange(6, 1)])

	TEST(@"-[stringByMD5Hashing]", [mutable.stringByMD5Hashing
	    isEqual: @"ab56b4d92b40713acc5af89985d4b786"])

	TEST(@"-[stringByRIPEMD160Hashing]", [mutable.stringByRIPEMD160Hashing
	    isEqual: @"973398b6e6c6cfa6b5e6a5173f195ce3274bf828"])

210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
212
213
214
215
216
217
218

219
220
221
222
223
224
225
226







-
+







	    OFOutOfRangeException, [mutable itemAtIndex: mutable.count])

	EXPECT_EXCEPTION(@"Detect out of range in -[addItems:count:]",
	    OFOutOfRangeException, [mutable addItems: raw[0] count: SIZE_MAX])

	EXPECT_EXCEPTION(@"Detect out of range in -[removeItemsInRange:]",
	    OFOutOfRangeException,
	    [mutable removeItemsInRange: of_range(mutable.count, 1)])
	    [mutable removeItemsInRange: OFMakeRange(mutable.count, 1)])

	free(raw[0]);
	free(raw[1]);

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFDateTests.m from [02539a3684] to [dca21ab5a6].

76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90







-
+







	    [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56+0200x"
				     format: @"%Y-%m-%dT%H:%M:%S%z"])

	TEST(@"-[isEqual:]",
	    [d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] &&
	    ![d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]])

	TEST(@"-[compare:]", [d1 compare: d2] == OF_ORDERED_ASCENDING)
	TEST(@"-[compare:]", [d1 compare: d2] == OFOrderedAscending)

	TEST(@"-[second]", d1.second == 0 && d2.second == 5)

	TEST(@"-[microsecond]", d1.microsecond == 0 && d2.microsecond == 2)

	TEST(@"-[minute]", d1.minute == 0 && d2.minute == 0)

Modified tests/OFDictionaryTests.m from [daa54d882b] to [fdcd71652e].

136
137
138
139
140
141
142
143

144
145
146
147
148
149
150
136
137
138
139
140
141
142

143
144
145
146
147
148
149
150







-
+








	[_dictionary removeObjectForKey: key];

	if (existed)
		_mutations++;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	int ret = [super countByEnumeratingWithState: state
					     objects: objects
					       count: count];

Modified tests/OFINIFileTests.m from [4cccd0237d] to [0d85330d49].

48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62







-
+







	OFArray *array;
#ifndef OF_NINTENDO_DS
	OFString *writePath;
#endif

	TEST(@"+[fileWithPath:encoding:]",
	    (file = [OFINIFile fileWithPath: @"testfile.ini"
				   encoding: OF_STRING_ENCODING_CODEPAGE_437]))
				   encoding: OFStringEncodingCodepage437]))

	tests = [file categoryForName: @"tests"];
	foobar = [file categoryForName: @"foobar"];
	types = [file categoryForName: @"types"];
	TEST(@"-[categoryForName:]",
	    tests != nil && foobar != nil && types != nil)

117
118
119
120
121
122
123
124

125
126
127

128
129
130
131
132
133
134
135
136
117
118
119
120
121
122
123

124
125
126

127
128
129
130
131
132
133
134
135
136







-
+


-
+









# else
	writePath = [OFString pathWithComponents: [OFArray arrayWithObjects:
	    [[OFApplication environment] objectForKey: @"HOME"],
	    @"tmp", @"tmpfile.ini", nil]];
# endif
	TEST(@"-[writeToFile:encoding:]",
	    R([file writeToFile: writePath
		       encoding: OF_STRING_ENCODING_CODEPAGE_437]) &&
		       encoding: OFStringEncodingCodepage437]) &&
	    [[OFString
		stringWithContentsOfFile: writePath
				encoding: OF_STRING_ENCODING_CODEPAGE_437]
				encoding: OFStringEncodingCodepage437]
	    isEqual: output])
	[[OFFileManager defaultManager] removeItemAtPath: writePath];
#else
	(void)output;
#endif

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFIPXSocketTests.m from [5b53a7c15d] to [2def7aa281].

22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
22
23
24
25
26
27
28

29
30
31
32
33
34
35
36







-
+







static OFString *module = @"OFIPXSocket";

@implementation TestsAppDelegate (OFIPXSocketTests)
- (void)IPXSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFIPXSocket *sock;
	of_socket_address_t address1, address2;
	OFSocketAddress address1, address2;
	char buffer[5];

	TEST(@"+[socket]", (sock = [OFIPXSocket socket]))

	@try {
		TEST(@"-[bindToPort:packetType:]",
		    R(address1 = [sock bindToPort: 0 packetType: 0]))
58
59
60
61
62
63
64
65
66


67
68
69
70
71
58
59
60
61
62
63
64


65
66

67
68
69
70







-
-
+
+
-





	TEST(@"-[sendBuffer:length:receiver:]",
	    R([sock sendBuffer: "Hello" length: 5 receiver: &address1]))

	TEST(@"-[receiveIntoBuffer:length:sender:]",
	    [sock receiveIntoBuffer: buffer length: 5 sender: &address2] == 5 &&
	    memcmp(buffer, "Hello", 5) == 0 &&
	    of_socket_address_equal(&address1, &address2) &&
	    of_socket_address_hash(&address1) ==
	    OFSocketAddressEqual(&address1, &address2) &&
	    OFSocketAddressHash(&address1) == OFSocketAddressHash(&address2))
	    of_socket_address_hash(&address2))

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFListTests.m from [6f825fa0b7] to [045f6f7c6a].

26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41
42
43
44


45
46
47


48
49
50


51
52
53


54
55
56
57
58
59





60
61
62


63
64

65
66

67
68
69


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85



86
87
88
89
90
91
92
93
94

95
96
97
98

99
100
101

102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117

118
119
120
121
122

123
124
125

126
127
128
129
130
131
132
133
134
135
136
137
138
139

140
141
142
143
144
145
146
147
148
149
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42


43
44
45


46
47
48


49
50
51


52
53
54





55
56
57
58
59
60


61
62


63
64

65
66


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



82
83
84
85
86
87
88
89
90
91
92

93
94
95
96

97
98
99

100
101
102
103
104
105
106
107
108

109
110
111
112
113
114
115

116
117
118
119
120

121
122
123

124
125
126
127
128
129
130
131
132
133
134
135
136
137

138
139
140
141
142
143
144
145
146
147
148







-
+









-
-
+
+

-
-
+
+

-
-
+
+

-
-
+
+

-
-
-
-
-
+
+
+
+
+

-
-
+
+
-
-
+

-
+

-
-
+
+













-
-
-
+
+
+








-
+



-
+


-
+








-
+






-
+




-
+


-
+













-
+











@implementation TestsAppDelegate (OFListTests)
- (void)listTests
{
	void *pool = objc_autoreleasePoolPush();
	OFList *list;
	OFEnumerator *enumerator;
	of_list_object_t *loe;
	OFListItem *iter;
	OFString *obj;
	size_t i;
	bool ok;

	TEST(@"+[list]", (list = [OFList list]))

	TEST(@"-[appendObject:]", [list appendObject: strings[0]] &&
	    [list appendObject: strings[1]] && [list appendObject: strings[2]])

	TEST(@"-[firstListObject]",
	    [list.firstListObject->object isEqual: strings[0]])
	TEST(@"-[firstListItem]",
	    [list.firstListItem->object isEqual: strings[0]])

	TEST(@"-[firstListObject]->next",
	    [list.firstListObject->next->object isEqual: strings[1]])
	TEST(@"-[firstListItem]->next",
	    [list.firstListItem->next->object isEqual: strings[1]])

	TEST(@"-[lastListObject]",
	    [list.lastListObject->object isEqual: strings[2]])
	TEST(@"-[lastListItem]",
	    [list.lastListItem->object isEqual: strings[2]])

	TEST(@"-[lastListObject]->previous",
	    [list.lastListObject->previous->object isEqual: strings[1]])
	TEST(@"-[lastListItem]->previous",
	    [list.lastListItem->previous->object isEqual: strings[1]])

	TEST(@"-[removeListObject:]",
	    R([list removeListObject: list.lastListObject]) &&
	    [list.lastListObject->object isEqual: strings[1]] &&
	    R([list removeListObject: list.firstListObject]) &&
	    [list.firstListObject->object isEqual: list.lastListObject->object])
	TEST(@"-[removeListItem:]",
	    R([list removeListItem: list.lastListItem]) &&
	    [list.lastListItem->object isEqual: strings[1]] &&
	    R([list removeListItem: list.firstListItem]) &&
	    [list.firstListItem->object isEqual: list.lastListItem->object])

	TEST(@"-[insertObject:beforeListObject:]",
	    [list insertObject: strings[0]
	TEST(@"-[insertObject:beforeListItem:]",
	    [list insertObject: strings[0] beforeListItem: list.lastListItem] &&
	      beforeListObject: list.lastListObject] &&
	    [list.lastListObject->previous->object isEqual: strings[0]])
	    [list.lastListItem->previous->object isEqual: strings[0]])

	TEST(@"-[insertObject:afterListObject:]",
	TEST(@"-[insertObject:afterListItem:]",
	    [list insertObject: strings[2]
	       afterListObject: list.firstListObject->next] &&
	    [list.lastListObject->object isEqual: strings[2]])
		 afterListItem: list.firstListItem->next] &&
	    [list.lastListItem->object isEqual: strings[2]])

	TEST(@"-[count]", list.count == 3)

	TEST(@"-[containsObject:]",
	    [list containsObject: strings[1]] &&
	    ![list containsObject: @"nonexistent"])

	TEST(@"-[containsObjectIdenticalTo:]",
	    [list containsObjectIdenticalTo: strings[1]] &&
	    ![list containsObjectIdenticalTo:
	    [OFString stringWithString: strings[1]]])

	TEST(@"-[copy]", (list = [[list copy] autorelease]) &&
	    [list.firstListObject->object isEqual: strings[0]] &&
	    [list.firstListObject->next->object isEqual: strings[1]] &&
	    [list.lastListObject->object isEqual: strings[2]])
	    [list.firstListItem->object isEqual: strings[0]] &&
	    [list.firstListItem->next->object isEqual: strings[1]] &&
	    [list.lastListItem->object isEqual: strings[2]])

	TEST(@"-[isEqual:]", [list isEqual: [[list copy] autorelease]])

	TEST(@"-[description]",
	    [list.description isEqual: @"[\n\tFoo,\n\tBar,\n\tBaz\n]"])

	TEST(@"-[objectEnumerator]", (enumerator = [list objectEnumerator]))

	loe = list.firstListObject;
	iter = list.firstListItem;
	i = 0;
	ok = true;
	while ((obj = [enumerator nextObject]) != nil) {
		if (![obj isEqual: loe->object])
		if (![obj isEqual: iter->object])
			ok = false;

		loe = loe->next;
		iter = iter->next;
		i++;
	}

	if (list.count != i)
		ok = false;

	TEST(@"OFEnumerator's -[nextObject]", ok);

	[list removeListObject: list.firstListObject];
	[list removeListItem: list.firstListItem];

	EXPECT_EXCEPTION(@"Detection of mutation during enumeration",
	    OFEnumerationMutationException, [enumerator nextObject])

	[list prependObject: strings[0]];

	loe = list.firstListObject;
	iter = list.firstListItem;
	i = 0;
	ok = true;

	for (OFString *object in list) {
		if (![object isEqual: loe->object])
		if (![object isEqual: iter->object])
			ok = false;

		loe = loe->next;
		iter = iter->next;
		i++;
	}

	if (list.count != i)
		ok = false;

	TEST(@"Fast Enumeration", ok)

	ok = false;
	@try {
		for (OFString *object in list) {
			(void)object;

			[list removeListObject: list.lastListObject];
			[list removeListItem: list.lastListItem];
		}
	} @catch (OFEnumerationMutationException *e) {
		ok = true;
	}

	TEST(@"Detection of mutation during Fast Enumeration", ok)

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFLocaleTests.m from [2b5c756cd6] to [958923ab2a].

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







-
+







	[of_stdout writeFormat: @"[OFLocale] Language: %@\n",
	    [OFLocale language]];

	[of_stdout writeFormat: @"[OFLocale] Territory: %@\n",
	    [OFLocale territory]];

	[of_stdout writeFormat: @"[OFLocale] Encoding: %@\n",
	    of_string_name_of_encoding([OFLocale encoding])];
	    OFStringEncodingName([OFLocale encoding])];

	[of_stdout writeFormat: @"[OFLocale] Decimal point: %@\n",
	    [OFLocale decimalPoint]];

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFSPXSocketTests.m from [b491e5d645] to [2f37ba742a].

69
70
71
72
73
74
75
76
77


78
79
80
81
82
83
84
69
70
71
72
73
74
75


76
77
78
79
80
81
82
83
84







-
-
+
+







@end

@implementation TestsAppDelegate (OFSPXSocketTests)
- (void)SPXSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFSPXSocket *sockClient, *sockServer, *sockAccepted;;
	of_socket_address_t address1;
	const of_socket_address_t *address2;
	OFSocketAddress address1;
	const OFSocketAddress *address2;
	unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	uint32_t network;
	uint16_t port;
	char buffer[5];
	SPXSocketDelegate *delegate;

	TEST(@"+[socket]", (sockClient = [OFSPXSocket socket]) &&
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
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







-
-
-
+
+
+

















-
+

-
+















-
+


-
-
+
+







			@throw e;
		}

		objc_autoreleasePoolPop(pool);
		return;
	}

	of_socket_address_get_ipx_node(&address1, node);
	network = of_socket_address_get_ipx_network(&address1);
	port = of_socket_address_get_port(&address1);
	OFSocketAddressIPXNode(&address1, node);
	network = OFSocketAddressIPXNetwork(&address1);
	port = OFSocketAddressPort(&address1);

	TEST(@"-[listen]", R([sockServer listen]))

	TEST(@"-[connectToNode:network:port:]",
	    R([sockClient connectToNode: node network: network port: port]))

	TEST(@"-[accept]", (sockAccepted = [sockServer accept]))

	TEST(@"-[sendBuffer:length:]",
	    R([sockAccepted sendBuffer: "Hello" length: 5]))

	TEST(@"-[receiveIntoBuffer:length:]",
	    [sockClient receiveIntoBuffer: buffer length: 5] == 5 &&
	    memcmp(buffer, "Hello", 5) == 0)

	TEST(@"-[remoteAddress]",
	    (address2 = sockAccepted.remoteAddress) &&
	    R(of_socket_address_get_ipx_node(address2, node2)) &&
	    R(OFSocketAddressIPXNode(address2, node2)) &&
	    memcmp(node, node2, IPX_NODE_LEN) == 0 &&
	    of_socket_address_get_ipx_network(address2) == network)
	    OFSocketAddressIPXNetwork(address2) == network)

	delegate = [[[SPXSocketDelegate alloc] init] autorelease];

	sockServer = [OFSPXSocket socket];
	delegate->_expectedServerSocket = sockServer;
	sockServer.delegate = delegate;

	sockClient = [OFSPXSocket socket];
	delegate->_expectedClientSocket = sockClient;
	sockClient.delegate = delegate;

	address1 = [sockServer bindToPort: 0];
	[sockServer listen];
	[sockServer asyncAccept];

	of_socket_address_get_ipx_node(&address1, node);
	OFSocketAddressIPXNode(&address1, node);
	memcpy(delegate->_expectedNode, node, IPX_NODE_LEN);
	delegate->_expectedNetwork = network =
	    of_socket_address_get_ipx_network(&address1);
	delegate->_expectedPort = port = of_socket_address_get_port(&address1);
	    OFSocketAddressIPXNetwork(&address1);
	delegate->_expectedPort = port = OFSocketAddressPort(&address1);

	@try {
		[sockClient asyncConnectToNode: node
				       network: network
					  port: port];

		[[OFRunLoop mainRunLoop] runUntilDate:

Modified tests/OFSPXStreamSocketTests.m from [3affd4c53c] to [f71b3b4551].

69
70
71
72
73
74
75
76
77


78
79
80
81
82
83
84
69
70
71
72
73
74
75


76
77
78
79
80
81
82
83
84







-
-
+
+







@end

@implementation TestsAppDelegate (OFSPXStreamSocketTests)
- (void)SPXStreamSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFSPXStreamSocket *sockClient, *sockServer, *sockAccepted;;
	of_socket_address_t address1;
	const of_socket_address_t *address2;
	OFSocketAddress address1;
	const OFSocketAddress *address2;
	unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	uint32_t network;
	uint16_t port;
	char buffer[5];
	SPXStreamSocketDelegate *delegate;

	TEST(@"+[socket]", (sockClient = [OFSPXStreamSocket socket]) &&
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
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







-
-
-
+
+
+




















-
+

-
+















-
+


-
-
+
+







			@throw e;
		}

		objc_autoreleasePoolPop(pool);
		return;
	}

	of_socket_address_get_ipx_node(&address1, node);
	network = of_socket_address_get_ipx_network(&address1);
	port = of_socket_address_get_port(&address1);
	OFSocketAddressIPXNode(&address1, node);
	network = OFSocketAddressIPXNetwork(&address1);
	port = OFSocketAddressPort(&address1);

	TEST(@"-[listen]", R([sockServer listen]))

	TEST(@"-[connectToNode:network:port:]",
	    R([sockClient connectToNode: node network: network port: port]))

	TEST(@"-[accept]", (sockAccepted = [sockServer accept]))

	/* Test reassembly (this would not work with OFSPXSocket) */
	TEST(@"-[writeBuffer:length:]",
	    R([sockAccepted writeBuffer: "Hello" length: 5]))

	TEST(@"-[readIntoBuffer:length:]",
	    [sockClient readIntoBuffer: buffer length: 2] == 2 &&
	    memcmp(buffer, "He", 2) == 0 &&
	    [sockClient readIntoBuffer: buffer length: 3] == 3 &&
	    memcmp(buffer, "llo", 3) == 0)

	TEST(@"-[remoteAddress]",
	    (address2 = sockAccepted.remoteAddress) &&
	    R(of_socket_address_get_ipx_node(address2, node2)) &&
	    R(OFSocketAddressIPXNode(address2, node2)) &&
	    memcmp(node, node2, IPX_NODE_LEN) == 0 &&
	    of_socket_address_get_ipx_network(address2) == network)
	    OFSocketAddressIPXNetwork(address2) == network)

	delegate = [[[SPXStreamSocketDelegate alloc] init] autorelease];

	sockServer = [OFSPXStreamSocket socket];
	delegate->_expectedServerSocket = sockServer;
	sockServer.delegate = delegate;

	sockClient = [OFSPXStreamSocket socket];
	delegate->_expectedClientSocket = sockClient;
	sockClient.delegate = delegate;

	address1 = [sockServer bindToPort: 0];
	[sockServer listen];
	[sockServer asyncAccept];

	of_socket_address_get_ipx_node(&address1, node);
	OFSocketAddressIPXNode(&address1, node);
	memcpy(delegate->_expectedNode, node, IPX_NODE_LEN);
	delegate->_expectedNetwork = network =
	    of_socket_address_get_ipx_network(&address1);
	delegate->_expectedPort = port = of_socket_address_get_port(&address1);
	    OFSocketAddressIPXNetwork(&address1);
	delegate->_expectedPort = port = OFSocketAddressPort(&address1);

	@try {
		[sockClient asyncConnectToNode: node
				       network: network
					  port: port];

		[[OFRunLoop mainRunLoop] runUntilDate:

Modified tests/OFSetTests.m from [297b7fe674] to [04cbdfa860].

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







-
+








	[_set removeObject: object];

	if (existed)
		_mutations++;
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state
- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	int ret = [_set countByEnumeratingWithState: state
					    objects: objects
					      count: count];

Modified tests/OFStringTests.m from [bc3d5b4b0a] to [4dd338b89d].

30
31
32
33
34
35
36
37

38
39
40

41
42
43
44
45
46
47
30
31
32
33
34
35
36

37
38
39

40
41
42
43
44
45
46
47







-
+


-
+







#endif

static OFString *module = nil;
static OFString *whitespace[] = {
	@" \r \t\n\t \tasd  \t \t\t\r\n",
	@" \t\t  \t\t  \t \t"
};
static of_unichar_t ucstr[] = {
static OFUnichar ucstr[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A, 0
};
static of_unichar_t sucstr[] = {
static OFUnichar sucstr[] = {
	0xFFFE0000, 0x66000000, 0xF6000000, 0xF6000000, 0x62000000, 0xE4000000,
	0x72000000, 0x3AF00100, 0
};
static uint16_t utf16str[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0xD83C, 0xDC3A, 0
};
static uint16_t sutf16str[] = {
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
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







-
+
















-
+

-
+
















-
+

-
+







		@throw e;
	}

	return self;
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (of_string_encoding_t)encoding
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)length
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc] initWithCString: cString
							  encoding: encoding
							    length: length];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithUTF16String: (const of_char16_t *)UTF16String
- (instancetype)initWithUTF16String: (const OFChar16 *)UTF16String
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc]
		    initWithUTF16String: UTF16String
				 length: length
			      byteOrder: byteOrder];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithUTF32String: (const of_char32_t *)UTF32String
- (instancetype)initWithUTF32String: (const OFChar32 *)UTF32String
			     length: (size_t)length
			  byteOrder: (of_byte_order_t)byteOrder
			  byteOrder: (OFByteOrder)byteOrder
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc]
		    initWithUTF32String: UTF32String
				 length: length
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
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







-
+

















-
+







- (void)dealloc
{
	[_string release];

	[super dealloc];
}

- (of_unichar_t)characterAtIndex: (size_t)idx
- (OFUnichar)characterAtIndex: (size_t)idx
{
	return [_string characterAtIndex: idx];
}

- (size_t)length
{
	return _string.length;
}
@end

@implementation SimpleMutableString
+ (void)initialize
{
	if (self == [SimpleMutableString class])
		[self inheritMethodsFromClass: [SimpleString class]];
}

- (void)replaceCharactersInRange: (of_range_t)range
- (void)replaceCharactersInRange: (OFRange)range
		      withString: (OFString *)string
{
	[_string replaceCharactersInRange: range withString: string];
}
@end

@interface EntityHandler: OFObject <OFStringXMLUnescapingDelegate>
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
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







-
+

















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



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





-
-
+
+







		mutableClass: (Class)mutableStringClass
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableString *s[3];
	OFString *is;
	OFArray *a;
	size_t i;
	const of_unichar_t *ua;
	const OFUnichar *ua;
	const uint16_t *u16a;
	OFCharacterSet *cs;
	EntityHandler *h;
#ifdef OF_HAVE_BLOCKS
	__block int j;
	__block bool ok;
#endif

#define C(s) ((OFString *)[stringClass stringWithString: s])

	s[0] = [mutableStringClass stringWithString: @"täs€"];
	s[1] = [mutableStringClass string];
	s[2] = [[s[0] copy] autorelease];

	TEST(@"-[isEqual:]", [s[0] isEqual: s[2]] &&
	    ![s[0] isEqual: [[[OFObject alloc] init] autorelease]])

	TEST(@"-[compare:]", [s[0] compare: s[2]] == OF_ORDERED_SAME &&
	    [s[0] compare: @""] != OF_ORDERED_SAME &&
	    [C(@"") compare: @"a"] == OF_ORDERED_ASCENDING &&
	    [C(@"a") compare: @"b"] == OF_ORDERED_ASCENDING &&
	    [C(@"cd") compare: @"bc"] == OF_ORDERED_DESCENDING &&
	    [C(@"ä") compare: @"ö"] == OF_ORDERED_ASCENDING &&
	    [C(@"€") compare: @"ß"] == OF_ORDERED_DESCENDING &&
	    [C(@"aa") compare: @"z"] == OF_ORDERED_ASCENDING)
	TEST(@"-[compare:]", [s[0] compare: s[2]] == OFOrderedSame &&
	    [s[0] compare: @""] != OFOrderedSame &&
	    [C(@"") compare: @"a"] == OFOrderedAscending &&
	    [C(@"a") compare: @"b"] == OFOrderedAscending &&
	    [C(@"cd") compare: @"bc"] == OFOrderedDescending &&
	    [C(@"ä") compare: @"ö"] == OFOrderedAscending &&
	    [C(@"€") compare: @"ß"] == OFOrderedDescending &&
	    [C(@"aa") compare: @"z"] == OFOrderedAscending)

#ifdef OF_HAVE_UNICODE_TABLES
	TEST(@"-[caseInsensitiveCompare:]",
	    [C(@"a") caseInsensitiveCompare: @"A"] == OF_ORDERED_SAME &&
	    [C(@"Ä") caseInsensitiveCompare: @"ä"] == OF_ORDERED_SAME &&
	    [C(@"я") caseInsensitiveCompare: @"Я"] == OF_ORDERED_SAME &&
	    [C(@"€") caseInsensitiveCompare: @"ß"] == OF_ORDERED_DESCENDING &&
	    [C(@"ß") caseInsensitiveCompare: @"→"] == OF_ORDERED_ASCENDING &&
	    [C(@"AA") caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING &&
	    [C(@"a") caseInsensitiveCompare: @"A"] == OFOrderedSame &&
	    [C(@"Ä") caseInsensitiveCompare: @"ä"] == OFOrderedSame &&
	    [C(@"я") caseInsensitiveCompare: @"Я"] == OFOrderedSame &&
	    [C(@"€") caseInsensitiveCompare: @"ß"] == OFOrderedDescending &&
	    [C(@"ß") caseInsensitiveCompare: @"→"] == OFOrderedAscending &&
	    [C(@"AA") caseInsensitiveCompare: @"z"] == OFOrderedAscending &&
	    [[stringClass stringWithUTF8String: "ABC"] caseInsensitiveCompare:
	    [stringClass stringWithUTF8String: "AbD"]] ==
	    [C(@"abc") compare: @"abd"])
#else
	TEST(@"-[caseInsensitiveCompare:]",
	    [C(@"a") caseInsensitiveCompare: @"A"] == OF_ORDERED_SAME &&
	    [C(@"AA") caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING &&
	    [C(@"a") caseInsensitiveCompare: @"A"] == OFOrderedSame &&
	    [C(@"AA") caseInsensitiveCompare: @"z"] == OFOrderedAscending &&
	    [[stringClass stringWithUTF8String: "ABC"] caseInsensitiveCompare:
	    [stringClass stringWithUTF8String: "AbD"]] ==
	    [C(@"abc") compare: @"abd"])
#endif

	TEST(@"-[hash] is the same if -[isEqual:] is true",
	    s[0].hash == s[2].hash)
346
347
348
349
350
351
352
353

354
355
356
357
358

359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381

382
383
384
385
386
387
388
389
390
391

392
393
394
395
396
397
398

399
400
401
402
403
404

405
406
407
408
409

410
411
412
413

414
415
416
417
418

419
420
421
422
423

424
425
426
427
428

429
430
431
432
433
434

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
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
346
347
348
349
350
351
352

353
354
355
356
357

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374

375
376
377
378
379
380

381
382
383
384
385
386
387
388
389
390

391
392
393
394
395
396
397

398
399
400
401
402
403

404
405
406
407
408

409
410
411
412

413
414
415
416
417

418
419
420
421
422

423
424
425
426
427

428
429
430
431
432
433

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







-
+




-
+
















-
+





-
+









-
+






-
+





-
+




-
+



-
+




-
+




-
+




-
+





-
+



-
+





-
+



-
+




-
+



-
+




-
+





-
+





-
+















-
+

-
+

-
+

-
+

-
+




-
+






-
+



-
+



-
+






-
+


-
-
+
+



-
+


-
+







	    [is isEqual: @"fööbär🀺"] &&
	    (is = [stringClass stringWithUTF32String: sucstr]) &&
	    [is isEqual: @"fööbär🀺"])

#ifdef OF_HAVE_FILES
	TEST(@"+[stringWithContentsOfFile:encoding]", (is = [stringClass
	    stringWithContentsOfFile: @"testfile.txt"
			    encoding: OF_STRING_ENCODING_ISO_8859_1]) &&
			    encoding: OFStringEncodingISO8859_1]) &&
	    [is isEqual: @"testäöü"])

	TEST(@"+[stringWithContentsOfURL:encoding]", (is = [stringClass
	    stringWithContentsOfURL: [OFURL fileURLWithPath: @"testfile.txt"]
			   encoding: OF_STRING_ENCODING_ISO_8859_1]) &&
			   encoding: OFStringEncodingISO8859_1]) &&
	    [is isEqual: @"testäöü"])
#endif

	TEST(@"-[appendUTFString:length:]",
	    R([s[0] appendUTF8String: "\xEF\xBB\xBF" "barqux" length: 6]) &&
	    [s[0] isEqual: @"foobar"])

	EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #1",
	    OFInvalidEncodingException,
	    [stringClass stringWithUTF8String: "\xE0\x80"])
	EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #2",
	    OFInvalidEncodingException,
	    [stringClass stringWithUTF8String: "\xF0\x80\x80\xC0"])

	TEST(@"Conversion of ISO 8859-1 to Unicode",
	    [[stringClass stringWithCString: "\xE4\xF6\xFC"
				   encoding: OF_STRING_ENCODING_ISO_8859_1]
				   encoding: OFStringEncodingISO8859_1]
	    isEqual: @"äöü"])

#ifdef HAVE_ISO_8859_15
	TEST(@"Conversion of ISO 8859-15 to Unicode",
	    [[stringClass stringWithCString: "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE"
				   encoding: OF_STRING_ENCODING_ISO_8859_15]
				   encoding: OFStringEncodingISO8859_15]
	    isEqual: @"€ŠšŽžŒœŸ"])
#endif

#ifdef HAVE_WINDOWS_1252
	TEST(@"Conversion of Windows 1252 to Unicode",
	    [[stringClass stringWithCString: "\x80\x82\x83\x84\x85\x86\x87\x88"
					     "\x89\x8A\x8B\x8C\x8E\x91\x92\x93"
					     "\x94\x95\x96\x97\x98\x99\x9A\x9B"
					     "\x9C\x9E\x9F"
				   encoding: OF_STRING_ENCODING_WINDOWS_1252]
				   encoding: OFStringEncodingWindows1252]
	    isEqual: @"€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"])
#endif

#ifdef HAVE_CODEPAGE_437
	TEST(@"Conversion of Codepage 437 to Unicode",
	    [[stringClass stringWithCString: "\xB0\xB1\xB2\xDB"
				   encoding: OF_STRING_ENCODING_CODEPAGE_437]
				   encoding: OFStringEncodingCodepage437]
	    isEqual: @"░▒▓█"])
#endif

	TEST(@"Conversion of Unicode to ASCII #1",
	    !strcmp([C(@"This is a test") cStringWithEncoding:
	    OF_STRING_ENCODING_ASCII], "This is a test"))
	    OFStringEncodingASCII], "This is a test"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to ASCII #2",
	    OFInvalidEncodingException,
	    [C(@"This is a tést")
	    cStringWithEncoding: OF_STRING_ENCODING_ASCII])
	    cStringWithEncoding: OFStringEncodingASCII])

	TEST(@"Conversion of Unicode to ISO-8859-1 #1",
	    !strcmp([C(@"This is ä test") cStringWithEncoding:
	    OF_STRING_ENCODING_ISO_8859_1], "This is \xE4 test"))
	    OFStringEncodingISO8859_1], "This is \xE4 test"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to ISO-8859-1 #2",
	    OFInvalidEncodingException,
	    [C(@"This is ä t€st") cStringWithEncoding:
	    OF_STRING_ENCODING_ISO_8859_1])
	    OFStringEncodingISO8859_1])

#ifdef HAVE_ISO_8859_15
	TEST(@"Conversion of Unicode to ISO-8859-15 #1",
	    !strcmp([C(@"This is ä t€st") cStringWithEncoding:
	    OF_STRING_ENCODING_ISO_8859_15], "This is \xE4 t\xA4st"))
	    OFStringEncodingISO8859_15], "This is \xE4 t\xA4st"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to ISO-8859-15 #2",
	    OFInvalidEncodingException,
	    [C(@"This is ä t€st…") cStringWithEncoding:
	    OF_STRING_ENCODING_ISO_8859_15])
	    OFStringEncodingISO8859_15])
#endif

#ifdef HAVE_WINDOWS_1252
	TEST(@"Conversion of Unicode to Windows-1252 #1",
	    !strcmp([C(@"This is ä t€st…") cStringWithEncoding:
	    OF_STRING_ENCODING_WINDOWS_1252], "This is \xE4 t\x80st\x85"))
	    OFStringEncodingWindows1252], "This is \xE4 t\x80st\x85"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to Windows-1252 #2",
	    OFInvalidEncodingException, [C(@"This is ä t€st…‼")
	    cStringWithEncoding: OF_STRING_ENCODING_WINDOWS_1252])
	    cStringWithEncoding: OFStringEncodingWindows1252])
#endif

#ifdef HAVE_CODEPAGE_437
	TEST(@"Conversion of Unicode to Codepage 437 #1",
	    !strcmp([C(@"Tést strîng ░▒▓") cStringWithEncoding:
	    OF_STRING_ENCODING_CODEPAGE_437], "T\x82st str\x8Cng \xB0\xB1\xB2"))
	    OFStringEncodingCodepage437], "T\x82st str\x8Cng \xB0\xB1\xB2"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to Codepage 437 #2",
	    OFInvalidEncodingException, [C(@"T€st strîng ░▒▓")
	    cStringWithEncoding: OF_STRING_ENCODING_CODEPAGE_437])
	    cStringWithEncoding: OFStringEncodingCodepage437])
#endif

	TEST(@"Lossy conversion of Unicode to ASCII",
	    !strcmp([C(@"This is a tést") lossyCStringWithEncoding:
	    OF_STRING_ENCODING_ASCII], "This is a t?st"))
	    OFStringEncodingASCII], "This is a t?st"))

	TEST(@"Lossy conversion of Unicode to ISO-8859-1",
	    !strcmp([C(@"This is ä t€st") lossyCStringWithEncoding:
	    OF_STRING_ENCODING_ISO_8859_1], "This is \xE4 t?st"))
	    OFStringEncodingISO8859_1], "This is \xE4 t?st"))

#ifdef HAVE_ISO_8859_15
	TEST(@"Lossy conversion of Unicode to ISO-8859-15",
	    !strcmp([C(@"This is ä t€st…") lossyCStringWithEncoding:
	    OF_STRING_ENCODING_ISO_8859_15], "This is \xE4 t\xA4st?"))
	    OFStringEncodingISO8859_15], "This is \xE4 t\xA4st?"))
#endif

#ifdef HAVE_WINDOWS_1252
	TEST(@"Lossy conversion of Unicode to Windows-1252",
	    !strcmp([C(@"This is ä t€st…‼") lossyCStringWithEncoding:
	    OF_STRING_ENCODING_WINDOWS_1252], "This is \xE4 t\x80st\x85?"))
	    OFStringEncodingWindows1252], "This is \xE4 t\x80st\x85?"))
#endif

#ifdef HAVE_CODEPAGE_437
	TEST(@"Lossy conversion of Unicode to Codepage 437",
	    !strcmp([C(@"T€st strîng ░▒▓") lossyCStringWithEncoding:
	    OF_STRING_ENCODING_CODEPAGE_437], "T?st str\x8Cng \xB0\xB1\xB2"))
	    OFStringEncodingCodepage437], "T?st str\x8Cng \xB0\xB1\xB2"))
#endif

	TEST(@"+[stringWithFormat:]",
	    [(s[0] = [mutableStringClass stringWithFormat: @"%@:%d", @"test",
							   123])
	    isEqual: @"test:123"])

	TEST(@"-[appendFormat:]",
	    R(([s[0] appendFormat: @"%02X", 15])) &&
	    [s[0] isEqual: @"test:1230F"])

	TEST(@"-[rangeOfString:]",
	    [C(@"𝄞öö") rangeOfString: @"öö"].location == 1 &&
	    [C(@"𝄞öö") rangeOfString: @"ö"].location == 1 &&
	    [C(@"𝄞öö") rangeOfString: @"𝄞"].location == 0 &&
	    [C(@"𝄞öö") rangeOfString: @"x"].location == OF_NOT_FOUND &&
	    [C(@"𝄞öö") rangeOfString: @"x"].location == OFNotFound &&
	    [C(@"𝄞öö") rangeOfString: @"öö"
	    options: OF_STRING_SEARCH_BACKWARDS].location == 1 &&
	    options: OFStringSearchBackwards].location == 1 &&
	    [C(@"𝄞öö") rangeOfString: @"ö"
	    options: OF_STRING_SEARCH_BACKWARDS].location == 2 &&
	    options: OFStringSearchBackwards].location == 2 &&
	    [C(@"𝄞öö") rangeOfString: @"𝄞"
	    options: OF_STRING_SEARCH_BACKWARDS].location == 0 &&
	    options: OFStringSearchBackwards].location == 0 &&
	    [C(@"𝄞öö") rangeOfString: @"x"
	    options: OF_STRING_SEARCH_BACKWARDS].location == OF_NOT_FOUND)
	    options: OFStringSearchBackwards].location == OFNotFound)

	EXPECT_EXCEPTION(
	    @"Detect out of range in -[rangeOfString:options:range:]",
	    OFOutOfRangeException,
	    [C(@"𝄞öö") rangeOfString: @"ö" options: 0 range: of_range(3, 1)])
	    [C(@"𝄞öö") rangeOfString: @"ö" options: 0 range: OFMakeRange(3, 1)])

	cs = [OFCharacterSet characterSetWithCharactersInString: @"cđ"];
	TEST(@"-[indexOfCharacterFromSet:]",
	     [C(@"abcđabcđe") indexOfCharacterFromSet: cs] == 2 &&
	     [C(@"abcđabcđë")
	     indexOfCharacterFromSet: cs
			     options: OF_STRING_SEARCH_BACKWARDS] == 7 &&
			     options: OFStringSearchBackwards] == 7 &&
	     [C(@"abcđabcđë")
	     indexOfCharacterFromSet: cs
			     options: 0
			       range: of_range(4, 4)] == 6 &&
			       range: OFMakeRange(4, 4)] == 6 &&
	     [C(@"abcđabcđëf")
	     indexOfCharacterFromSet: cs
			     options: 0
			       range: of_range(8, 2)] == OF_NOT_FOUND)
			       range: OFMakeRange(8, 2)] == OFNotFound)

	EXPECT_EXCEPTION(
	    @"Detect out of range in -[indexOfCharacterFromSet:options:range:]",
	    OFOutOfRangeException,
	    [C(@"𝄞öö") indexOfCharacterFromSet: cs
				       options: 0
					 range: of_range(3, 1)])
					 range: OFMakeRange(3, 1)])

	TEST(@"-[substringWithRange:]",
	    [[C(@"𝄞öö") substringWithRange: of_range(1, 1)] isEqual: @"ö"] &&
	    [[C(@"𝄞öö") substringWithRange: of_range(3, 0)] isEqual: @""])
	    [[C(@"𝄞öö") substringWithRange: OFMakeRange(1, 1)] isEqual: @"ö"] &&
	    [[C(@"𝄞öö") substringWithRange: OFMakeRange(3, 0)] isEqual: @""])

	EXPECT_EXCEPTION(@"Detect out of range in -[substringWithRange:] #1",
	    OFOutOfRangeException,
	    [C(@"𝄞öö") substringWithRange: of_range(2, 2)])
	    [C(@"𝄞öö") substringWithRange: OFMakeRange(2, 2)])
	EXPECT_EXCEPTION(@"Detect out of range in -[substringWithRange:] #2",
	    OFOutOfRangeException,
	    [C(@"𝄞öö") substringWithRange: of_range(4, 0)])
	    [C(@"𝄞öö") substringWithRange: OFMakeRange(4, 0)])

	TEST(@"-[stringByAppendingString:]",
	    [[C(@"foo") stringByAppendingString: @"bar"] isEqual: @"foobar"])

	TEST(@"-[stringByPrependingString:]",
	    [[C(@"foo") stringByPrependingString: @"bar"] isEqual: @"barfoo"])

606
607
608
609
610
611
612
613

614
615
616
617
618
619
620
606
607
608
609
610
611
612

613
614
615
616
617
618
619
620







-
+







	    [[a objectAtIndex: 0] isEqual: @"foo"] &&
	    a.count == 1)

	i = 0;
	TEST(@"-[componentsSeparatedByString:options:]",
	    (a = [C(@"fooXXbarXXXXbazXXXX")
	    componentsSeparatedByString: @"XX"
				options: OF_STRING_SKIP_EMPTY]) &&
				options: OFStringSkipEmptyComponents]) &&
	    [[a objectAtIndex: i++] isEqual: @"foo"] &&
	    [[a objectAtIndex: i++] isEqual: @"bar"] &&
	    [[a objectAtIndex: i++] isEqual: @"baz"] &&
	    a.count == i)

	cs = [OFCharacterSet characterSetWithCharactersInString: @"XYZ"];

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







-
+







	    [[a objectAtIndex: i++] isEqual: @"x"] &&
	    a.count == i)

	i = 0;
	TEST(@"-[componentsSeparatedByCharactersInSet:options:]",
	    (a = [C(@"fooXYbarXYZXbazXYXZ")
	    componentsSeparatedByCharactersInSet: cs
					 options: OF_STRING_SKIP_EMPTY]) &&
	    options: OFStringSkipEmptyComponents]) &&
	    [[a objectAtIndex: i++] isEqual: @"foo"] &&
	    [[a objectAtIndex: i++] isEqual: @"bar"] &&
	    [[a objectAtIndex: i++] isEqual: @"baz"] &&
	    a.count == i)

#ifdef OF_HAVE_FILES
# if defined(OF_WINDOWS)
1185
1186
1187
1188
1189
1190
1191
1192

1193
1194

1195
1196
1197
1198
1199
1200
1201
1185
1186
1187
1188
1189
1190
1191

1192
1193

1194
1195
1196
1197
1198
1199
1200
1201







-
+

-
+







	       @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
	    unsignedLongLongValueWithBase: 16])

	TEST(@"-[characters]", (ua = C(@"fööbär🀺").characters) &&
	    !memcmp(ua, ucstr + 1, sizeof(ucstr) - 8))

#ifdef OF_BIG_ENDIAN
# define SWAPPED_BYTE_ORDER OF_BYTE_ORDER_LITTLE_ENDIAN
# define SWAPPED_BYTE_ORDER OFByteOrderLittleEndian
#else
# define SWAPPED_BYTE_ORDER OF_BYTE_ORDER_BIG_ENDIAN
# define SWAPPED_BYTE_ORDER OFByteOrderBigEndian
#endif
	TEST(@"-[UTF16String]", (u16a = C(@"fööbär🀺").UTF16String) &&
	    !memcmp(u16a, utf16str + 1, of_string_utf16_length(utf16str) * 2) &&
	    (u16a = [C(@"fööbär🀺")
	    UTF16StringWithByteOrder: SWAPPED_BYTE_ORDER]) &&
	    !memcmp(u16a, sutf16str + 1, of_string_utf16_length(sutf16str) * 2))

1264
1265
1266
1267
1268
1269
1270
1271

1272
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
1323
1324

1325
1326
1327
1328
1329
1330
1331
1264
1265
1266
1267
1268
1269
1270

1271
1272

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
1323

1324
1325
1326
1327
1328
1329
1330
1331







-
+

-
+




-
+


-
+


-
+







-
+




-
+




-
+




-
+
















-
+







	    [s[0] isEqual: @"abcde"] &&
	    R([s[0] setCharacter: 0x20AC atIndex: 3]) &&
	    [s[0] isEqual: @"abc€e"] &&
	    R([s[0] setCharacter: 'x' atIndex: 1]) && [s[0] isEqual: @"axc€e"])

	TEST(@"-[deleteCharactersInRange:]",
	    (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) &&
	    R([s[0] deleteCharactersInRange: of_range(1, 3)]) &&
	    R([s[0] deleteCharactersInRange: OFMakeRange(1, 3)]) &&
	    [s[0] isEqual: @"𝄞bä€"] &&
	    R([s[0] deleteCharactersInRange: of_range(0, 4)]) &&
	    R([s[0] deleteCharactersInRange: OFMakeRange(0, 4)]) &&
	    [s[0] isEqual: @""])

	TEST(@"-[replaceCharactersInRange:withString:]",
	    (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) &&
	    R([s[0] replaceCharactersInRange: of_range(1, 3)
	    R([s[0] replaceCharactersInRange: OFMakeRange(1, 3)
				  withString: @"äöüß"]) &&
	    [s[0] isEqual: @"𝄞äöüßbä€"] &&
	    R([s[0] replaceCharactersInRange: of_range(4, 2)
	    R([s[0] replaceCharactersInRange: OFMakeRange(4, 2)
				  withString: @"b"]) &&
	    [s[0] isEqual: @"𝄞äöübä€"] &&
	    R([s[0] replaceCharactersInRange: of_range(0, 7)
	    R([s[0] replaceCharactersInRange: OFMakeRange(0, 7)
				  withString: @""]) &&
	    [s[0] isEqual: @""])

	EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #1",
	    OFOutOfRangeException,
	    {
		s[0] = [mutableStringClass stringWithString: @"𝄞öö"];
		[s[0] deleteCharactersInRange: of_range(2, 2)];
		[s[0] deleteCharactersInRange: OFMakeRange(2, 2)];
	    })

	EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #2",
	    OFOutOfRangeException,
	    [s[0] deleteCharactersInRange: of_range(4, 0)])
	    [s[0] deleteCharactersInRange: OFMakeRange(4, 0)])

	EXPECT_EXCEPTION(@"Detect OoR in "
	    @"-[replaceCharactersInRange:withString:] #1",
	    OFOutOfRangeException,
	    [s[0] replaceCharactersInRange: of_range(2, 2) withString: @""])
	    [s[0] replaceCharactersInRange: OFMakeRange(2, 2) withString: @""])

	EXPECT_EXCEPTION(@"Detect OoR in "
	    @"-[replaceCharactersInRange:withString:] #2",
	    OFOutOfRangeException,
	    [s[0] replaceCharactersInRange: of_range(4, 0) withString: @""])
	    [s[0] replaceCharactersInRange: OFMakeRange(4, 0) withString: @""])

	TEST(@"-[replaceOccurrencesOfString:withString:]",
	    (s[0] = [mutableStringClass stringWithString:
	    @"asd fo asd fofo asd"]) &&
	    R([s[0] replaceOccurrencesOfString: @"fo" withString: @"foo"]) &&
	    [s[0] isEqual: @"asd foo asd foofoo asd"] &&
	    (s[0] = [mutableStringClass stringWithString: @"XX"]) &&
	    R([s[0] replaceOccurrencesOfString: @"X" withString: @"XX"]) &&
	    [s[0] isEqual: @"XXXX"])

	TEST(@"-[replaceOccurrencesOfString:withString:options:range:]",
	    (s[0] = [mutableStringClass stringWithString:
	    @"foofoobarfoobarfoo"]) &&
	    R([s[0] replaceOccurrencesOfString: @"oo"
				    withString: @"óò"
				       options: 0
					 range: of_range(2, 15)]) &&
					 range: OFMakeRange(2, 15)]) &&
	    [s[0] isEqual: @"foofóòbarfóòbarfoo"])

	TEST(@"-[deleteLeadingWhitespaces]",
	    (s[0] = [mutableStringClass stringWithString: whitespace[0]]) &&
	    R([s[0] deleteLeadingWhitespaces]) &&
	    [s[0] isEqual: @"asd  \t \t\t\r\n"] &&
	    (s[0] = [mutableStringClass stringWithString: whitespace[1]]) &&

Modified tests/OFTCPSocketTests.m from [da7e6e6092] to [dfc17ad706].

39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
54
55
56
57
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
57







-
+












	TEST(@"-[connectToHost:port:]",
	    R([client connectToHost: @"127.0.0.1" port: port]))

	TEST(@"-[accept]", (accepted = [server accept]))

	TEST(@"-[remoteAddress]",
	    [of_socket_address_ip_string(accepted.remoteAddress, NULL)
	    [OFSocketAddressString(accepted.remoteAddress)
	    isEqual: @"127.0.0.1"])

	TEST(@"-[writeString:]", [client writeString: @"Hello!"])

	TEST(@"-[readIntoBuffer:length:]",
	    [accepted readIntoBuffer: buf length: 6] &&
	    !memcmp(buf, "Hello!", 6))

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFUDPSocketTests.m from [29ec231a7f] to [c440a7c2a6].

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







-
-
+
+

-






-
+







-
-
+
+

-
+





-
-
-
+
+
+

-
-
-
+
+
+




static OFString *module = @"OFUDPSocket";

@implementation TestsAppDelegate (OFUDPSocketTests)
- (void)UDPSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFUDPSocket *sock;
	uint16_t port1, port2;
	of_socket_address_t addr1, addr2, addr3;
	uint16_t port1;
	OFSocketAddress addr1, addr2, addr3;
	char buf[6];
	OFString *host;

	TEST(@"+[socket]", (sock = [OFUDPSocket socket]))

	TEST(@"-[bindToHost:port:]",
	    (port1 = [sock bindToHost: @"127.0.0.1" port: 0]))

	addr1 = of_socket_address_parse_ip(@"127.0.0.1", port1);
	addr1 = OFSocketAddressParseIP(@"127.0.0.1", port1);

	TEST(@"-[sendBuffer:length:receiver:]",
	    R([sock sendBuffer: "Hello" length: 6 receiver: &addr1]))

	TEST(@"-[receiveIntoBuffer:length:sender:]",
	    [sock receiveIntoBuffer: buf length: 6 sender: &addr2] == 6 &&
	    !memcmp(buf, "Hello", 6) &&
	    (host = of_socket_address_ip_string(&addr2, &port2)) &&
	    [host isEqual: @"127.0.0.1"] && port2 == port1)
	    [OFSocketAddressString(&addr2) isEqual: @"127.0.0.1"] &&
	    OFSocketAddressPort(&addr2) == port1)

	addr3 = of_socket_address_parse_ip(@"127.0.0.1", port1 + 1);
	addr3 = OFSocketAddressParseIP(@"127.0.0.1", port1 + 1);

	/*
	 * TODO: Move those tests elsewhere as soon as the DNS resolving part
	 *	 is no longer in OFUDPSocket.
	 */
	TEST(@"of_socket_address_equal()",
	    of_socket_address_equal(&addr1, &addr2) &&
	    !of_socket_address_equal(&addr1, &addr3))
	TEST(@"OFSocketAddressEqual()",
	    OFSocketAddressEqual(&addr1, &addr2) &&
	    !OFSocketAddressEqual(&addr1, &addr3))

	TEST(@"of_socket_address_hash()",
	    of_socket_address_hash(&addr1) == of_socket_address_hash(&addr2) &&
	    of_socket_address_hash(&addr1) != of_socket_address_hash(&addr3))
	TEST(@"OFSocketAddressHash()",
	    OFSocketAddressHash(&addr1) == OFSocketAddressHash(&addr2) &&
	    OFSocketAddressHash(&addr1) != OFSocketAddressHash(&addr3))

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/OFValueTests.m from [dd07d710ca] to [8235c5a687].

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







-
-
-
-
+
+
+
+
-





-
+

-
+


-
-
+
+



-
+








static OFString *module = @"OFValue";

@implementation TestsAppDelegate (OFValueTests)
- (void)valueTests
{
	void *pool = objc_autoreleasePoolPush();
	of_range_t range = of_range(1, 64), range2;
	of_point_t point = of_point(1.5f, 3.0f), point2;
	of_dimension_t dimension = of_dimension(4.5f, 5.0f), dimension2;
	of_rectangle_t rectangle = of_rectangle(1.5f, 3.0f, 4.5f, 6.0f);
	OFRange range = OFMakeRange(1, 64), range2;
	OFPoint point = OFMakePoint(1.5f, 3.0f), point2;
	OFSize size = OFMakeSize(4.5f, 5.0f), size2;
	OFRect rect = OFMakeRect(1.5f, 3.0f, 4.5f, 6.0f), rect2;
	of_rectangle_t rectangle2;
	OFValue *value;
	void *pointer = &value;

	TEST(@"+[valueWithBytes:objCType:]",
	    (value = [OFValue valueWithBytes: &range
				    objCType: @encode(of_range_t)]))
				    objCType: @encode(OFRange)]))

	TEST(@"-[objCType]", strcmp(value.objCType, @encode(of_range_t)) == 0)
	TEST(@"-[objCType]", strcmp(value.objCType, @encode(OFRange)) == 0)

	TEST(@"-[getValue:size:]",
	    R([value getValue: &range2 size: sizeof(of_range_t)]) &&
	    of_range_equal(range2, range))
	    R([value getValue: &range2 size: sizeof(OFRange)]) &&
	    OFEqualRanges(range2, range))

	EXPECT_EXCEPTION(@"-[getValue:size:] with wrong size throws",
	    OFOutOfRangeException,
	    [value getValue: &range size: sizeof(of_range_t) - 1])
	    [value getValue: &range size: sizeof(OFRange) - 1])

	TEST(@"+[valueWithPointer:]",
	    (value = [OFValue valueWithPointer: pointer]))

	TEST(@"-[pointerValue]",
	    value.pointerValue == pointer &&
	    [[OFValue valueWithBytes: &pointer
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
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







-
+

-
-
+
+




-
+










-
+

-
-
+
+




-
+






-
-
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
+
+
+
+

-
+


-
+

-
-
+
+

-
-
-
-
-
+
+
+
+
+

-
-
-
-
+
+
+
+

-
+

-
+
-


-
-
-
+
+
+









	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] nonretainedObjectValue])

	TEST(@"+[valueWithRange:]",
	    (value = [OFValue valueWithRange: range]))

	TEST(@"-[rangeValue]",
	    of_range_equal(value.rangeValue, range) &&
	    OFEqualRanges(value.rangeValue, range) &&
	    (value = [OFValue valueWithBytes: &range
				    objCType: @encode(of_range_t)]) &&
	    of_range_equal(value.rangeValue, range))
				    objCType: @encode(OFRange)]) &&
	    OFEqualRanges(value.rangeValue, range))

	TEST(@"-[getValue:size:] for OFRangeValue",
	    (value = [OFValue valueWithRange: range]) &&
	    R([value getValue: &range2 size: sizeof(range2)]) &&
	    of_range_equal(range2, range))
	    OFEqualRanges(range2, range))

	EXPECT_EXCEPTION(@"-[rangeValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] rangeValue])

	TEST(@"+[valueWithPoint:]",
	    (value = [OFValue valueWithPoint: point]))

	TEST(@"-[pointValue]",
	    of_point_equal(value.pointValue, point) &&
	    OFEqualPoints(value.pointValue, point) &&
	    (value = [OFValue valueWithBytes: &point
				    objCType: @encode(of_point_t)]) &&
	    of_point_equal(value.pointValue, point))
				    objCType: @encode(OFPoint)]) &&
	    OFEqualPoints(value.pointValue, point))

	TEST(@"-[getValue:size:] for OFPointValue",
	    (value = [OFValue valueWithPoint: point]) &&
	    R([value getValue: &point2 size: sizeof(point2)]) &&
	    of_point_equal(point2, point))
	    OFEqualPoints(point2, point))

	EXPECT_EXCEPTION(@"-[pointValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] pointValue])

	TEST(@"+[valueWithDimension:]",
	    (value = [OFValue valueWithDimension: dimension]))
	TEST(@"+[valueWithSize:]",
	    (value = [OFValue valueWithSize: size]))

	TEST(@"-[dimensionValue]",
	    of_dimension_equal(value.dimensionValue, dimension) &&
	    (value = [OFValue valueWithBytes: &dimension
				    objCType: @encode(of_dimension_t)]) &&
	    of_dimension_equal(value.dimensionValue, dimension))
	TEST(@"-[sizeValue]",
	    OFEqualSizes(value.sizeValue, size) &&
	    (value = [OFValue valueWithBytes: &size
				    objCType: @encode(OFSize)]) &&
	    OFEqualSizes(value.sizeValue, size))

	TEST(@"-[getValue:size:] for OFDimensionValue",
	    (value = [OFValue valueWithDimension: dimension]) &&
	    R([value getValue: &dimension2 size: sizeof(dimension2)]) &&
	    of_dimension_equal(dimension2, dimension))
	TEST(@"-[getValue:size:] for OFSizeValue",
	    (value = [OFValue valueWithSize: size]) &&
	    R([value getValue: &size2 size: sizeof(size2)]) &&
	    OFEqualSizes(size2, size))

	EXPECT_EXCEPTION(@"-[dimensionValue] with wrong size throws",
	EXPECT_EXCEPTION(@"-[sizeValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] dimensionValue])
			    objCType: @encode(char)] sizeValue])

	TEST(@"+[valueWithRectangle:]",
	    (value = [OFValue valueWithRectangle: rectangle]))
	TEST(@"+[valueWithRect:]",
	    (value = [OFValue valueWithRect: rect]))

	TEST(@"-[rectangleValue]",
	    of_rectangle_equal(value.rectangleValue, rectangle) &&
	    (value = [OFValue valueWithBytes: &rectangle
				    objCType: @encode(of_rectangle_t)]) &&
	    of_rectangle_equal(value.rectangleValue, rectangle))
	TEST(@"-[rectValue]",
	    OFEqualRects(value.rectValue, rect) &&
	    (value = [OFValue valueWithBytes: &rect
				    objCType: @encode(OFRect)]) &&
	    OFEqualRects(value.rectValue, rect))

	TEST(@"-[getValue:size:] for OFRectangleValue",
	    (value = [OFValue valueWithRectangle: rectangle]) &&
	    R([value getValue: &rectangle2 size: sizeof(rectangle2)]) &&
	    of_rectangle_equal(rectangle2, rectangle))
	TEST(@"-[getValue:size:] for OFRectValue",
	    (value = [OFValue valueWithRect: rect]) &&
	    R([value getValue: &rect2 size: sizeof(rect2)]) &&
	    OFEqualRects(rect2, rect))

	EXPECT_EXCEPTION(@"-[rectangleValue] with wrong size throws",
	EXPECT_EXCEPTION(@"-[rectValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
	    [[OFValue valueWithBytes: "a" objCType: @encode(char)] rectValue])
			    objCType: @encode(char)] rectangleValue])

	TEST(@"-[isEqual:]",
	    [[OFValue valueWithRectangle: rectangle]
	    isEqual: [OFValue valueWithBytes: &rectangle
				    objCType: @encode(of_rectangle_t)]] &&
	    [[OFValue valueWithRect: rect]
	    isEqual: [OFValue valueWithBytes: &rect
				    objCType: @encode(OFRect)]] &&
	    ![[OFValue valueWithBytes: "a" objCType: @encode(signed char)]
	    isEqual: [OFValue valueWithBytes: "a"
				    objCType: @encode(unsigned char)]] &&
	    ![[OFValue valueWithBytes: "a" objCType: @encode(char)]
	    isEqual: [OFValue valueWithBytes: "b" objCType: @encode(char)]])

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/SocketTests.m from [a3c28758aa] to [ca5a359d97].

54
55
56
57
58
59
60
61

62
63
64
65

66
67
68
69

70
71

72
73

74
75

76
77

78
79

80
81

82
83

84
85

86
87

88
89

90
91

92


93
94

95
96
97
98

99
100
101
102
103
104
105

106
107
108
109
110

111
112
113
114
115

116
117
118
119
120

121
122
123
124

125
126

127
128

129
130

131
132

133
134

135
136

137
138

139
140

141
142

143
144

145
146

147
148

149
150

151
152

153
154

155
156

157
158

159
160
161
162




163
164
165
166

167
168
169
170
171

172
173
174
175
176

177
178
179
180
181
182
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
54
55
56
57
58
59
60

61

62
63

64
65
66
67

68


69
70

71


72
73

74


75
76

77


78
79

80


81
82

83


84
85
86
87
88

89

90
91

92
93
94
95
96
97
98

99
100
101
102
103

104
105
106
107
108

109
110
111
112
113

114
115
116
117

118


119
120

121


122
123

124


125
126

127


128
129

130


131
132

133


134
135

136


137
138

139


140
141

142


143
144



145
146
147
148
149
150
151

152

153
154
155

156

157
158
159

160

161
162
163
164


165
166

167
168
169


170
171

172
173
174


175
176

177
178
179


180
181

182
183
184


185
186

187
188
189


190

191
192
193


194
195

196
197
198
199







-
+
-


-
+



-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

+
+

-
+
-


-
+






-
+




-
+




-
+




-
+



-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
+
-
-
+

-
-
-
+
+
+
+



-
+
-



-
+
-



-
+
-




-
-
+
+
-



-
-
+
+
-



-
-
+
+
-



-
-
+
+
-



-
-
+
+
-



-
-
+
-



-
-
+
+
-





static OFString *module = @"Socket";

@implementation TestsAppDelegate (SocketTests)
- (void)socketTests
{
	void *pool = objc_autoreleasePoolPush();
	of_socket_address_t addr;
	OFSocketAddress addr;
	uint16_t port;

	TEST(@"Parsing an IPv4",
	    R(addr = of_socket_address_parse_ip(@"127.0.0.1", 1234)) &&
	    R(addr = OFSocketAddressParseIP(@"127.0.0.1", 1234)) &&
	    OF_BSWAP32_IF_LE(addr.sockaddr.in.sin_addr.s_addr) == 0x7F000001 &&
	    OF_BSWAP16_IF_LE(addr.sockaddr.in.sin_port) == 1234)

	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1",
	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"127.0.0.0.1", 1234))
	    OFSocketAddressParseIP(@"127.0.0.0.1", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2",
	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"127.0.0.256", 1234))
	    OFSocketAddressParseIP(@"127.0.0.256", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3",
	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"127.0.0. 1", 1234))
	    OFSocketAddressParseIP(@"127.0.0. 1", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4",
	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@" 127.0.0.1", 1234))
	    OFSocketAddressParseIP(@" 127.0.0.1", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5",
	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"127.0.a.1", 1234))
	    OFSocketAddressParseIP(@"127.0.a.1", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6",
	EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"127.0..1", 1234))
	    OFSocketAddressParseIP(@"127.0..1", 1234))

	TEST(@"Port of an IPv4 address", OFSocketAddressPort(&addr) == 1234)

	TEST(@"Converting an IPv4 to a string",
	    [of_socket_address_ip_string(&addr, &port) isEqual: @"127.0.0.1"] &&
	    [OFSocketAddressString(&addr) isEqual: @"127.0.0.1"])
	    port == 1234)

	TEST(@"Parsing an IPv6 #1",
	    R(addr = of_socket_address_parse_ip(
	    R(addr = OFSocketAddressParseIP(
	    @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) &&
	    COMPARE_V6(addr,
	    0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) &&
	    OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234)

	TEST(@"Parsing an IPv6 #2",
	    R(addr = of_socket_address_parse_ip(@"::", 1234)) &&
	    R(addr = OFSocketAddressParseIP(@"::", 1234)) &&
	    COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) &&
	    OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234)

	TEST(@"Parsing an IPv6 #3",
	    R(addr = of_socket_address_parse_ip(@"aaAa::bBbb", 1234)) &&
	    R(addr = OFSocketAddressParseIP(@"aaAa::bBbb", 1234)) &&
	    COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) &&
	    OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234)

	TEST(@"Parsing an IPv6 #4",
	    R(addr = of_socket_address_parse_ip(@"aaAa::", 1234)) &&
	    R(addr = OFSocketAddressParseIP(@"aaAa::", 1234)) &&
	    COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) &&
	    OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234)

	TEST(@"Parsing an IPv6 #5",
	    R(addr = of_socket_address_parse_ip(@"::aaAa", 1234)) &&
	    R(addr = OFSocketAddressParseIP(@"::aaAa", 1234)) &&
	    COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) &&
	    OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234)

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1:::2", 1234))
	    OFSocketAddressParseIP(@"1:::2", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1: ::2", 1234))
	    OFSocketAddressParseIP(@"1: ::2", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1:: :2", 1234))
	    OFSocketAddressParseIP(@"1:: :2", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1::2::3", 1234))
	    OFSocketAddressParseIP(@"1::2::3", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"10000::1", 1234))
	    OFSocketAddressParseIP(@"10000::1", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"::10000", 1234))
	    OFSocketAddressParseIP(@"::10000", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"::1::", 1234))
	    OFSocketAddressParseIP(@"::1::", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1:2:3:4:5:6:7:", 1234))
	    OFSocketAddressParseIP(@"1:2:3:4:5:6:7:", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9",
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", OFInvalidFormatException,
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1:2:3:4:5:6:7::", 1234))
	    OFSocketAddressParseIP(@"1:2:3:4:5:6:7::", 1234))

	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10",
	    OFInvalidFormatException,
	    of_socket_address_parse_ip(@"1:2", 1234))
	EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", OFInvalidFormatException,
	    OFSocketAddressParseIP(@"1:2", 1234))

	TEST(@"Port of an IPv6 address", OFSocketAddressPort(&addr) == 1234)

	SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0)
	TEST(@"Converting an IPv6 to a string #1",
	    [of_socket_address_ip_string(&addr, &port) isEqual: @"::"] &&
	    [OFSocketAddressString(&addr) isEqual: @"::"])
	    port == 1234)

	SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1)
	TEST(@"Converting an IPv6 to a string #2",
	    [of_socket_address_ip_string(&addr, &port) isEqual: @"::1"] &&
	    [OFSocketAddressString(&addr) isEqual: @"::1"])
	    port == 1234)

	SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0)
	TEST(@"Converting an IPv6 to a string #3",
	    [of_socket_address_ip_string(&addr, &port) isEqual: @"1::"] &&
	    [OFSocketAddressString(&addr) isEqual: @"1::"])
	    port == 1234)

	SET_V6(addr,
	    0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00)
	TEST(@"Converting an IPv6 to a string #4",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"] &&
	    [OFSocketAddressString(&addr)
	    isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"])
	    port == 1234)

	SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0)
	TEST(@"Converting an IPv6 to a string #5",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"1122:3344:5566:7788:99aa:bbcc:ddee:0"] &&
	    [OFSocketAddressString(&addr)
	    isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:0"])
	    port == 1234)

	SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0)
	TEST(@"Converting an IPv6 to a string #6",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"1122:3344:5566:7788:99aa:bbcc::"] &&
	    [OFSocketAddressString(&addr)
	    isEqual: @"1122:3344:5566:7788:99aa:bbcc::"])
	    port == 1234)

	SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00)
	TEST(@"Converting an IPv6 to a string #7",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"] &&
	    [OFSocketAddressString(&addr)
	    isEqual: @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"])
	    port == 1234)

	SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00)
	TEST(@"Converting an IPv6 to a string #8",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"::5566:7788:99aa:bbcc:ddee:ff00"] &&
	    [OFSocketAddressString(&addr)
	    isEqual: @"::5566:7788:99aa:bbcc:ddee:ff00"])
	    port == 1234)

	SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00)
	TEST(@"Converting an IPv6 to a string #9",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"0:0:5566::ddee:ff00"] &&
	    [OFSocketAddressString(&addr) isEqual: @"0:0:5566::ddee:ff00"])
	    port == 1234)

	SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0)
	TEST(@"Converting an IPv6 to a string #10",
	    [of_socket_address_ip_string(&addr, &port) isEqual:
	    @"::5566:7788:99aa:bbcc:0:0"] &&
	    [OFSocketAddressString(&addr)
	    isEqual: @"::5566:7788:99aa:bbcc:0:0"])
	    port == 1234)

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/terminal/TerminalTests.m from [cd3ec05bca] to [75c2b20fdf].

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







-
+



-
+

-
+

-
+

-
+

-
+

-
+










	[of_stdout eraseLine];
	[of_stdout writeString: @"World!"];
	[OFThread sleepForTimeInterval: 2];

	[of_stdout clear];
	[OFThread sleepForTimeInterval: 2];

	[of_stdout setCursorPosition: of_point(5, 3)];
	[of_stdout setCursorPosition: OFMakePoint(5, 3)];
	[of_stdout writeString: @"Text at (5, 3)"];
	[OFThread sleepForTimeInterval: 2];

	[of_stdout setRelativeCursorPosition: of_point(-2, 0)];
	[of_stdout setRelativeCursorPosition: OFMakePoint(-2, 0)];
	[OFThread sleepForTimeInterval: 2];
	[of_stdout setRelativeCursorPosition: of_point(2, 0)];
	[of_stdout setRelativeCursorPosition: OFMakePoint(2, 0)];
	[OFThread sleepForTimeInterval: 2];
	[of_stdout setRelativeCursorPosition: of_point(0, -2)];
	[of_stdout setRelativeCursorPosition: OFMakePoint(0, -2)];
	[OFThread sleepForTimeInterval: 2];
	[of_stdout setRelativeCursorPosition: of_point(0, 2)];
	[of_stdout setRelativeCursorPosition: OFMakePoint(0, 2)];
	[OFThread sleepForTimeInterval: 2];
	[of_stdout setRelativeCursorPosition: of_point(1, 1)];
	[of_stdout setRelativeCursorPosition: OFMakePoint(1, 1)];
	[OFThread sleepForTimeInterval: 2];
	[of_stdout setRelativeCursorPosition: of_point(-1, -1)];
	[of_stdout setRelativeCursorPosition: OFMakePoint(-1, -1)];
	[OFThread sleepForTimeInterval: 2];

	[of_stdout setCursorColumn: 2];
	[OFThread sleepForTimeInterval: 2];

	[of_stdout reset];

	[OFApplication terminate];
}
@end

Modified utils/ofarc/Archive.h from [2900eb7128] to [c76a3f3daa].

16
17
18
19
20
21
22
23

24
25
26

27
28
29
30
31
32
16
17
18
19
20
21
22

23
24
25

26
27
28
29
30
31
32







-
+


-
+






#import "OFObject.h"
#import "OFFile.h"
#import "OFArray.h"

@protocol Archive <OFObject>
+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
			     mode: (OFString *)mode
			 encoding: (of_string_encoding_t)encoding;
			 encoding: (OFStringEncoding)encoding;
- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
			  mode: (OFString *)mode
		      encoding: (of_string_encoding_t)encoding;
		      encoding: (OFStringEncoding)encoding;
- (void)listFiles;
- (void)extractFiles: (OFArray OF_GENERIC(OFString *) *)files;
- (void)printFiles: (OFArray OF_GENERIC(OFString *) *)files;
@optional
- (void)addFiles: (OFArray OF_GENERIC(OFString *) *)files;
@end

Modified utils/ofarc/GZIPArchive.m from [c5bd2c7c25] to [cd709fb905].

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







-
-
-
-
+
+
+
+












-
+






-
+













-
+








-
+







static OFArc *app;

static void
setPermissions(OFString *destination, OFString *source)
{
#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
	OFFileManager *fileManager = [OFFileManager defaultManager];
	of_file_attributes_t attributes =
	    [fileManager attributesOfItemAtPath: source];
	of_file_attribute_key_t key = of_file_attribute_key_posix_permissions;
	of_file_attributes_t destinationAttributes = [OFDictionary
	OFFileAttributes attributes = [fileManager
	    attributesOfItemAtPath: source];
	OFFileAttributeKey key = OFFilePOSIXPermissions;
	OFFileAttributes destinationAttributes = [OFDictionary
	    dictionaryWithObject: [attributes objectForKey: key]
			  forKey: key];

	[fileManager setAttributes: destinationAttributes
		      ofItemAtPath: destination];
#endif
}

static void
setModificationDate(OFString *path, OFGZIPStream *stream)
{
	OFDate *modificationDate = stream.modificationDate;
	of_file_attributes_t attributes;
	OFFileAttributes attributes;

	if (modificationDate == nil)
		return;

	attributes = [OFDictionary
	    dictionaryWithObject: modificationDate
			  forKey: of_file_attribute_key_modification_date];
			  forKey: OFFileModificationDate];
	[[OFFileManager defaultManager] setAttributes: attributes
					 ofItemAtPath: path];
}

@implementation GZIPArchive
+ (void)initialize
{
	if (self == [GZIPArchive class])
		app = (OFArc *)[OFApplication sharedApplication].delegate;
}

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
			     mode: (OFString *)mode
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithStream: stream
					mode: mode
				    encoding: encoding] autorelease];
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
			  mode: (OFString *)mode
		      encoding: (of_string_encoding_t)encoding
		      encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		_stream = [[OFGZIPStream alloc] initWithStream: stream
							  mode: mode];
	} @catch (id e) {

Modified utils/ofarc/LHAArchive.m from [a0cfa6c4ee] to [228be0ebf1].

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







-
+

-
+










-
+














-
+













-
+








-
+







-
+








	if (mode == nil)
		return;

	mode = [OFNumber numberWithUnsignedShort:
	    mode.unsignedShortValue & 0777];

	of_file_attributes_t attributes = [OFDictionary
	OFFileAttributes attributes = [OFDictionary
	    dictionaryWithObject: mode
			  forKey: of_file_attribute_key_posix_permissions];
			  forKey: OFFilePOSIXPermissions];

	[[OFFileManager defaultManager] setAttributes: attributes
					 ofItemAtPath: path];
#endif
}

static void
setModificationDate(OFString *path, OFLHAArchiveEntry *entry)
{
	OFDate *modificationDate = entry.modificationDate;
	of_file_attributes_t attributes;
	OFFileAttributes attributes;

	if (modificationDate == nil) {
		/*
		 * Fall back to the original date if we have no modification
		 * date, as the modification date is a UNIX extension.
		 */
		modificationDate = entry.date;

		if (modificationDate == nil)
			return;
	}

	attributes = [OFDictionary
	    dictionaryWithObject: modificationDate
			  forKey: of_file_attribute_key_modification_date];
			  forKey: OFFileModificationDate];
	[[OFFileManager defaultManager] setAttributes: attributes
					 ofItemAtPath: path];
}

@implementation LHAArchive
+ (void)initialize
{
	if (self == [LHAArchive class])
		app = (OFArc *)[OFApplication sharedApplication].delegate;
}

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
			     mode: (OFString *)mode
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithStream: stream
					mode: mode
				    encoding: encoding] autorelease];
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
			  mode: (OFString *)mode
		      encoding: (of_string_encoding_t)encoding
		      encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		_archive = [[OFLHAArchive alloc] initWithStream: stream
							   mode: mode];

		if (encoding != OF_STRING_ENCODING_AUTODETECT)
		if (encoding != OFStringEncodingAutodetect)
			_archive.encoding = encoding;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
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
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







-
-
+
+



















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


-
+




-
+







		    @"Need one or more files to add!")];
		app->_exitStatus = 1;
		return;
	}

	for (OFString *fileName in files) {
		void *pool = objc_autoreleasePoolPush();
		of_file_attributes_t attributes;
		of_file_type_t type;
		OFFileAttributes attributes;
		OFFileAttributeType type;
		OFMutableLHAArchiveEntry *entry;
		OFStream *output;

		if (app->_outputLevel >= 0)
			[of_stdout writeString: OF_LOCALIZED(@"adding_file",
			    @"Adding %[file]...",
			    @"file", fileName)];

		attributes = [fileManager attributesOfItemAtPath: fileName];
		type = attributes.fileType;
		entry = [OFMutableLHAArchiveEntry entryWithFileName: fileName];

#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
		entry.mode = [OFNumber numberWithUnsignedLong:
		    attributes.filePOSIXPermissions];
#endif
		entry.date = attributes.fileModificationDate;

#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER
		entry.UID =
		    [OFNumber numberWithUnsignedLong: attributes.filePOSIXUID];
		entry.GID =
		    [OFNumber numberWithUnsignedLong: attributes.filePOSIXGID];
		entry.owner = attributes.fileOwner;
		entry.group = attributes.fileGroup;
		entry.UID = [OFNumber numberWithUnsignedLong:
		    attributes.fileOwnerAccountID];
		entry.GID = [OFNumber numberWithUnsignedLong:
		    attributes.fileGroupOwnerAccountID];
		entry.owner = attributes.fileOwnerAccountName;
		entry.group = attributes.fileGroupOwnerAccountName;
#endif

		if ([type isEqual: of_file_type_directory])
		if ([type isEqual: OFFileTypeDirectory])
			entry.compressionMethod = @"-lhd-";

		output = [_archive streamForWritingEntry: entry];

		if ([type isEqual: of_file_type_regular]) {
		if ([type isEqual: OFFileTypeRegular]) {
			unsigned long long written = 0;
			unsigned long long size = attributes.fileSize;
			int8_t percent = -1, newPercent;

			OFFile *input = [OFFile fileWithPath: fileName
							mode: @"r"];

Modified utils/ofarc/OFArc.h from [535da98fc8] to [f6ae34fcaa].

35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51
35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51







-
+









	OFString *_archivePath;
	int _exitStatus;
}

- (id <Archive>)openArchiveWithPath: (OFString *)path
			       type: (OFString *)type
			       mode: (char)mode
			   encoding: (of_string_encoding_t)encoding;
			   encoding: (OFStringEncoding)encoding;
- (bool)shouldExtractFile: (OFString *)fileName
	      outFileName: (OFString *)outFileName;
- (ssize_t)copyBlockFromStream: (OFStream *)input
		      toStream: (OFStream *)output
		      fileName: (OFString *)fileName;
- (nullable OFString *)safeLocalPathForPath: (OFString *)path;
@end

OF_ASSUME_NONNULL_END

Modified utils/ofarc/OFArc.m from [e174e86e3a] to [f6c3dc0d49].

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







-
-
+
+


















-
-
-
-
-
+
+
+
+
+







		    @"    -x  --extract     Extract files")];
	}

	[OFApplication terminateWithStatus: status];
}

static void
mutuallyExclusiveError(of_unichar_t shortOption1, OFString *longOption1,
    of_unichar_t shortOption2, OFString *longOption2)
mutuallyExclusiveError(OFUnichar shortOption1, OFString *longOption1,
    OFUnichar shortOption2, OFString *longOption2)
{
	OFString *shortOption1Str = [OFString stringWithFormat: @"%C",
								shortOption1];
	OFString *shortOption2Str = [OFString stringWithFormat: @"%C",
								shortOption2];

	[of_stderr writeLine: OF_LOCALIZED(@"2_options_mutually_exclusive",
	    @"Error: -%[shortopt1] / --%[longopt1] and "
	    @"-%[shortopt2] / --%[longopt2] "
	    @"are mutually exclusive!",
	    @"shortopt1", shortOption1Str,
	    @"longopt1", longOption1,
	    @"shortopt2", shortOption2Str,
	    @"longopt2", longOption2)];
	[OFApplication terminateWithStatus: 1];
}

static void
mutuallyExclusiveError5(of_unichar_t shortOption1, OFString *longOption1,
    of_unichar_t shortOption2, OFString *longOption2,
    of_unichar_t shortOption3, OFString *longOption3,
    of_unichar_t shortOption4, OFString *longOption4,
    of_unichar_t shortOption5, OFString *longOption5)
mutuallyExclusiveError5(OFUnichar shortOption1, OFString *longOption1,
    OFUnichar shortOption2, OFString *longOption2,
    OFUnichar shortOption3, OFString *longOption3,
    OFUnichar shortOption4, OFString *longOption4,
    OFUnichar shortOption5, OFString *longOption5)
{
	OFString *shortOption1Str = [OFString stringWithFormat: @"%C",
								shortOption1];
	OFString *shortOption2Str = [OFString stringWithFormat: @"%C",
								shortOption2];
	OFString *shortOption3Str = [OFString stringWithFormat: @"%C",
								shortOption3];
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
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







-
+















-
-
+
+







	    @"type", type)];
}

@implementation OFArc
- (void)applicationDidFinishLaunching
{
	OFString *outputDir, *encodingString, *type;
	const of_options_parser_option_t options[] = {
	const OFOptionsParserOption options[] = {
		{ 'a', @"append", 0, NULL, NULL },
		{ 'c', @"create", 0, NULL, NULL },
		{ 'C', @"directory", 1, NULL, &outputDir },
		{ 'E', @"encoding", 1, NULL, &encodingString },
		{ 'f', @"force", 0, NULL, NULL },
		{ 'h', @"help", 0, NULL, NULL },
		{ 'l', @"list", 0, NULL, NULL },
		{ 'n', @"no-clobber", 0, NULL, NULL },
		{ 'p', @"print", 0, NULL, NULL },
		{ 'q', @"quiet", 0, NULL, NULL },
		{ 't', @"type", 1, NULL, &type },
		{ 'v', @"verbose", 0, NULL, NULL },
		{ 'x', @"extract", 0, NULL, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	of_unichar_t option, mode = '\0';
	of_string_encoding_t encoding = OF_STRING_ENCODING_AUTODETECT;
	OFUnichar option, mode = '\0';
	OFStringEncoding encoding = OFStringEncodingAutodetect;
	OFOptionsParser *optionsParser;
	OFArray OF_GENERIC(OFString *) *remainingArguments, *files;
	id <Archive> archive;

#ifdef OF_HAVE_SANDBOX
	OFSandbox *sandbox = [OFSandbox sandbox];
	sandbox.allowsStdIO = true;
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
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







-
+



















-
+







			[OFApplication terminateWithStatus: 1];
			break;
		}
	}

	@try {
		if (encodingString != nil)
			encoding = of_string_parse_encoding(encodingString);
			encoding = OFParseStringEncodingName(encodingString);
	} @catch (OFInvalidArgumentException *e) {
		[of_stderr writeLine: OF_LOCALIZED(
		    @"invalid_encoding",
		    @"%[prog]: Invalid encoding: %[encoding]",
		    @"prog", [OFApplication programName],
		    @"encoding", encodingString)];

		[OFApplication terminateWithStatus: 1];
	}

	remainingArguments = optionsParser.remainingArguments;

	switch (mode) {
	case 'a':
	case 'c':
		if (remainingArguments.count < 1)
			help(of_stderr, false, 1);

		files = [remainingArguments objectsInRange:
		    of_range(1, remainingArguments.count - 1)];
		    OFMakeRange(1, remainingArguments.count - 1)];

#ifdef OF_HAVE_SANDBOX
		if (![remainingArguments.firstObject isEqual: @"-"])
			[sandbox unveilPath: remainingArguments.firstObject
				permissions: (mode == 'a' ? @"rwc" : @"wc")];

		for (OFString *path in files)
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
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







-
+














-
+







				permissions: @"r"];

		sandbox.allowsUnveil = false;
		[OFApplication of_activateSandbox: sandbox];
#endif

		files = [remainingArguments objectsInRange:
		    of_range(1, remainingArguments.count - 1)];
		    OFMakeRange(1, remainingArguments.count - 1)];

		archive = [self
		    openArchiveWithPath: remainingArguments.firstObject
				   type: type
				   mode: mode
			       encoding: encoding];

		[archive printFiles: files];
		break;
	case 'x':
		if (remainingArguments.count < 1)
			help(of_stderr, false, 1);

		files = [remainingArguments objectsInRange:
		    of_range(1, remainingArguments.count - 1)];
		    OFMakeRange(1, remainingArguments.count - 1)];

#ifdef OF_HAVE_SANDBOX
		if (![remainingArguments.firstObject isEqual: @"-"])
			[sandbox unveilPath: remainingArguments.firstObject
				permissions: @"r"];

		if (files.count > 0)
460
461
462
463
464
465
466
467

468
469
470
471
472
473
474
460
461
462
463
464
465
466

467
468
469
470
471
472
473
474







-
+








	[OFApplication terminateWithStatus: _exitStatus];
}

- (id <Archive>)openArchiveWithPath: (OFString *)path
			       type: (OFString *)type
			       mode: (char)mode
			   encoding: (of_string_encoding_t)encoding
			   encoding: (OFStringEncoding)encoding
{
	OFString *modeString, *fileModeString;
	OFStream *file = nil;
	id <Archive> archive = nil;

	[_archivePath release];
	_archivePath = [path copy];

Modified utils/ofarc/TarArchive.m from [c4cfac3bfa] to [661f4e2e9e].

30
31
32
33
34
35
36
37

38
39

40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57

58
59
60
61
62
63
64
65
66
67
68
69
70
71

72
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
30
31
32
33
34
35
36

37
38

39
40
41
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95







-
+

-
+










-
+






-
+













-
+








-
+







-
+







static OFArc *app;

static void
setPermissions(OFString *path, OFTarArchiveEntry *entry)
{
#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
	OFNumber *mode = [OFNumber numberWithUnsignedShort: entry.mode & 0777];
	of_file_attributes_t attributes = [OFDictionary
	OFFileAttributes attributes = [OFDictionary
	    dictionaryWithObject: mode
			  forKey: of_file_attribute_key_posix_permissions];
			  forKey: OFFilePOSIXPermissions];

	[[OFFileManager defaultManager] setAttributes: attributes
					 ofItemAtPath: path];
#endif
}

static void
setModificationDate(OFString *path, OFTarArchiveEntry *entry)
{
	OFDate *modificationDate = entry.modificationDate;
	of_file_attributes_t attributes;
	OFFileAttributes attributes;

	if (modificationDate == nil)
		return;

	attributes = [OFDictionary
	    dictionaryWithObject: modificationDate
			  forKey: of_file_attribute_key_modification_date];
			  forKey: OFFileModificationDate];
	[[OFFileManager defaultManager] setAttributes: attributes
					 ofItemAtPath: path];
}

@implementation TarArchive
+ (void)initialize
{
	if (self == [TarArchive class])
		app = (OFArc *)[OFApplication sharedApplication].delegate;
}

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
			     mode: (OFString *)mode
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithStream: stream
					mode: mode
				    encoding: encoding] autorelease];
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
			  mode: (OFString *)mode
		      encoding: (of_string_encoding_t)encoding
		      encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		_archive = [[OFTarArchive alloc] initWithStream: stream
							   mode: mode];

		if (encoding != OF_STRING_ENCODING_AUTODETECT)
		if (encoding != OFStringEncodingAutodetect)
			_archive.encoding = encoding;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
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
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







-
+




-
+









-
+









-
+




















-
+




















-
+




-
+




-
+







			    @"date", date)];
		}

		if (app->_outputLevel >= 2) {
			[of_stdout writeString: @"\t"];

			switch (entry.type) {
			case OF_TAR_ARCHIVE_ENTRY_TYPE_FILE:
			case OFTarArchiveEntryTypeFile:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_normal",
				    @"Type: Normal file")];
				break;
			case OF_TAR_ARCHIVE_ENTRY_TYPE_LINK:
			case OFTarArchiveEntryTypeLink:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_hardlink",
				    @"Type: Hard link")];
				[of_stdout writeString: @"\t"];
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_link_target",
				    @"Target file name: %[target]",
				    @"target", entry.targetFileName)];
				break;
			case OF_TAR_ARCHIVE_ENTRY_TYPE_SYMLINK:
			case OFTarArchiveEntryTypeSymlink:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_symlink",
				    @"Type: Symbolic link")];
				[of_stdout writeString: @"\t"];
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_link_target",
				    @"Target file name: %[target]",
				    @"target", entry.targetFileName)];
				break;
			case OF_TAR_ARCHIVE_ENTRY_TYPE_CHARACTER_DEVICE: {
			case OFTarArchiveEntryTypeCharacterDevice: {
				OFString *majorString = [OFString
				    stringWithFormat: @"%d", entry.deviceMajor];
				OFString *minorString = [OFString
				    stringWithFormat: @"%d", entry.deviceMinor];

				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_character_device",
				    @"Type: Character device")];
				[of_stdout writeString: @"\t"];
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_device_major",
				    @"Device major: %[major]",
				    @"major", majorString)];
				[of_stdout writeString: @"\t"];
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_device_minor",
				    @"Device minor: %[minor]",
				    @"minor", minorString)];
				break;
			}
			case OF_TAR_ARCHIVE_ENTRY_TYPE_BLOCK_DEVICE: {
			case OFTarArchiveEntryTypeBlockDevice: {
				OFString *majorString = [OFString
				    stringWithFormat: @"%d", entry.deviceMajor];
				OFString *minorString = [OFString
				    stringWithFormat: @"%d", entry.deviceMinor];

				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_block_device",
				    @"Type: Block device")];
				[of_stdout writeString: @"\t"];
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_device_major",
				    @"Device major: %[major]",
				    @"major", majorString)];
				[of_stdout writeString: @"\t"];
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_device_minor",
				    @"Device minor: %[minor]",
				    @"minor", minorString)];
				break;
			}
			case OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY:
			case OFTarArchiveEntryTypeDirectory:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_directory",
				    @"Type: Directory")];
				break;
			case OF_TAR_ARCHIVE_ENTRY_TYPE_FIFO:
			case OFTarArchiveEntryTypeFIFO:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_fifo",
				    @"Type: FIFO")];
				break;
			case OF_TAR_ARCHIVE_ENTRY_TYPE_CONTIGUOUS_FILE:
			case OFTarArchiveEntryTypeContiguousFile:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_contiguous_file",
				    @"Type: Contiguous file")];
				break;
			default:
				[of_stdout writeLine: OF_LOCALIZED(
				    @"list_type_unknown",
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
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







-
+









-
-
+
+







	OFMutableSet OF_GENERIC(OFString *) *missing =
	    [OFMutableSet setWithArray: files];
	OFTarArchiveEntry *entry;

	while ((entry = [_archive nextEntry]) != nil) {
		void *pool = objc_autoreleasePoolPush();
		OFString *fileName = entry.fileName;
		of_tar_archive_entry_type_t type = entry.type;
		OFTarArchiveEntryType type = entry.type;
		OFString *outFileName, *directory;
		OFFile *output;
		OFStream *stream;
		uint64_t written = 0, size = entry.size;
		int8_t percent = -1, newPercent;

		if (!all && ![files containsObject: fileName])
			continue;

		if (type != OF_TAR_ARCHIVE_ENTRY_TYPE_FILE &&
		    type != OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY) {
		if (type != OFTarArchiveEntryTypeFile &&
		    type != OFTarArchiveEntryTypeDirectory) {
			if (app->_outputLevel >= 0)
				[of_stdout writeLine: OF_LOCALIZED(
				    @"skipping_file",
				    @"Skipping %[file]...",
				    @"file", fileName)];
			continue;
		}
311
312
313
314
315
316
317
318
319


320
321
322
323
324
325
326
311
312
313
314
315
316
317


318
319
320
321
322
323
324
325
326







-
-
+
+







		}

		if (app->_outputLevel >= 0)
			[of_stdout writeString: OF_LOCALIZED(@"extracting_file",
			    @"Extracting %[file]...",
			    @"file", fileName)];

		if (type == OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY ||
		    (type == OF_TAR_ARCHIVE_ENTRY_TYPE_FILE &&
		if (type == OFTarArchiveEntryTypeDirectory ||
		    (type == OFTarArchiveEntryTypeFile &&
		    [fileName hasSuffix: @"/"])) {
			[fileManager createDirectoryAtPath: outFileName
					     createParents: true];
			setPermissions(outFileName, entry);
			setModificationDate(outFileName, entry);

			if (app->_outputLevel >= 0) {
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
517
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
517







-
-
+
+



















-
-
-
-
+
+
+
+


-
-
-
-
+
+
+
+

-
-
+
+









-
+







		    @"Need one or more files to add!")];
		app->_exitStatus = 1;
		return;
	}

	for (OFString *fileName in files) {
		void *pool = objc_autoreleasePoolPush();
		of_file_attributes_t attributes;
		of_file_type_t type;
		OFFileAttributes attributes;
		OFFileAttributeType type;
		OFMutableTarArchiveEntry *entry;
		OFStream *output;

		if (app->_outputLevel >= 0)
			[of_stdout writeString: OF_LOCALIZED(@"adding_file",
			    @"Adding %[file]...",
			    @"file", fileName)];

		attributes = [fileManager attributesOfItemAtPath: fileName];
		type = attributes.fileType;
		entry = [OFMutableTarArchiveEntry entryWithFileName: fileName];

#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
		entry.mode = attributes.filePOSIXPermissions;
#endif
		entry.size = attributes.fileSize;
		entry.modificationDate = attributes.fileModificationDate;

#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER
		entry.UID = attributes.filePOSIXUID;
		entry.GID = attributes.filePOSIXGID;
		entry.owner = attributes.fileOwner;
		entry.group = attributes.fileGroup;
		entry.UID = attributes.fileOwnerAccountID;
		entry.GID = attributes.fileGroupOwnerAccountID;
		entry.owner = attributes.fileOwnerAccountName;
		entry.group = attributes.fileGroupOwnerAccountName;
#endif

		if ([type isEqual: of_file_type_regular])
			entry.type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE;
		else if ([type isEqual: of_file_type_directory]) {
			entry.type = OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY;
		if ([type isEqual: OFFileTypeRegular])
			entry.type = OFTarArchiveEntryTypeFile;
		else if ([type isEqual: OFFileTypeDirectory]) {
			entry.type = OFTarArchiveEntryTypeDirectory;
			entry.size = 0;
		} else if ([type isEqual: of_file_type_symbolic_link]) {
			entry.type = OF_TAR_ARCHIVE_ENTRY_TYPE_SYMLINK;
		} else if ([type isEqual: OFFileTypeSymbolicLink]) {
			entry.type = OFTarArchiveEntryTypeSymlink;
			entry.targetFileName =
			    attributes.fileSymbolicLinkDestination;
			entry.size = 0;
		}

		[entry makeImmutable];

		output = [_archive streamForWritingEntry: entry];

		if (entry.type == OF_TAR_ARCHIVE_ENTRY_TYPE_FILE) {
		if (entry.type == OFTarArchiveEntryTypeFile) {
			uint64_t written = 0, size = entry.size;
			int8_t percent = -1, newPercent;

			OFFile *input = [OFFile fileWithPath: fileName
							mode: @"r"];

			while (!input.atEndOfStream) {

Modified utils/ofarc/ZIPArchive.m from [a469b7585b] to [20066e086c].

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







-
-
-
-
+
+
+











-
+






-
+













-
+








-
+







setPermissions(OFString *path, OFZIPArchiveEntry *entry)
{
#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS
	if ((entry.versionMadeBy >> 8) ==
	    OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_UNIX) {
		OFNumber *mode = [OFNumber numberWithUnsignedShort:
		    (entry.versionSpecificAttributes >> 16) & 0777];
		of_file_attribute_key_t key =
		    of_file_attribute_key_posix_permissions;
		of_file_attributes_t attributes =
		    [OFDictionary dictionaryWithObject: mode forKey: key];
		OFFileAttributes attributes = [OFDictionary
		    dictionaryWithObject: mode
				  forKey: OFFilePOSIXPermissions];

		[[OFFileManager defaultManager] setAttributes: attributes
						 ofItemAtPath: path];
	}
#endif
}

static void
setModificationDate(OFString *path, OFZIPArchiveEntry *entry)
{
	OFDate *modificationDate = entry.modificationDate;
	of_file_attributes_t attributes;
	OFFileAttributes attributes;

	if (modificationDate == nil)
		return;

	attributes = [OFDictionary
	    dictionaryWithObject: modificationDate
			  forKey: of_file_attribute_key_modification_date];
			  forKey: OFFileModificationDate];
	[[OFFileManager defaultManager] setAttributes: attributes
					 ofItemAtPath: path];
}

@implementation ZIPArchive
+ (void)initialize
{
	if (self == [ZIPArchive class])
		app = (OFArc *)[OFApplication sharedApplication].delegate;
}

+ (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream
			     mode: (OFString *)mode
			 encoding: (of_string_encoding_t)encoding
			 encoding: (OFStringEncoding)encoding
{
	return [[[self alloc] initWithStream: stream
					mode: mode
				    encoding: encoding] autorelease];
}

- (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream
			  mode: (OFString *)mode
		      encoding: (of_string_encoding_t)encoding
		      encoding: (OFStringEncoding)encoding
{
	self = [super init];

	@try {
		_archive = [[OFZIPArchive alloc] initWithStream: stream
							   mode: mode];
	} @catch (id e) {
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
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







-
+











-
+







		return;
	}

	for (OFString *localFileName in files) {
		void *pool = objc_autoreleasePoolPush();
		OFArray OF_GENERIC (OFString *) *components;
		OFString *fileName;
		of_file_attributes_t attributes;
		OFFileAttributes attributes;
		bool isDirectory = false;
		OFMutableZIPArchiveEntry *entry;
		unsigned long long size;
		OFStream *output;

		components = localFileName.pathComponents;
		fileName = [components componentsJoinedByString: @"/"];

		attributes = [fileManager
		    attributesOfItemAtPath: localFileName];

		if ([attributes.fileType isEqual: of_file_type_directory]) {
		if ([attributes.fileType isEqual: OFFileTypeDirectory]) {
			isDirectory = true;
			fileName = [fileName stringByAppendingString: @"/"];
		}

		if (app->_outputLevel >= 0)
			[of_stdout writeString: OF_LOCALIZED(@"adding_file",
			    @"Adding %[file]...",

Modified utils/ofdns/OFDNS.m from [f422617926] to [3d972b3bf5].

79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94

95
96
97
98
99
100
101
102







-
+








-
+







	if (_inFlight == 0)
		[OFApplication terminateWithStatus: _errors];
}

- (void)applicationDidFinishLaunching
{
	OFString *DNSClassString, *server;
	const of_options_parser_option_t options[] = {
	const OFOptionsParserOption options[] = {
		{ 'c', @"class", 1, NULL, &DNSClassString },
		{ 'h', @"help", 0, NULL, NULL },
		{ 's', @"server", 1, NULL, &server },
		{ 't', @"type", 1, NULL, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFMutableArray OF_GENERIC(OFString *) *recordTypes;
	OFOptionsParser *optionsParser;
	of_unichar_t option;
	OFUnichar option;
	OFArray OF_GENERIC(OFString *) *remainingArguments;
	OFDNSResolver *resolver;
	of_dns_class_t DNSClass;

#ifdef OF_HAVE_FILES
# ifndef OF_AMIGAOS
	[OFLocale addLanguageDirectory: @LANGUAGE_DIR];

Modified utils/ofhash/OFHash.m from [871b144274] to [20916b6a0f].

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







-
+











-
+








@implementation OFHash
- (void)applicationDidFinishLaunching
{
	int exitStatus = 0;
	bool calculateMD5, calculateRIPEMD160, calculateSHA1, calculateSHA224;
	bool calculateSHA256, calculateSHA384, calculateSHA512;
	const of_options_parser_option_t options[] = {
	const OFOptionsParserOption options[] = {
		{ '\0', @"md5", 0, &calculateMD5, NULL },
		{ '\0', @"ripemd160", 0, &calculateRIPEMD160, NULL },
		{ '\0', @"sha1", 0, &calculateSHA1, NULL },
		{ '\0', @"sha224", 0, &calculateSHA224, NULL },
		{ '\0', @"sha256", 0, &calculateSHA256, NULL },
		{ '\0', @"sha384", 0, &calculateSHA384, NULL },
		{ '\0', @"sha512", 0, &calculateSHA512, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFOptionsParser *optionsParser =
	    [OFOptionsParser parserWithOptions: options];
	of_unichar_t option;
	OFUnichar option;
	OFMD5Hash *MD5Hash = nil;
	OFRIPEMD160Hash *RIPEMD160Hash = nil;
	OFSHA1Hash *SHA1Hash = nil;
	OFSHA224Hash *SHA224Hash = nil;
	OFSHA256Hash *SHA256Hash = nil;
	OFSHA384Hash *SHA384Hash = nil;
	OFSHA512Hash *SHA512Hash = nil;

Modified utils/ofhttp/OFHTTP.m from [f445945689] to [b36faae7ff].

313
314
315
316
317
318
319
320

321
322
323
324
325
326
327
313
314
315
316
317
318
319

320
321
322
323
324
325
326
327







-
+







}

- (void)addHeader: (OFString *)header
{
	size_t pos = [header rangeOfString: @":"].location;
	OFString *name, *value;

	if (pos == OF_NOT_FOUND) {
	if (pos == OFNotFound) {
		[of_stderr writeLine: OF_LOCALIZED(@"invalid_input_header",
		    @"%[prog]: Headers must to be in format name:value!",
		    @"prog", [OFApplication programName])];
		[OFApplication terminateWithStatus: 1];
	}

	name = [header substringToIndex: pos]
383
384
385
386
387
388
389
390

391
392
393
394

395
396
397
398
399
400
401
383
384
385
386
387
388
389

390
391
392
393

394
395
396
397
398
399
400
401







-
+



-
+







}

- (void)setProxy: (OFString *)proxy
{
	@try {
		size_t pos = [proxy
		    rangeOfString: @":"
			  options: OF_STRING_SEARCH_BACKWARDS].location;
			  options: OFStringSearchBackwards].location;
		OFString *host;
		unsigned long long port;

		if (pos == OF_NOT_FOUND)
		if (pos == OFNotFound)
			@throw [OFInvalidFormatException exception];

		host = [proxy substringToIndex: pos];
		port = [proxy substringFromIndex: pos + 1]
		    .unsignedLongLongValue;

		if (port > UINT16_MAX)
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
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







-
+
















-
+







		[OFApplication terminateWithStatus: 1];
	}
}

- (void)applicationDidFinishLaunching
{
	OFString *outputPath;
	const of_options_parser_option_t options[] = {
	const OFOptionsParserOption options[] = {
		{ 'b', @"body",	1, NULL, NULL },
		{ 'c', @"continue", 0, &_continue, NULL },
		{ 'f', @"force", 0, &_force, NULL },
		{ 'h', @"help",	0, NULL, NULL },
		{ 'H', @"header", 1, NULL, NULL },
		{ 'm', @"method", 1, NULL, NULL },
		{ 'o', @"output", 1, NULL, &outputPath },
		{ 'O', @"detect-filename", 0, &_detectFileName, NULL },
		{ 'P', @"socks5-proxy", 1, NULL, NULL },
		{ 'q', @"quiet", 0, &_quiet, NULL },
		{ 'v', @"verbose", 0, &_verbose, NULL },
		{ '\0', @"insecure", 0, &_insecure, NULL },
		{ '\0', @"ignore-status", 0, &_ignoreStatus, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFOptionsParser *optionsParser;
	of_unichar_t option;
	OFUnichar option;

#ifdef OF_HAVE_SANDBOX
	OFSandbox *sandbox = [OFSandbox sandbox];
	sandbox.allowsStdIO = true;
	sandbox.allowsReadingFiles = true;
	sandbox.allowsWritingFiles = true;
	sandbox.allowsCreatingFiles = true;
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
569
570
571
572
573
574
575

576
577
578
579
580
581
582
583







-
+







		    @"prog", [OFApplication programName])];
		[OFApplication terminateWithStatus: 1];
	}

	if (_insecure)
		_HTTPClient.allowsInsecureRedirects = true;

	_useUnicode = ([OFLocale encoding] == OF_STRING_ENCODING_UTF_8);
	_useUnicode = ([OFLocale encoding] == OFStringEncodingUTF8);

	[self performSelector: @selector(downloadNextURL) afterDelay: 0];
}

-    (void)client: (OFHTTPClient *)client
  didCreateSocket: (OFTCPSocket *)sock
	  request: (OFHTTPRequest *)request