ObjFW  Check-in [c85ff8d35a]

Overview
Comment:OFDataArray: Improve API.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: c85ff8d35a9a7fb28a142a4705dbbb9fd7847c8ec41c551aeb098fa890da3bbf
User & Date: js on 2012-12-15 17:52:20
Other Links: manifest | tags
Context
2012-12-15
19:36
OFHTTPServer: Fix handling of Host:. check-in: 2fb248a952 user: js tags: trunk
17:52
OFDataArray: Improve API. check-in: c85ff8d35a user: js tags: trunk
2012-12-14
01:46
Add -[description] for OFHTTPRequest(Result). check-in: c3d536d43c user: js tags: trunk
Changes

Modified src/OFArray_adjacent.m from [78c03c8d5c] to [72c1eebe96].

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
122







-
-
+
+







		@throw e;
	}

	@try {
		for (i = 0; i < count; i++)
			[objects[i] retain];

		[array addItemsFromCArray: objects
				    count: count];
		[array addItems: objects
			  count: count];
	} @catch (id e) {
		for (i = 0; i < count; i++)
			[objects[i] release];

		/* Prevent double-release of objects */
		[array release];
		array = nil;
144
145
146
147
148
149
150
151
152


153
154
155
156
157
158
159
144
145
146
147
148
149
150


151
152
153
154
155
156
157
158
159







-
-
+
+







			[objects[i] retain];
		}

		if (!ok)
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]];

		[array addItemsFromCArray: objects
				    count: count];
		[array addItems: objects
			  count: count];
	} @catch (id e) {
		size_t i;

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

		[self release];
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
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







-
+















-
+


















-
+

















-
+



















-
+







- (size_t)count
{
	return [array count];
}

- (id*)objects
{
	return [array cArray];
	return [array items];
}

- (id)objectAtIndex: (size_t)index
{
	return *((id*)[array itemAtIndex: index]);
}

- (id)objectAtIndexedSubscript: (size_t)index
{
	return *((id*)[array itemAtIndex: index]);
}

- (void)getObjects: (id*)buffer
	   inRange: (of_range_t)range
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];

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

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

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

	if (object == nil)
		return OF_NOT_FOUND;

	objects = [array cArray];
	objects = [array items];
	count = [array count];

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

	return OF_NOT_FOUND;
}

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

	if (object == nil)
		return OF_NOT_FOUND;

	objects = [array cArray];
	objects = [array items];
	count = [array count];

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

	return OF_NOT_FOUND;
}


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

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

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

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







-
+











-
+
















-
+










-
+










	otherArray = object;

	count = [array count];

	if (count != [otherArray count])
		return NO;

	objects = [array cArray];
	objects = [array items];
	otherObjects = [otherArray objects];

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

	return YES;
}

- (uint32_t)hash
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];
	uint32_t hash;

	OF_HASH_INIT(hash);

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

	OF_HASH_FINALIZE(hash);

	return hash;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];
	BOOL stop = NO;

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

- (void)dealloc
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];

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

	[array release];

	[super dealloc];
}
@end

Modified src/OFDataArray+Hashing.m from [d10ff72ecd] to [f44a85040b].

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







-
+

















-
+










-
+

















-
+


{
	void *pool = objc_autoreleasePoolPush();
	OFMD5Hash *hash = [OFMD5Hash hash];
	uint8_t *digest;
	char cString[OF_MD5_DIGEST_SIZE * 2];
	size_t i;

	[hash updateWithBuffer: data
	[hash updateWithBuffer: items
			length: count * itemSize];
	digest = [hash digest];

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

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

		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
				    length: 32];
				    length: OF_MD5_DIGEST_SIZE * 2];
}

- (OFString*)SHA1Hash
{
	void *pool = objc_autoreleasePoolPush();
	OFSHA1Hash *hash = [OFSHA1Hash hash];
	uint8_t *digest;
	char cString[OF_SHA1_DIGEST_SIZE * 2];
	size_t i;

	[hash updateWithBuffer: data
	[hash updateWithBuffer: items
			length: count * itemSize];
	digest = [hash digest];

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

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

		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
				    length: 40];
				    length: OF_SHA1_DIGEST_SIZE * 2];
}
@end

Modified src/OFDataArray.h from [ebbd8162b6] to [fbee0f546e].

27
28
29
30
31
32
33
34

35
36
37
38
39
40

41
42
43
44
45
46
47
27
28
29
30
31
32
33

34
35
36
37
38
39

40
41
42
43
44
45
46
47







-
+





-
+







 * OFBigDataArray, which allocates the memory in pages rather than in bytes.
 *
 * For security reasons, serialization and deserialization is only implemented
 * for OFDataArrays with item size 1.
 */
@interface OFDataArray: OFObject <OFCopying, OFComparing, OFSerialization>
{
	uint8_t *data;
	uint8_t *items;
	size_t count;
	size_t itemSize;
}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, getter=cArray) void *data;
@property (readonly) void *items;
@property (readonly) size_t count;
@property (readonly) size_t itemSize;
#endif

/*!
 * @brief Creates a new OFDataArray with an item size of 1.
 *
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165

166
167
168
169
170
171
172
149
150
151
152
153
154
155

156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172







-
+








-
+







 * @brief Returns the size of each item in the OFDataArray in bytes.
 *
 * @return The size of each item in the OFDataArray in bytes
 */
- (size_t)itemSize;

/*!
 * @brief Returns all elements of the OFDataArray as a C array.
 * @brief Returns all items of the OFDataArray as a C array.
 *
 * @warning The pointer is only valid until the OFDataArray is changed!
 *
 * Modifying the returned array directly is allowed and will change the contents
 * of the data array.
 *
 * @return All elements of the OFDataArray as a C array
 */
- (void*)cArray OF_RETURNS_INNER_POINTER;
- (void*)items OF_RETURNS_INNER_POINTER;

/*!
 * @brief Returns a specific item of the OFDataArray.
 *
 * @param index The number of the item to return
 * @return The specified item of the OFDataArray
 */
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
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







-
+

-
-
+
+




-
+



-
-
-
+
+
+







- (void)insertItem: (const void*)item
	   atIndex: (size_t)index;

/*!
 * @brief Adds items from a C array to the OFDataArray.
 *
 * @param count The number of items to add
 * @param cArray A C array containing the items to add
 * @param items A C array containing the items to add
 */
- (void)addItemsFromCArray: (const void*)cArray
		     count: (size_t)count;
- (void)addItems: (const void*)array
	   count: (size_t)count;

/*!
 * @brief Adds items from a C array to the OFDataArray at the specified index.
 *
 * @param cArray A C array containing the items to add
 * @param items A C array containing the items to add
 * @param index The index where the items should be added
 * @param count The number of items to add
 */
- (void)insertItemsFromCArray: (const void*)cArray
		      atIndex: (size_t)index
			count: (size_t)count;
- (void)insertItems: (const void*)items
	    atIndex: (size_t)index
	      count: (size_t)count;

/*!
 * @brief Removes the item at the specified index.
 *
 * @param index The index of the item to remove
 */
- (void)removeItemAtIndex: (size_t)index;

Modified src/OFDataArray.m from [ca2bfba7fb] to [9afe18d8f2].

116
117
118
119
120
121
122
123
124


125
126
127
128
129
130
131
116
117
118
119
120
121
122


123
124
125
126
127
128
129
130
131







-
-
+
+







			char *buffer = [self allocMemoryWithSize: of_pagesize];

			while (![file isAtEndOfStream]) {
				size_t length;

				length = [file readIntoBuffer: buffer
						       length: of_pagesize];
				[self addItemsFromCArray: buffer
						   count: length];
				[self addItems: buffer
					 count: length];
			}

			[self freeMemory: buffer];
		} @finally {
			[file release];
		}
	} @catch (id e) {
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







-
+








		if (count & 1)
			@throw [OFInvalidFormatException
			    exceptionWithClass: [self class]];

		count >>= 1;
		cString = [string UTF8String];
		data = [self allocMemoryWithSize: count];
		items = [self allocMemoryWithSize: count];

		for (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')
210
211
212
213
214
215
216
217

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

217
218
219
220
221
222
223
224







-
+







				byte |= c2 - 'a' + 10;
			else if (c2 >= 'A' && c2 <= 'F')
				byte |= c2 - 'A' + 10;
			else
				@throw [OFInvalidFormatException
				    exceptionWithClass: [self class]];

			data[i] = byte;
			items[i] = byte;
		}
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
286
287
288
289
290
291
292
293

294
295

296
297
298
299
300
301
302
303

304
305
306
307
308

309
310
311

312
313
314
315
316

317
318
319

320
321
322
323
324
325
326
327
328
329



330
331

332
333
334
335
336
337
338
339
340
341



342
343
344
345


346
347

348
349
350
351
352



353
354
355


356
357
358
359
360



361
362

363
364
365
366
367



368
369

370
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
286
287
288
289
290
291
292

293
294

295
296
297
298
299
300
301
302

303
304
305
306
307

308
309
310

311
312
313
314
315

316
317
318

319
320
321
322
323
324
325
326



327
328
329
330

331
332
333
334
335
336
337
338



339
340
341
342
343


344
345
346

347
348
349



350
351
352
353


354
355
356
357



358
359
360
361

362
363
364



365
366
367
368

369
370

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







-
+

-
+







-
+




-
+


-
+




-
+


-
+







-
-
-
+
+
+

-
+







-
-
-
+
+
+


-
-
+
+

-
+


-
-
-
+
+
+

-
-
+
+


-
-
-
+
+
+

-
+


-
-
-
+
+
+

-
+

-
+

-
+













-
-
+
+




-
-
-
+
+
+












-
-
-
+
+
+







-
+

-
+







-
-
+
+
















-
+







}

- (size_t)itemSize
{
	return itemSize;
}

- (void*)cArray
- (void*)items
{
	return data;
	return items;
}

- (void*)itemAtIndex: (size_t)index
{
	if (index >= count)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	return data + index * itemSize;
	return items + index * itemSize;
}

- (void*)firstItem
{
	if (data == NULL || count == 0)
	if (items == NULL || count == 0)
		return NULL;

	return data;
	return items;
}

- (void*)lastItem
{
	if (data == NULL || count == 0)
	if (items == NULL || count == 0)
		return NULL;

	return data + (count - 1) * itemSize;
	return items + (count - 1) * itemSize;
}

- (void)addItem: (const void*)item
{
	if (SIZE_MAX - count < 1)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	data = [self resizeMemory: data
			     size: itemSize
			    count: count + 1];
	items = [self resizeMemory: items
			      size: itemSize
			     count: count + 1];

	memcpy(data + count * itemSize, item, itemSize);
	memcpy(items + count * itemSize, item, itemSize);

	count++;
}

- (void)insertItem: (const void*)item
	   atIndex: (size_t)index
{
	[self insertItemsFromCArray: item
			    atIndex: index
			      count: 1];
	[self insertItems: item
		  atIndex: index
		    count: 1];
}

- (void)addItemsFromCArray: (const void*)cArray
		     count: (size_t)nItems
- (void)addItems: (const void*)items_
	   count: (size_t)count_
{
	if (nItems > SIZE_MAX - count)
	if (count_ > SIZE_MAX - count)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	data = [self resizeMemory: data
			     size: itemSize
			    count: count + nItems];
	items = [self resizeMemory: items
			      size: itemSize
			     count: count + count_];

	memcpy(data + count * itemSize, cArray, nItems * itemSize);
	count += nItems;
	memcpy(items + count * itemSize, items_, count_ * itemSize);
	count += count_;
}

- (void)insertItemsFromCArray: (const void*)cArray
		      atIndex: (size_t)index
			count: (size_t)nItems
- (void)insertItems: (const void*)items_
	    atIndex: (size_t)index
	      count: (size_t)count_
{
	if (nItems > SIZE_MAX - count || index > count)
	if (count_ > SIZE_MAX - count || index > count)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	data = [self resizeMemory: data
			     size: itemSize
			    count: count + nItems];
	items = [self resizeMemory: items
			      size: itemSize
			     count: count + count_];

	memmove(data + (index + nItems) * itemSize, data + index * itemSize,
	memmove(items + (index + count_) * itemSize, items + index * itemSize,
	    (count - index) * itemSize);
	memcpy(data + index * itemSize, cArray, nItems * itemSize);
	memcpy(items + index * itemSize, items_, count_ * itemSize);

	count += nItems;
	count += count_;
}

- (void)removeItemAtIndex: (size_t)index
{
	[self removeItemsInRange: of_range(index, 1)];
}

- (void)removeItemsInRange: (of_range_t)range
{
	if (range.length > SIZE_MAX - range.location ||
	    range.location + range.length > count)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	memmove(data + range.location * itemSize,
	    data + (range.location + range.length) * itemSize,
	memmove(items + range.location * itemSize,
	    items + (range.location + range.length) * itemSize,
	    (count - range.location - range.length) * itemSize);

	count -= range.length;
	@try {
		data = [self resizeMemory: data
				     size: itemSize
				    count: count];
		items = [self resizeMemory: items
				      size: itemSize
				     count: count];
	} @catch (OFOutOfMemoryException *e) {
		/* We don't really care, as we only made it smaller */
	}
}

- (void)removeLastItem
{
	if (count == 0)
		return;

	count--;
	@try {
		data = [self resizeMemory: data
				     size: itemSize
				    count: count];
		items = [self resizeMemory: items
				      size: itemSize
				     count: count];
	} @catch (OFOutOfMemoryException *e) {
		/* We don't care, as we only made it smaller */
	}
}

- (void)removeAllItems
{
	[self freeMemory: data];
	[self freeMemory: items];

	data = NULL;
	items = NULL;
	count = 0;
}

- copy
{
	OFDataArray *copy = [[[self class] alloc] initWithItemSize: itemSize];

	[copy addItemsFromCArray: data
			   count: count];
	[copy addItems: items
		 count: count];

	return copy;
}

- (BOOL)isEqual: (id)object
{
	OFDataArray *otherDataArray;

	if (![object isKindOfClass: [OFDataArray class]])
		return NO;

	otherDataArray = object;

	if ([otherDataArray count] != count ||
	    [otherDataArray itemSize] != itemSize)
		return NO;
	if (memcmp([otherDataArray cArray], data, count * itemSize))
	if (memcmp([otherDataArray items], items, count * itemSize))
		return NO;

	return YES;
}

- (of_comparison_result_t)compare: (id <OFComparing>)object
{
465
466
467
468
469
470
471
472

473
474
475
476
477
478
479
465
466
467
468
469
470
471

472
473
474
475
476
477
478
479







-
+







		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]
			      selector: _cmd];

	otherCount = [otherDataArray count];
	minimumCount = (count > otherCount ? otherCount : count);

	if ((comparison = memcmp(data, [otherDataArray cArray],
	if ((comparison = memcmp(items, [otherDataArray items],
	    minimumCount * itemSize)) == 0) {
		if (count > otherCount)
			return OF_ORDERED_DESCENDING;
		if (count < otherCount)
			return OF_ORDERED_ASCENDING;
		return OF_ORDERED_SAME;
	}
488
489
490
491
492
493
494
495

496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530

531
532
533
534
535
536
537
538

539
540
541
542
543
544
545
546
547

548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568

569
570
571
572
573
574
575
488
489
490
491
492
493
494

495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529

530
531
532
533
534
535
536
537

538
539
540
541
542
543
544
545
546

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567

568
569
570
571
572
573
574
575







-
+


















-
+















-
+







-
+








-
+




















-
+







{
	uint32_t hash;
	size_t i;

	OF_HASH_INIT(hash);

	for (i = 0; i < count * itemSize; i++)
		OF_HASH_ADD(hash, ((char*)data)[i]);
		OF_HASH_ADD(hash, ((uint8_t*)items)[i]);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (OFString*)description
{
	OFMutableString *ret = [OFMutableString stringWithString: @"<"];
	size_t i;

	for (i = 0; i < count; i++) {
		size_t j;

		if (i > 0)
			[ret appendString: @" "];

		for (j = 0; j < itemSize; j++)
			[ret appendFormat: @"%02x", data[i * itemSize + j]];
			[ret appendFormat: @"%02x", items[i * itemSize + j]];
	}

	[ret appendString: @">"];

	[ret makeImmutable];
	return ret;
}

- (OFString*)stringRepresentation
{
	OFMutableString *ret = [OFMutableString string];
	size_t i, j;

	for (i = 0; i < count; i++)
		for (j = 0; j < itemSize; j++)
			[ret appendFormat: @"%02x", data[i * itemSize + j]];
			[ret appendFormat: @"%02x", items[i * itemSize + j]];

	[ret makeImmutable];
	return ret;
}

- (OFString*)stringByBase64Encoding
{
	return of_base64_encode(data, count * itemSize);
	return of_base64_encode(items, count * itemSize);
}

- (void)writeToFile: (OFString*)path
{
	OFFile *file = [[OFFile alloc] initWithPath: path
					       mode: @"wb"];

	@try {
		[file writeBuffer: data
		[file writeBuffer: items
			   length: count * itemSize];
	} @finally {
		[file release];
	}
}

- (OFXMLElement*)XMLElementBySerializing
{
	void *pool;
	OFXMLElement *element;

	if (itemSize != 1)
		@throw [OFNotImplementedException
		    exceptionWithClass: [self class]
			      selector: _cmd];

	pool = objc_autoreleasePoolPush();
	element = [OFXMLElement
	    elementWithName: [self className]
		  namespace: OF_SERIALIZATION_NS
		stringValue: of_base64_encode(data, count * itemSize)];
		stringValue: of_base64_encode(items, count * itemSize)];

	[element retain];

	objc_autoreleasePoolPop(pool);

	return [element autorelease];
}
583
584
585
586
587
588
589
590
591


592
593

594
595
596
597
598
599
600


601
602
603
604

605
606
607
608

609
610
611
612


613
614

615
616

617
618
619
620
621
622



623
624
625
626
627


628
629
630
631

632
633
634
635


636
637

638
639

640
641

642
643
644
645
646
647
648
649
650
651
652
653
654


655
656
657
658
659
660
661
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
583
584
585
586
587
588
589


590
591
592

593
594
595
596
597
598


599
600
601
602
603

604
605
606
607

608
609
610


611
612
613

614
615

616
617
618
619



620
621
622
623
624
625


626
627
628
629
630

631
632
633


634
635
636

637
638

639
640

641
642
643
644
645
646
647
648
649
650
651
652


653
654
655
656
657
658
659
660
661


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







-
-
+
+

-
+





-
-
+
+



-
+



-
+


-
-
+
+

-
+

-
+



-
-
-
+
+
+



-
-
+
+



-
+


-
-
+
+

-
+

-
+

-
+











-
-
+
+







-
-
+
+
















-
-
+
+










-
+

-
+




	if (SIZE_MAX - count < 1 || count + 1 > SIZE_MAX / itemSize)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	lastPageByte = of_pagesize - 1;
	newSize = ((count + 1) * itemSize + lastPageByte) & ~lastPageByte;

	if (size != newSize)
		data = [self resizeMemory: data
				     size: newSize];
		items = [self resizeMemory: items
				      size: newSize];

	memcpy(data + count * itemSize, item, itemSize);
	memcpy(items + count * itemSize, item, itemSize);

	count++;
	size = newSize;
}

- (void)addItemsFromCArray: (const void*)cArray
		     count: (size_t)nItems
- (void)addItems: (const void*)items_
	   count: (size_t)count_
{
	size_t newSize, lastPageByte;

	if (nItems > SIZE_MAX - count || count + nItems > SIZE_MAX / itemSize)
	if (count_ > SIZE_MAX - count || count + count_ > SIZE_MAX / itemSize)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	lastPageByte = of_pagesize - 1;
	newSize = ((count + nItems) * itemSize + lastPageByte) & ~lastPageByte;
	newSize = ((count + count_) * itemSize + lastPageByte) & ~lastPageByte;

	if (size != newSize)
		data = [self resizeMemory: data
				     size: newSize];
		items = [self resizeMemory: items
				      size: newSize];

	memcpy(data + count * itemSize, cArray, nItems * itemSize);
	memcpy(items + count * itemSize, items_, count_ * itemSize);

	count += nItems;
	count += count_;
	size = newSize;
}

- (void)insertItemsFromCArray: (const void*)cArray
		      atIndex: (size_t)index
			count: (size_t)nItems
- (void)insertItems: (const void*)items_
	    atIndex: (size_t)index
	      count: (size_t)count_
{
	size_t newSize, lastPageByte;

	if (nItems > SIZE_MAX - count || index > count ||
	    count + nItems > SIZE_MAX / itemSize)
	if (count_ > SIZE_MAX - count || index > count ||
	    count + count_ > SIZE_MAX / itemSize)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	lastPageByte = of_pagesize - 1;
	newSize = ((count + nItems) * itemSize + lastPageByte) & ~lastPageByte;
	newSize = ((count + count_) * itemSize + lastPageByte) & ~lastPageByte;

	if (size != newSize)
		data = [self resizeMemory: data
				     size: newSize];
		items = [self resizeMemory: items
				      size: newSize];

	memmove(data + (index + nItems) * itemSize, data + index * itemSize,
	memmove(items + (index + count_) * itemSize, items + index * itemSize,
	    (count - index) * itemSize);
	memcpy(data + index * itemSize, cArray, nItems * itemSize);
	memcpy(items + index * itemSize, items_, count_ * itemSize);

	count += nItems;
	count += count_;
	size = newSize;
}

- (void)removeItemsInRange: (of_range_t)range
{
	size_t newSize, lastPageByte;

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

	memmove(data + range.location * itemSize,
	    data + (range.location + range.length) * itemSize,
	memmove(items + range.location * itemSize,
	    items + (range.location + range.length) * itemSize,
	    (count - range.location - range.length) * itemSize);

	count -= range.length;
	lastPageByte = of_pagesize - 1;
	newSize = (count * itemSize + lastPageByte) & ~lastPageByte;

	if (size != newSize)
		data = [self resizeMemory: data
				     size: newSize];
		items = [self resizeMemory: items
				      size: newSize];
	size = newSize;
}

- (void)removeLastItem
{
	size_t newSize, lastPageByte;

	if (count == 0)
		return;

	count--;
	lastPageByte = of_pagesize - 1;
	newSize = (count * itemSize + lastPageByte) & ~lastPageByte;

	if (size != newSize) {
		@try {
			data = [self resizeMemory: data
					     size: newSize];
			items = [self resizeMemory: items
					      size: newSize];
		} @catch (OFOutOfMemoryException *e) {
			/* We don't care, as we only made it smaller */
		}

		size = newSize;
	}
}

- (void)removeAllItems
{
	[self freeMemory: data];
	[self freeMemory: items];

	data = NULL;
	items = NULL;
	count = 0;
	size = 0;
}
@end

Modified src/OFHTTPClient.m from [befaf122bc] to [9d0e6d26b7].

215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229







-
+







	[sock writeString: @"\r\n"];

	/* Work around a bug in lighttpd, see above */
	[sock flushWriteBuffer];
	[sock setWriteBufferEnabled: NO];

	if (requestType == OF_HTTP_REQUEST_TYPE_POST)
		[sock writeBuffer: [POSTData cArray]
		[sock writeBuffer: [POSTData items]
			   length: [POSTData count] * [POSTData itemSize]];

	@try {
		line = [sock readLine];
	} @catch (OFInvalidEncodingException *e) {
		@throw [OFInvalidServerReplyException
		    exceptionWithClass: [self class]];
403
404
405
406
407
408
409
410
411


412
413
414
415
416
417
418
403
404
405
406
407
408
409


410
411
412
413
414
415
416
417
418







-
-
+
+







						  length: length
						 request: request];

					objc_autoreleasePoolPop(pool2);
					pool2 = objc_autoreleasePoolPush();

					bytesReceived += length;
					[data addItemsFromCArray: buffer
							   count: length];
					[data addItems: buffer
						 count: length];

					toRead -= length;
				}

				@try {
					line = [sock readLine];
				} @catch (OFInvalidEncodingException *e) {
441
442
443
444
445
446
447
448
449


450
451
452
453
454
455
456
441
442
443
444
445
446
447


448
449
450
451
452
453
454
455
456







-
-
+
+







				  didReceiveData: buffer
					  length: length
					 request: request];

				objc_autoreleasePoolPop(pool2);

				bytesReceived += length;
				[data addItemsFromCArray: buffer
						   count: length];
				[data addItems: buffer
					 count: length];

				if (contentLengthHeader != nil &&
				    bytesReceived >= contentLength)
					break;
			}
		}
	} @finally {

Modified src/OFHTTPServer.m from [e6f92f7b1d] to [61524a3f46].

396
397
398
399
400
401
402
403
404


405
406
407
408
409
410
411
396
397
398
399
400
401
402


403
404
405
406
407
408
409
410
411







-
-
+
+







  didReadIntoBuffer: (const char*)buffer
	     length: (size_t)length
	  exception: (OFException*)exception
{
	if ([sock_ isAtEndOfStream] || exception != nil)
		return NO;

	[POSTData addItemsFromCArray: buffer
			       count: length];
	[POSTData addItems: buffer
		     count: length];

	if ([POSTData count] >= contentLength) {
		@try {
			[self sendReply];
		} @catch (OFWriteFailedException *e) {
			return NO;
		}
497
498
499
500
501
502
503
504

505
506
507
508
509
510
511
497
498
499
500
501
502
503

504
505
506
507
508
509
510
511







-
+







	while ((key = [keyEnumerator nextObject]) != nil &&
	    (value = [valueEnumerator nextObject]) != nil)
		[sock writeFormat: @"%@: %@\r\n", key, value];

	[sock writeString: @"\r\n"];

	if (requestType != OF_HTTP_REQUEST_TYPE_HEAD)
		[sock writeBuffer: [replyData cArray]
		[sock writeBuffer: [replyData items]
			   length: [replyData count] * [replyData itemSize]];
}
@end

@implementation OFHTTPServer
+ (instancetype)server
{

Modified src/OFMD5Hash.h from [b8a9b23fd3] to [569dd9f1c4].

12
13
14
15
16
17
18
19

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

19
20
21
22
23
24
25
26







-
+







 * 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 "OFHash.h"

#define OF_MD5_DIGEST_SIZE  16
#define OF_MD5_DIGEST_SIZE 16

/*!
 * @brief A class which provides functions to create an MD5 hash.
 */
@interface OFMD5Hash: OFHash
{
	uint32_t buffer[4];

Modified src/OFMutableArray_adjacent.m from [b75900fe79] to [f345fceab0].

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







-
-
-
+
+
+

















-
+








- (void)insertObjectsFromArray: (OFArray*)array_
		       atIndex: (size_t)index
{
	id *objects = [array_ objects];
	size_t i, count = [array_ count];

	[array insertItemsFromCArray: objects
			     atIndex: index
			       count: count];
	[array insertItems: objects
		   atIndex: index
		     count: count];

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

	mutations++;
}

- (void)replaceObject: (id)oldObject
	   withObject: (id)newObject
{
	id *objects;
	size_t i, count;

	if (oldObject == nil || newObject == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]];

	objects = [array cArray];
	objects = [array items];
	count = [array count];

	for (i = 0; i < count; i++) {
		if ([objects[i] isEqual: oldObject]) {
			[newObject retain];
			[objects[i] release];
			objects[i] = newObject;
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
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







-
+



















-
+







	id *objects;
	id oldObject;

	if (object == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]];

	objects = [array cArray];
	objects = [array items];

	if (index >= [array count])
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	oldObject = objects[index];
	objects[index] = [object retain];
	[oldObject release];
}

- (void)replaceObjectIdenticalTo: (id)oldObject
		      withObject: (id)newObject
{
	id *objects;
	size_t i, count;

	if (oldObject == nil || newObject == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]];

	objects = [array cArray];
	objects = [array items];
	count = [array count];

	for (i = 0; i < count; i++) {
		if (objects[i] == oldObject) {
			[newObject retain];
			[objects[i] release];
			objects[i] = newObject;
148
149
150
151
152
153
154
155

156
157
158
159
160
161
162
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162







-
+







	id *objects;
	size_t i, count;

	if (object == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]];

	objects = [array cArray];
	objects = [array items];
	count = [array count];

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

			[array removeItemAtIndex: i];
174
175
176
177
178
179
180
181

182
183
184
185
186
187
188
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188







-
+







	id *objects;
	size_t i, count;

	if (object == nil)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]];

	objects = [array cArray];
	objects = [array items];
	count = [array count];

	for (i = 0; i < count; i++) {
		if (objects[i] == object) {
			[array removeItemAtIndex: i];
			mutations++;

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







-
+










-
+







	[object release];

	mutations++;
}

- (void)removeAllObjects
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];

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

	[array removeAllItems];
}

- (void)removeObjectsInRange: (of_range_t)range
{
	id *objects = [array cArray], *copy;
	id *objects = [array items], *copy;
	size_t i, count = [array count];

	if (range.length > SIZE_MAX - range.location ||
	    range.length > count - range.location)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

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







-
+













-
+








	mutations++;
}

- (void)exchangeObjectAtIndex: (size_t)index1
	    withObjectAtIndex: (size_t)index2
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t count = [array count];
	id tmp;

	if (index1 >= count || index2 >= count)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];

	tmp = objects[index1];
	objects[index1] = objects[index2];
	objects[index2] = tmp;
}

- (void)reverse
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, j, count = [array count];

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

	for (i = 0, j = count - 1; i < j; i++, j--) {
		id tmp = objects[i];
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
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







-
+
















-
+







	    initWithArray: self
	     mutationsPtr: &mutations] autorelease];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];
	BOOL stop = NO;
	unsigned long mutations_ = mutations;

	for (i = 0; i < count && !stop; i++) {
		if (mutations != mutations_)
			@throw [OFEnumerationMutationException
			    exceptionWithClass: [self class]
					object: self];

		block(objects[i], i, &stop);
	}
}

- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block
{
	id *objects = [array cArray];
	id *objects = [array items];
	size_t i, count = [array count];
	BOOL stop = NO;
	unsigned long mutations_ = mutations;

	for (i = 0; i < count && !stop; i++) {
		id newObject;

Modified src/OFStream.m from [cea01024de] to [c1d9e7762b].

496
497
498
499
500
501
502
503
504


505
506
507
508
509
510
511
496
497
498
499
500
501
502


503
504
505
506
507
508
509
510
511







-
-
+
+







	tmp = [self allocMemoryWithSize: itemSize
				  count: count];

	@try {
		[self readIntoBuffer: tmp
			 exactLength: count * itemSize];

		[dataArray addItemsFromCArray: tmp
					count: count];
		[dataArray addItems: tmp
			      count: count];
	} @finally {
		[self freeMemory: tmp];
	}

	return dataArray;
}

519
520
521
522
523
524
525
526
527


528
529
530
531
532
533
534
519
520
521
522
523
524
525


526
527
528
529
530
531
532
533
534







-
-
+
+








	@try {
		while (![self isAtEndOfStream]) {
			size_t length;

			length = [self readIntoBuffer: buffer
					       length: of_pagesize];
			[dataArray addItemsFromCArray: buffer
						count: length];
			[dataArray addItems: buffer
				      count: length];
		}
	} @finally {
		[self freeMemory: buffer];
	}

	return dataArray;
}
1353
1354
1355
1356
1357
1358
1359
1360

1361
1362
1363

1364
1365
1366
1367
1368
1369
1370
1353
1354
1355
1356
1357
1358
1359

1360
1361
1362

1363
1364
1365
1366
1367
1368
1369
1370







-
+


-
+







	return size;
}

- (size_t)writeDataArray: (OFDataArray*)dataArray
{
	size_t length = [dataArray count] * [dataArray itemSize];

	[self writeBuffer: [dataArray cArray]
	[self writeBuffer: [dataArray items]
		   length: length];

	return [dataArray count] * [dataArray itemSize];
	return length;
}

- (size_t)writeString: (OFString*)string
{
	size_t length = [string UTF8StringLength];

	[self writeBuffer: [string UTF8String]

Modified src/OFStreamObserver.m from [f18e106529] to [0c778cd456].

289
290
291
292
293
294
295
296
297


298
299
300
301
302
303


304
305
306
307
308
309
310
289
290
291
292
293
294
295


296
297
298
299
300
301


302
303
304
305
306
307
308
309
310







-
-
+
+




-
-
+
+







}

- (void)OF_processQueue
{
	[mutex lock];
	@try {
		OFStream **queueObjects = [queue objects];
		int *queueInfoCArray = [queueInfo cArray];
		int *queueFDsCArray = [queueFDs cArray];
		int *queueInfoItems = [queueInfo items];
		int *queueFDsItems = [queueFDs items];
		size_t i, count = [queue count];

		for (i = 0; i < count; i++) {
			OFStream *stream = queueObjects[i];
			int action = queueInfoCArray[i];
			int fd = queueFDsCArray[i];
			int action = queueInfoItems[i];
			int fd = queueFDsItems[i];

			if ((action & QUEUE_ACTION) == QUEUE_ADD) {
				if (fd > maxFD) {
					maxFD = fd;
					FDToStream = [self
					    resizeMemory: FDToStream
						    size: sizeof(OFStream*)

Modified src/OFStreamObserver_kqueue.m from [1e1bf29b71] to [c9bbb01ae1].

120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134







-
+







	if ([self OF_processCache]) {
		objc_autoreleasePoolPop(pool);
		return YES;
	}

	objc_autoreleasePoolPop(pool);

	events = kevent(kernelQueue, [changeList cArray],
	events = kevent(kernelQueue, [changeList items],
	    (int)[changeList count], eventList, EVENTLIST_SIZE,
	    (timeout == -1 ? NULL : &timespec));

	if (events == -1) {
		switch (errno) {
		case EINTR:
			return NO;

Modified src/OFStreamObserver_poll.m from [ca9d956364] to [c07acfe92a].

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







-
+




-
-
+
+














-
+



-
-
+
+

-
+








	[super dealloc];
}

- (void)OF_addFileDescriptor: (int)fd
		  withEvents: (short)events
{
	struct pollfd *FDsCArray = [FDs cArray];
	struct pollfd *FDs_ = [FDs items];
	size_t i, count = [FDs count];
	BOOL found = NO;

	for (i = 0; i < count; i++) {
		if (FDsCArray[i].fd == fd) {
			FDsCArray[i].events |= events;
		if (FDs_[i].fd == fd) {
			FDs_[i].events |= events;
			found = YES;
			break;
		}
	}

	if (!found) {
		struct pollfd p = { fd, events | POLLERR, 0 };
		[FDs addItem: &p];
	}
}

- (void)OF_removeFileDescriptor: (int)fd
		     withEvents: (short)events
{
	struct pollfd *FDsCArray = [FDs cArray];
	struct pollfd *FDs_ = [FDs items];
	size_t i, nFDs = [FDs count];

	for (i = 0; i < nFDs; i++) {
		if (FDsCArray[i].fd == fd) {
			FDsCArray[i].events &= ~events;
		if (FDs_[i].fd == fd) {
			FDs_[i].events &= ~events;

			if ((FDsCArray[i].events & ~POLLERR) == 0)
			if ((FDs_[i].events & ~POLLERR) == 0)
				[FDs removeItemAtIndex: i];

			break;
		}
	}
}

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







-
+











-
+







-
+






-
-
+
+



-
+







-
+


-
+


-
+


-
+


-
+


-
+










	[self OF_removeFileDescriptor: fd
			   withEvents: POLLOUT];
}

- (BOOL)observeWithTimeout: (double)timeout
{
	void *pool = objc_autoreleasePoolPush();
	struct pollfd *FDsCArray;
	struct pollfd *FDs_;
	size_t i, nFDs, realEvents = 0;

	[self OF_processQueue];

	if ([self OF_processCache]) {
		objc_autoreleasePoolPop(pool);
		return YES;
	}

	objc_autoreleasePoolPop(pool);

	FDsCArray = [FDs cArray];
	FDs_ = [FDs items];
	nFDs = [FDs count];

#ifdef OPEN_MAX
	if (nFDs > OPEN_MAX)
		@throw [OFOutOfRangeException exceptionWithClass: [self class]];
#endif

	if (poll(FDsCArray, (nfds_t)nFDs,
	if (poll(FDs_, (nfds_t)nFDs,
	    (int)(timeout != -1 ? timeout * 1000 : -1)) < 1)
		return NO;

	for (i = 0; i < nFDs; i++) {
		pool = objc_autoreleasePoolPush();

		if (FDsCArray[i].revents & POLLIN) {
			if (FDsCArray[i].fd == cancelFD[0]) {
		if (FDs_[i].revents & POLLIN) {
			if (FDs_[i].fd == cancelFD[0]) {
				char buffer;

				OF_ENSURE(read(cancelFD[0], &buffer, 1) > 0);
				FDsCArray[i].revents = 0;
				FDs_[i].revents = 0;

				objc_autoreleasePoolPop(pool);
				continue;
			}

			realEvents++;
			[delegate streamIsReadyForReading:
			    FDToStream[FDsCArray[i].fd]];
			    FDToStream[FDs_[i].fd]];
		}

		if (FDsCArray[i].revents & POLLOUT) {
		if (FDs_[i].revents & POLLOUT) {
			realEvents++;
			[delegate streamIsReadyForWriting:
			    FDToStream[FDsCArray[i].fd]];
			    FDToStream[FDs_[i].fd]];
		}

		if (FDsCArray[i].revents & POLLERR) {
		if (FDs_[i].revents & POLLERR) {
			realEvents++;
			[delegate streamDidReceiveException:
			    FDToStream[FDsCArray[i].fd]];
			    FDToStream[FDs_[i].fd]];
		}

		FDsCArray[i].revents = 0;
		FDs_[i].revents = 0;

		objc_autoreleasePoolPop(pool);
	}

	if (realEvents == 0)
		return NO;

	return YES;
}
@end

Modified src/OFString.m from [90ef2353c5] to [712053e8f6].

779
780
781
782
783
784
785
786

787
788
789
790
791
792
793
779
780
781
782
783
784
785

786
787
788
789
790
791
792
793







-
+







		if ([contentType hasSuffix: @"charset=windows-1252"])
			encoding = OF_STRING_ENCODING_WINDOWS_1252;
	}

	if (encoding == OF_STRING_ENCODING_AUTODETECT)
		encoding = OF_STRING_ENCODING_UTF_8;

	self = [[c alloc] initWithCString: (char*)[[result data] cArray]
	self = [[c alloc] initWithCString: (char*)[[result data] items]
				 encoding: encoding
				   length: [[result data] count]];

	objc_autoreleasePoolPop(pool);
	return self;
}

Modified src/OFXMLElement.m from [177c46b1d0] to [16ca049b3f].

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







-
-
+
+

















-
+







					       indentation: ind
						     level: level + 1];
			else
				child = [childrenObjects[j]
				    XMLStringWithIndentation: ind
						       level: level + 1];

			[tmp addItemsFromCArray: [child UTF8String]
					  count: [child UTF8StringLength]];
			[tmp addItems: [child UTF8String]
				count: [child UTF8StringLength]];
		}

		if (indent)
			[tmp addItem: "\n"];

		length += [tmp count] + [name UTF8StringLength] + 2 +
		    (indent ? level * indentation : 0);
		@try {
			cString = [self resizeMemory: cString
						size: length];
		} @catch (id e) {
			[self freeMemory: cString];
			@throw e;
		}

		cString[i++] = '>';

		memcpy(cString + i, [tmp cArray], [tmp count]);
		memcpy(cString + i, [tmp items], [tmp count]);
		i += [tmp count];

		if (indent) {
			memset(cString + i, ' ', level * indentation);
			i += level * indentation;
		}

Modified src/OFXMLParser.m from [c33143cf90] to [4543342dd4].

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







-
-
+
+





-
-
+
+








-
+




-
+



-
-
+
+

-
+




-
-
+
+



-
+







static state_function lookupTable[OF_XMLPARSER_NUM_STATES];

static OF_INLINE void
cache_append(OFDataArray *cache, const char *string,
    of_string_encoding_t encoding, size_t length)
{
	if (OF_LIKELY(encoding == OF_STRING_ENCODING_UTF_8))
		[cache addItemsFromCArray: string
				    count: length];
		[cache addItems: string
			  count: length];
	else {
		void *pool = objc_autoreleasePoolPush();
		OFString *tmp = [OFString stringWithCString: string
						   encoding: encoding
						     length: length];
		[cache addItemsFromCArray: [tmp UTF8String]
				    count: [tmp UTF8StringLength]];
		[cache addItems: [tmp UTF8String]
			  count: [tmp UTF8StringLength]];
		objc_autoreleasePoolPop(pool);
	}
}

static OFString*
transform_string(OFDataArray *cache, size_t cut, BOOL unescape,
    id <OFStringXMLUnescapingDelegate> delegate)
{
	char *cArray;
	char *items;
	size_t i, length;
	BOOL hasEntities = NO;
	OFMutableString *ret;

	cArray = [cache cArray];
	items = [cache items];
	length = [cache count] - cut;

	for (i = 0; i < length; i++) {
		if (cArray[i] == '\r') {
			if (i + 1 < length && cArray[i + 1] == '\n') {
		if (items[i] == '\r') {
			if (i + 1 < length && items[i + 1] == '\n') {
				[cache removeItemAtIndex: i];
				cArray = [cache cArray];
				items = [cache items];

				i--;
				length--;
			} else
				cArray[i] = '\n';
		} else if (cArray[i] == '&')
				items[i] = '\n';
		} else if (items[i] == '&')
			hasEntities = YES;
	}

	ret = [OFMutableString stringWithUTF8String: cArray
	ret = [OFMutableString stringWithUTF8String: items
					     length: length];

	if (unescape && hasEntities)
		return [ret stringByXMLUnescapingWithDelegate: delegate];

	[ret makeImmutable];

533
534
535
536
537
538
539
540

541
542
543
544
545
546
547
533
534
535
536
537
538
539

540
541
542
543
544
545
546
547







-
+







		return;

	if ((length = *i - *last) > 0)
		cache_append(cache, buffer + *last, encoding, length);

	pool = objc_autoreleasePoolPush();

	cacheCString = [cache cArray];
	cacheCString = [cache items];
	cacheLength = [cache count];
	cacheString = [OFString stringWithUTF8String: cacheCString
					      length: cacheLength];

	if ((tmp = memchr(cacheCString, ':', cacheLength)) != NULL) {
		name = [[OFString alloc]
		    initWithUTF8String: tmp + 1
616
617
618
619
620
621
622
623

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

623
624
625
626
627
628
629
630







-
+







		return;

	if ((length = *i - *last) > 0)
		cache_append(cache, buffer + *last, encoding, length);

	pool = objc_autoreleasePoolPush();

	cacheCString = [cache cArray];
	cacheCString = [cache items];
	cacheLength = [cache count];
	cacheString = [OFString stringWithUTF8String: cacheCString
					      length: cacheLength];

	if ((tmp = memchr(cacheCString, ':', cacheLength)) != NULL) {
		name = [[OFString alloc]
		    initWithUTF8String: tmp + 1
759
760
761
762
763
764
765
766

767
768
769
770
771
772
773
759
760
761
762
763
764
765

766
767
768
769
770
771
772
773







-
+







		return;

	if ((length = *i - *last) > 0)
		cache_append(cache, buffer + *last, encoding, length);

	pool = objc_autoreleasePoolPush();

	cacheString = [OFMutableString stringWithUTF8String: [cache cArray]
	cacheString = [OFMutableString stringWithUTF8String: [cache items]
						     length: [cache count]];
	[cacheString deleteEnclosingWhitespaces];
	/* Prevent a useless copy later */
	[cacheString makeImmutable];

	cacheCString = [cacheString UTF8String];
	cacheLength = [cacheString UTF8StringLength];

Modified src/base64.m from [9c1fb17538] to [c2598ccd38].

146
147
148
149
150
151
152
153
154


155
156
157
158
146
147
148
149
150
151
152


153
154
155
156
157
158







-
-
+
+





		sb |= tmp;

		db[0] = (sb & 0xFF0000) >> 16;
		db[1] = (sb & 0x00FF00) >> 8;
		db[2] = sb & 0x0000FF;

		[data addItemsFromCArray: db
				   count: count];
		[data addItems: db
			 count: count];
	}

	return YES;
}

Modified tests/OFDataArrayTests.m from [eae28a70a3] to [6c7d01470b].

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







-
-
+
+




















-
-
+
+



-
+



-
+

-
-
-
-
-
+
+
+
+
+










-
+



-
-
-
+
+
+




-
+
-
-
-
+
+








	TEST(@"-[count]", [array[0] count] == 2)

	other = (class == [OFDataArray class]
	    ? [OFBigDataArray class]
	    : [OFDataArray class]);
	TEST(@"-[isEqual:]", (array[1] = [other dataArrayWithItemSize: 4096]) &&
	    R([array[1] addItemsFromCArray: [array[0] cArray]
				     count: [array[0] count]]) &&
	    R([array[1] addItems: [array[0] items]
			   count: [array[0] count]]) &&
	    [array[1] isEqual: array[0]] &&
	    R([array[1] removeLastItem]) && ![array[0] isEqual: array[1]])

	TEST(@"-[copy]", (array[1] = [[array[0] copy] autorelease]) &&
	    [array[0] isEqual: array[1]])

	array[2] = [OFDataArray dataArray];
	array[3] = [OFDataArray dataArray];
	[array[2] addItem: "a"];
	[array[2] addItem: "a"];
	[array[3] addItem: "z"];
	TEST(@"-[compare]", [array[0] compare: array[1]] == 0 &&
	    R([array[1] removeLastItem]) &&
	    [array[0] compare: array[1]] == OF_ORDERED_DESCENDING &&
	    [array[1] compare: array[0]] == OF_ORDERED_ASCENDING &&
	    [array[2] compare: array[3]] == OF_ORDERED_ASCENDING)

	TEST(@"-[hash]", [array[0] hash] == 0x634A529F)

	array[0] = [class dataArray];
	[array[0] addItemsFromCArray: "abcdef"
			       count: 6];
	[array[0] addItems: "abcdef"
		     count: 6];

	TEST(@"-[removeLastItem]", R([array[0] removeLastItem]) &&
	    [array[0] count] == 5 &&
	    !memcmp([array[0] cArray], "abcde", 5))
	    !memcmp([array[0] items], "abcde", 5))

	TEST(@"-[removeItemsInRange:]",
	    R([array[0] removeItemsInRange: of_range(1, 2)]) &&
	    [array[0] count] == 3 && !memcmp([array[0] cArray], "ade", 3))
	    [array[0] count] == 3 && !memcmp([array[0] items], "ade", 3))

	TEST(@"-[insertItemsFromCArray:atIndex:count:]",
	    R([array[0] insertItemsFromCArray: "bc"
				      atIndex: 1
					count: 2]) && [array[0] count] == 5 &&
	    !memcmp([array[0] cArray], "abcde", 5))
	TEST(@"-[insertItems:atIndex:count:]",
	    R([array[0] insertItems: "bc"
			    atIndex: 1
			      count: 2]) && [array[0] count] == 5 &&
	    !memcmp([array[0] items], "abcde", 5))

	TEST(@"-[MD5Hash]", [[array[0] MD5Hash] isEqual: [@"abcde" MD5Hash]])

	TEST(@"-[SHA1Hash]", [[array[0] SHA1Hash] isEqual: [@"abcde" SHA1Hash]])

	TEST(@"-[stringByBase64Encoding]",
	    [[array[0] stringByBase64Encoding] isEqual: @"YWJjZGU="])

	TEST(@"+[dataArrayWithBase64EncodedString:]",
	    !memcmp([[class dataArrayWithBase64EncodedString: @"YWJjZGU="]
	    cArray], "abcde", 5))
	    items], "abcde", 5))

	TEST(@"Building strings",
	    (array[0] = [class dataArray]) &&
	    R([array[0] addItemsFromCArray: (void*)str
				     count: 6]) && R([array[0] addItem: ""]) &&
	    !strcmp([array[0] cArray], str))
	    R([array[0] addItems: (void*)str
			   count: 6]) && R([array[0] addItem: ""]) &&
	    !strcmp([array[0] items], str))

	EXPECT_EXCEPTION(@"Detect out of range in -[itemAtIndex:]",
	    OFOutOfRangeException, [array[0] itemAtIndex: [array[0] count]])

	EXPECT_EXCEPTION(@"Detect out of range in "
	EXPECT_EXCEPTION(@"Detect out of range in -[addItems:count:]",
	    @"-[addItemsFromCArray:count:]",
	    OFOutOfRangeException, [array[0] addItemsFromCArray: NULL
							  count: SIZE_MAX])
	    OFOutOfRangeException, [array[0] addItems: NULL
						count: SIZE_MAX])

	EXPECT_EXCEPTION(@"Detect out of range in -[removeItemsInRange:]",
	    OFOutOfRangeException,
	    [array[0] removeItemsInRange: of_range([array[0] count], 1)])
}

- (void)dataArrayTests

Modified tests/OFSerializationTests.m from [cf7d67e102] to [61f9a15e64].

63
64
65
66
67
68
69
70
71


72
73
74
75
76
77
78
79
80
81
82
83
84
63
64
65
66
67
68
69


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







-
-
+
+













	[l appendObject: [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]];
	[l appendObject:
	    [OFCountedSet setWithObjects: @"foo", @"foo", @"bar", nil]];

	[d setObject: @"list"
	      forKey: l];

	[da addItemsFromCArray: "0123456789:;<ABCDEFGHJIKLMNOPQRSTUVWXYZ"
			 count: 39];
	[da addItems: "0123456789:;<ABCDEFGHJIKLMNOPQRSTUVWXYZ"
	       count: 39];
	[d setObject: @"data"
	      forKey: da];

	TEST(@"-[stringBySerializing]",
	    (s = [d stringBySerializing]) && [s isEqual:
	    [OFString stringWithContentsOfFile: @"serialization.xml"]])

	TEST(@"-[objectByDeserializing]",
	    [[s objectByDeserializing] isEqual: d])

	[pool drain];
}
@end