ObjFW  Check-in [7cddd5f891]

Overview
Comment:OFString: Add methods for UTF-32.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7cddd5f891be8c029dfd7bc5f3c08b0fa132ccc74673be301a57a7264294b957
User & Date: js on 2013-01-08 12:33:53
Other Links: manifest | tags
Context
2013-01-09
22:10
OFTCPSocket: Set ai_flags. check-in: 541b33d978 user: js tags: trunk
2013-01-08
12:33
OFString: Add methods for UTF-32. check-in: 7cddd5f891 user: js tags: trunk
03:41
OFProcess: Kill the process in -[close]. check-in: 382e89a033 user: js tags: trunk
Changes

Modified src/OFString.h from [31ec44e41b] to [4892881708].

201
202
203
204
205
206
207



















208
209
210
211
212
213
214
 * @param byteOrder The byte order to assume if there is no BOM
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF16String: (const uint16_t*)string
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)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.
 *
 * @param format A string used as format to initialize the OFString







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
 * @param byteOrder The byte order to assume if there is no BOM
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF16String: (const uint16_t*)string
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)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 uint32_t*)string;

/*!
 * @brief Creates a new OFString from a UTF-32 encoded string, assuming the
 *	  specified byte order if no BOM is found.
 *
 * @param string The UTF-32 string
 * @param byteOrder The byte order to assume if there is no BOM
 * @return A new autoreleased OFString
 */
+ (instancetype)stringWithUTF32String: (const uint32_t*)string
			    byteOrder: (of_byte_order_t)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.
 *
 * @param format A string used as format to initialize the OFString
400
401
402
403
404
405
406



















407
408
409
410
411
412
413
 * @param byteOrder The byte order to assume if there is no BOM
 * @return An initialized OFString
 */
- initWithUTF16String: (const uint16_t*)string
	       length: (size_t)length
	    byteOrder: (of_byte_order_t)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.
 *
 * @param format A string used as format to initialize the OFString







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
 * @param byteOrder The byte order to assume if there is no BOM
 * @return An initialized OFString
 */
- initWithUTF16String: (const uint16_t*)string
	       length: (size_t)length
	    byteOrder: (of_byte_order_t)byteOrder;

/*!
 * @brief Initializes an already allocated OFString with a UTF-32 string.
 *
 * @param string The UTF-32 string
 * @return An initialized OFString
 */
- initWithUTF32String: (const uint32_t*)string;

/*!
 * @brief Initializes an already allocated OFString with a UTF-32 string,
 *	  assuming the specified byte order if no BOM is found.
 *
 * @param string The UTF-32 string
 * @param byteOrder The byte order to assume if there is no BOM
 * @return An initialized OFString
 */
- initWithUTF32String: (const uint32_t*)string
	    byteOrder: (of_byte_order_t)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.
 *
 * @param format A string used as format to initialize the OFString
900
901
902
903
904
905
906
























907
908
909
910
911
912
913
/*!
 * @brief Returns the length of the string in UTF-16 characters.
 *
 * @return The length of string in UTF-16 characters
 */
- (size_t)UTF16StringLength;

























/*!
 * @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;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
/*!
 * @brief Returns the length of the string in UTF-16 characters.
 *
 * @return The length of string in UTF-16 characters
 */
- (size_t)UTF16StringLength;

/*!
 * @brief Returns 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.
 *
 * @return The string in UTF-32 encoding with native byte order
 */
- (const of_unichar_t*)UTF32String 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_unichar_t*)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
    OF_RETURNS_INNER_POINTER;

/*!
 * @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;

937
938
939
940
941
942
943

944
945
946

#ifdef __cplusplus
extern "C" {
#endif
extern size_t of_string_utf8_encode(of_unichar_t, char*);
extern size_t of_string_utf8_decode(const char*, size_t, of_unichar_t*);
extern size_t of_string_utf16_length(const uint16_t*);

#ifdef __cplusplus
}
#endif







>



999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009

#ifdef __cplusplus
extern "C" {
#endif
extern size_t of_string_utf8_encode(of_unichar_t, char*);
extern size_t of_string_utf8_decode(const char*, size_t, of_unichar_t*);
extern size_t of_string_utf16_length(const uint16_t*);
extern size_t of_string_utf32_length(const uint32_t*);
#ifdef __cplusplus
}
#endif

Modified src/OFString.m from [6044846057] to [2ad39db524].

148
149
150
151
152
153
154











155
156
157
158
159
160
161
	size_t length = 0;

	while (*string++ != 0)
		length++;

	return length;
}












static OFString*
standardize_path(OFArray *components, OFString *currentDirectory,
    OFString *parentDirectory, OFString *joinString)
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableArray *array;







>
>
>
>
>
>
>
>
>
>
>







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
	size_t length = 0;

	while (*string++ != 0)
		length++;

	return length;
}

size_t
of_string_utf32_length(const uint32_t *string)
{
	size_t length = 0;

	while (*string++ != 0)
		length++;

	return length;
}

static OFString*
standardize_path(OFArray *components, OFString *currentDirectory,
    OFString *parentDirectory, OFString *joinString)
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableArray *array;
335
336
337
338
339
340
341












342
343
344
345
346
347
348
	       length: (size_t)length
	    byteOrder: (of_byte_order_t)byteOrder
{
	return (id)[[OFString_UTF8 alloc] initWithUTF16String: string
						       length: length
						    byteOrder: byteOrder];
}













- initWithFormat: (OFConstantString*)format, ...
{
	id ret;
	va_list arguments;

	va_start(arguments, format);







>
>
>
>
>
>
>
>
>
>
>
>







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
	       length: (size_t)length
	    byteOrder: (of_byte_order_t)byteOrder
{
	return (id)[[OFString_UTF8 alloc] initWithUTF16String: string
						       length: length
						    byteOrder: byteOrder];
}

- initWithUTF32String: (const uint32_t*)string
{
	return (id)[[OFString_UTF8 alloc] initWithUTF32String: string];
}

- initWithUTF32String: (const uint32_t*)string
	    byteOrder: (of_byte_order_t)byteOrder
{
	return (id)[[OFString_UTF8 alloc] initWithUTF32String: string
						    byteOrder: byteOrder];
}

- initWithFormat: (OFConstantString*)format, ...
{
	id ret;
	va_list arguments;

	va_start(arguments, format);
534
535
536
537
538
539
540












541
542
543
544
545
546
547
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)byteOrder
{
	return [[[self alloc] initWithUTF16String: string
					   length: length
					byteOrder: byteOrder] autorelease];
}













+ (instancetype)stringWithFormat: (OFConstantString*)format, ...
{
	id ret;
	va_list arguments;

	va_start(arguments, format);







>
>
>
>
>
>
>
>
>
>
>
>







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
			       length: (size_t)length
			    byteOrder: (of_byte_order_t)byteOrder
{
	return [[[self alloc] initWithUTF16String: string
					   length: length
					byteOrder: byteOrder] autorelease];
}

+ (instancetype)stringWithUTF32String: (const uint32_t*)string
{
	return [[[self alloc] initWithUTF32String: string] autorelease];
}

+ (instancetype)stringWithUTF32String: (const uint32_t*)string
			    byteOrder: (of_byte_order_t)byteOrder
{
	return [[[self alloc] initWithUTF32String: string
					byteOrder: byteOrder] autorelease];
}

+ (instancetype)stringWithFormat: (OFConstantString*)format, ...
{
	id ret;
	va_list arguments;

	va_start(arguments, format);
709
710
711
712
713
714
715















716
717
718
719
720
721
722
		[self doesNotRecognizeSelector: _cmd];
		abort();
	} @catch (id e) {
		[self release];
		@throw e;
	}
}
















- initWithFormat: (OFConstantString*)format, ...
{
	id ret;
	va_list arguments;

	va_start(arguments, format);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
		[self doesNotRecognizeSelector: _cmd];
		abort();
	} @catch (id e) {
		[self release];
		@throw e;
	}
}

- initWithUTF32String: (const uint32_t*)string
{
	return [self initWithCharacters: string
				 length: of_string_utf32_length(string)
			      byteOrder: OF_BYTE_ORDER_NATIVE];
}

- initWithUTF32String: (const uint32_t*)string
	    byteOrder: (of_byte_order_t)byteOrder
{
	return [self initWithCharacters: string
				 length: of_string_utf32_length(string)
			      byteOrder: byteOrder];
}

- initWithFormat: (OFConstantString*)format, ...
{
	id ret;
	va_list arguments;

	va_start(arguments, format);
2114
2115
2116
2117
2118
2119
2120



























2121
2122
2123
2124
2125
2126
2127

	for (i = 0; i < length; i++)
		if (characters[i] > 0xFFFF)
			UTF16StringLength++;

	return UTF16StringLength;
}




























- (void)writeToFile: (OFString*)path
{
	void *pool = objc_autoreleasePoolPush();
	OFFile *file;

	file = [OFFile fileWithPath: path







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204

	for (i = 0; i < length; i++)
		if (characters[i] > 0xFFFF)
			UTF16StringLength++;

	return UTF16StringLength;
}

- (const of_unichar_t*)UTF32String
{
	return [self UTF32StringWithByteOrder: OF_BYTE_ORDER_NATIVE];
}

- (const of_unichar_t*)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
{
	OFObject *object = [[[OFObject alloc] init] autorelease];
	size_t length = [self length];
	of_unichar_t *ret;

	ret = [object allocMemoryWithSize: sizeof(of_unichar_t)
				    count: length + 1];
	[self getCharacters: ret
		    inRange: of_range(0, length)];
	ret[length] = 0;

	if (byteOrder != OF_BYTE_ORDER_NATIVE) {
		size_t i;

		for (i = 0; i < length; i++)
			ret[i] = OF_BSWAP32(ret[i]);
	}

	return ret;
}

- (void)writeToFile: (OFString*)path
{
	void *pool = objc_autoreleasePoolPush();
	OFFile *file;

	file = [OFFile fileWithPath: path

Modified src/OFString_UTF8.m from [0ddb5e507a] to [c7327619e7].

527
528
529
530
531
532
533





534
535
536
537
538
539
540
				if (length <= i + 1)
					@throw [OFInvalidEncodingException
					    exceptionWithClass: [self class]];

				nextCharacter = (swap
				    ? OF_BSWAP16(string[i + 1])
				    : string[i + 1]);





				character = (((character & 0x3FF) << 10) |
				    (nextCharacter & 0x3FF)) + 0x10000;

				i++;
				s->cStringLength--;
				s->length--;
			}







>
>
>
>
>







527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
				if (length <= i + 1)
					@throw [OFInvalidEncodingException
					    exceptionWithClass: [self class]];

				nextCharacter = (swap
				    ? OF_BSWAP16(string[i + 1])
				    : string[i + 1]);

				if ((nextCharacter & 0xFC00) != 0xDC00)
					@throw [OFInvalidEncodingException
					    exceptionWithClass: [self class]];

				character = (((character & 0x3FF) << 10) |
				    (nextCharacter & 0x3FF)) + 0x10000;

				i++;
				s->cStringLength--;
				s->length--;
			}
1268
1269
1270
1271
1272
1273
1274


































1275
1276
1277
1278
1279
1280
1281
		if (cLen == 0 || c > 0x10FFFF)
			@throw [OFInvalidEncodingException
			    exceptionWithClass: [self class]];

		ret[j++] = c;
		i += cLen;
	}



































	return ret;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
{







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
		if (cLen == 0 || c > 0x10FFFF)
			@throw [OFInvalidEncodingException
			    exceptionWithClass: [self class]];

		ret[j++] = c;
		i += cLen;
	}

	return ret;
}

- (const of_unichar_t*)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder
{
	OFObject *object = [[[OFObject alloc] init] autorelease];
	of_unichar_t *ret;
	size_t i, j;

	ret = [object allocMemoryWithSize: sizeof(of_unichar_t)
				    count: s->length + 1];

	i = j = 0;

	while (i < s->cStringLength) {
		of_unichar_t c;
		size_t cLen;

		cLen = of_string_utf8_decode(s->cString + i,
		    s->cStringLength - i, &c);

		if (cLen == 0 || c > 0x10FFFF)
			@throw [OFInvalidEncodingException
			    exceptionWithClass: [self class]];

		if (byteOrder != OF_BYTE_ORDER_NATIVE)
			ret[j++] = OF_BSWAP32(c);
		else
			ret[j++] = c;

		i += cLen;
	}
	ret[j] = 0;

	return ret;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block
{

Modified tests/OFStringTests.m from [7f9159fd57] to [1701ed672c].

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

static OFString *module = @"OFString";
static OFString* whitespace[] = {
	@" \r \t\n\t \tasd  \t \t\t\r\n",
	@" \t\t  \t\t  \t \t"
};
static of_unichar_t ucstr[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A
};
static of_unichar_t sucstr[] = {
	0xFFFE0000, 0x66000000, 0xF6000000, 0xF6000000, 0x62000000, 0xE4000000,
	0x72000000, 0x3AF00100
};
static uint16_t utf16str[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0xD83C, 0xDC3A, 0
};
static uint16_t sutf16str[] = {
	0xFFFE, 0x6600, 0xF600, 0xF600, 0x6200, 0xE400, 0x7200, 0x3CD8, 0x3ADC,
	0







|



|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

static OFString *module = @"OFString";
static OFString* whitespace[] = {
	@" \r \t\n\t \tasd  \t \t\t\r\n",
	@" \t\t  \t\t  \t \t"
};
static of_unichar_t ucstr[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A, 0
};
static of_unichar_t 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[] = {
	0xFFFE, 0x6600, 0xF600, 0xF600, 0x6200, 0xE400, 0x7200, 0x3CD8, 0x3ADC,
	0
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

	TEST(@"+[stringWithUTF8String:length:]",
	    (s[0] = [OFMutableString stringWithUTF8String: "\xEF\xBB\xBF"
							   "foobar"
						   length: 6]) &&
	    [s[0] isEqual: @"foo"])

	TEST(@"+[stringWithCharacters:length:]",
	    (is = [OFString stringWithCharacters: ucstr
					  length: sizeof(ucstr) /
						  sizeof(*ucstr)]) &&
	    [is isEqual: @"fööbär🀺"] &&
	    (is = [OFString stringWithCharacters: sucstr
					  length: sizeof(sucstr) /
						  sizeof(*sucstr)]) &&
	    [is isEqual: @"fööbär🀺"])

	TEST(@"+[stringWithUTF16String:]",
	    (is = [OFString stringWithUTF16String: utf16str]) &&
	    [is isEqual: @"fööbär🀺"] &&
	    (is = [OFString stringWithUTF16String: sutf16str]) &&
	    [is isEqual: @"fööbär🀺"])







	TEST(@"+[stringWithContentsOfFile:encoding]", (is = [OFString
	    stringWithContentsOfFile: @"testfile.txt"
			    encoding: OF_STRING_ENCODING_ISO_8859_1]) &&
	    [is isEqual: @"testäöü"])

	TEST(@"+[stringWithContentsOfURL:encoding]", (is = [OFString







<
<
<
<
<
<
<
<
<
<





>
>
>
>
>
>







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

	TEST(@"+[stringWithUTF8String:length:]",
	    (s[0] = [OFMutableString stringWithUTF8String: "\xEF\xBB\xBF"
							   "foobar"
						   length: 6]) &&
	    [s[0] isEqual: @"foo"])











	TEST(@"+[stringWithUTF16String:]",
	    (is = [OFString stringWithUTF16String: utf16str]) &&
	    [is isEqual: @"fööbär🀺"] &&
	    (is = [OFString stringWithUTF16String: sutf16str]) &&
	    [is isEqual: @"fööbär🀺"])

	TEST(@"+[stringWithUTF32String::]",
	    (is = [OFString stringWithUTF32String: ucstr]) &&
	    [is isEqual: @"fööbär🀺"] &&
	    (is = [OFString stringWithUTF32String: sucstr]) &&
	    [is isEqual: @"fööbär🀺"])

	TEST(@"+[stringWithContentsOfFile:encoding]", (is = [OFString
	    stringWithContentsOfFile: @"testfile.txt"
			    encoding: OF_STRING_ENCODING_ISO_8859_1]) &&
	    [is isEqual: @"testäöü"])

	TEST(@"+[stringWithContentsOfURL:encoding]", (is = [OFString
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
	EXPECT_EXCEPTION(@"Detect out of range in -[hexadecimalValue]",
	    OFOutOfRangeException,
	    [@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
	     @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
	    hexadecimalValue])

	TEST(@"-[characters]", (ua = [@"fööbär🀺" characters]) &&
	    !memcmp(ua, ucstr + 1, sizeof(ucstr) / sizeof(*ucstr)))

	TEST(@"-[UTF16String]", (u16a = [@"fööbär🀺" UTF16String]) &&
	    !memcmp(u16a, utf16str + 1, sizeof(utf16str) - sizeof(uint16_t)))

	TEST(@"-[UTF16String]", (u16a = [@"fööbär🀺"
#ifdef OF_BIG_ENDIAN
	    UTF16StringWithByteOrder: OF_BYTE_ORDER_LITTLE_ENDIAN]) &&
#else
	    UTF16StringWithByteOrder: OF_BYTE_ORDER_BIG_ENDIAN]) &&
#endif
	    !memcmp(u16a, sutf16str + 1, sizeof(sutf16str) - sizeof(uint16_t)))

	TEST(@"-[UTF16StringLength]", [@"fööbär🀺" UTF16StringLength] == 8)











	TEST(@"-[MD5Hash]", [[@"asdfoobar" MD5Hash]
	    isEqual: @"184dce2ec49b5422c7cfd8728864db4c"])

	TEST(@"-[SHA1Hash]", [[@"asdfoobar" SHA1Hash]
	    isEqual: @"f5f81ac0a8b5cbfdc4585ec1ad32e7b3a12b9b49"])








|


|
<
|





|


>
>
>
>
>
>
>
>
>
>







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
	EXPECT_EXCEPTION(@"Detect out of range in -[hexadecimalValue]",
	    OFOutOfRangeException,
	    [@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
	     @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
	    hexadecimalValue])

	TEST(@"-[characters]", (ua = [@"fööbär🀺" characters]) &&
	    !memcmp(ua, ucstr + 1, sizeof(ucstr) - 8))

	TEST(@"-[UTF16String]", (u16a = [@"fööbär🀺" UTF16String]) &&
	    !memcmp(u16a, utf16str + 1, of_string_utf16_length(utf16str) * 2) &&

	    (u16a = [@"fööbär🀺"
#ifdef OF_BIG_ENDIAN
	    UTF16StringWithByteOrder: OF_BYTE_ORDER_LITTLE_ENDIAN]) &&
#else
	    UTF16StringWithByteOrder: OF_BYTE_ORDER_BIG_ENDIAN]) &&
#endif
	    !memcmp(u16a, sutf16str + 1, of_string_utf16_length(sutf16str) * 2))

	TEST(@"-[UTF16StringLength]", [@"fööbär🀺" UTF16StringLength] == 8)

	TEST(@"-[UTF32String]", (ua = [@"fööbär🀺" UTF32String]) &&
	    !memcmp(ua, ucstr + 1, of_string_utf32_length(ucstr) * 4) &&
	    (ua = [@"fööbär🀺"
#ifdef OF_BIG_ENDIAN
	    UTF32StringWithByteOrder: OF_BYTE_ORDER_LITTLE_ENDIAN]) &&
#else
	    UTF32StringWithByteOrder: OF_BYTE_ORDER_BIG_ENDIAN]) &&
#endif
	    !memcmp(ua, sucstr + 1, of_string_utf32_length(sucstr) * 4))

	TEST(@"-[MD5Hash]", [[@"asdfoobar" MD5Hash]
	    isEqual: @"184dce2ec49b5422c7cfd8728864db4c"])

	TEST(@"-[SHA1Hash]", [[@"asdfoobar" SHA1Hash]
	    isEqual: @"f5f81ac0a8b5cbfdc4585ec1ad32e7b3a12b9b49"])