2 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 #include <libkern/OSByteOrder.h>
25 #if defined(__LITTLE_ENDIAN__)
26 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST DISPATCH_DATA_FORMAT_TYPE_UTF16LE
27 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_REV DISPATCH_DATA_FORMAT_TYPE_UTF16BE
28 #elif defined(__BIG_ENDIAN__)
29 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST DISPATCH_DATA_FORMAT_TYPE_UTF16BE
30 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_REV DISPATCH_DATA_FORMAT_TYPE_UTF16LE
34 _DISPATCH_DATA_FORMAT_NONE
= 0x1,
35 _DISPATCH_DATA_FORMAT_UTF8
= 0x2,
36 _DISPATCH_DATA_FORMAT_UTF16LE
= 0x4,
37 _DISPATCH_DATA_FORMAT_UTF16BE
= 0x8,
38 _DISPATCH_DATA_FORMAT_UTF_ANY
= 0x10,
39 _DISPATCH_DATA_FORMAT_BASE32
= 0x20,
40 _DISPATCH_DATA_FORMAT_BASE32HEX
= 0x40,
41 _DISPATCH_DATA_FORMAT_BASE64
= 0x80,
45 #pragma mark baseXX tables
47 static const unsigned char base32_encode_table
[] =
48 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
50 static const char base32_decode_table
[] = {
51 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26,
54 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2,
55 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
56 20, 21, 22, 23, 24, 25
58 static const ssize_t base32_decode_table_size
= sizeof(base32_decode_table
)
59 / sizeof(*base32_decode_table
);
61 static const unsigned char base32hex_encode_table
[] =
62 "0123456789ABCDEFGHIJKLMNOPQRSTUV";
64 static const char base32hex_decode_table
[] = {
65 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
66 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
67 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2,
68 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -2, -1, -1, -1, 10, 11, 12,
69 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
72 static const ssize_t base32hex_decode_table_size
=
73 sizeof(base32hex_encode_table
) / sizeof(*base32hex_encode_table
);
75 static const unsigned char base64_encode_table
[] =
76 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
78 static const char base64_decode_table
[] = {
79 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
80 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
81 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
82 -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
83 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4,
84 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
85 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26,
86 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
87 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
90 static const ssize_t base64_decode_table_size
= sizeof(base64_decode_table
)
91 / sizeof(*base64_decode_table
);
94 #pragma mark dispatch_transform_buffer
96 typedef struct dispatch_transform_buffer_s
{
104 } dispatch_transform_buffer_s
;
107 _dispatch_transform_sizet_mul(size_t a
, size_t b
)
109 size_t rv
= SIZE_MAX
;
110 if (a
== 0 || rv
/a
>= b
) {
116 #define BUFFER_MALLOC_MAX (100*1024*1024)
119 _dispatch_transform_buffer_new(dispatch_transform_buffer_s
*buffer
,
120 size_t required
, size_t size
)
122 size_t remaining
= buffer
->size
- (size_t)(buffer
->ptr
.u8
- buffer
->start
);
123 if (required
== 0 || remaining
< required
) {
125 if (buffer
->ptr
.u8
> buffer
->start
) {
126 dispatch_data_t _new
= dispatch_data_create(buffer
->start
,
127 (size_t)(buffer
->ptr
.u8
- buffer
->start
), NULL
,
128 DISPATCH_DATA_DESTRUCTOR_FREE
);
129 dispatch_data_t _concat
= dispatch_data_create_concat(
131 dispatch_release(_new
);
132 dispatch_release(buffer
->data
);
133 buffer
->data
= _concat
;
138 buffer
->size
= required
+ size
;
139 buffer
->start
= NULL
;
140 if (buffer
->size
> 0) {
141 if (buffer
->size
> BUFFER_MALLOC_MAX
) {
144 buffer
->start
= (uint8_t*)malloc(buffer
->size
);
145 if (buffer
->start
== NULL
) {
149 buffer
->ptr
.u8
= buffer
->start
;
155 #pragma mark dispatch_transform_helpers
157 static dispatch_data_t
158 _dispatch_data_subrange_map(dispatch_data_t data
, const void **ptr
,
159 size_t offset
, size_t size
)
161 dispatch_data_t subrange
, map
= NULL
;
163 subrange
= dispatch_data_create_subrange(data
, offset
, size
);
164 if (dispatch_data_get_size(subrange
) == size
) {
165 map
= dispatch_data_create_map(subrange
, ptr
, NULL
);
167 dispatch_release(subrange
);
171 static dispatch_data_format_type_t
172 _dispatch_transform_detect_utf(dispatch_data_t data
)
175 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
, &p
, 0, 2);
177 if (subrange
== NULL
) {
181 const uint16_t ch
= *(const uint16_t *)p
;
182 dispatch_data_format_type_t type
= DISPATCH_DATA_FORMAT_TYPE_UTF8
;
185 type
= DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST
;
186 } else if (ch
== 0xfffe) {
187 type
= DISPATCH_DATA_FORMAT_TYPE_UTF16_REV
;
190 dispatch_release(subrange
);
196 _dispatch_transform_swap_to_host(uint16_t x
, int32_t byteOrder
)
198 if (byteOrder
== OSLittleEndian
) {
199 return OSSwapLittleToHostInt16(x
);
201 return OSSwapBigToHostInt16(x
);
205 _dispatch_transform_swap_from_host(uint16_t x
, int32_t byteOrder
)
207 if (byteOrder
== OSLittleEndian
) {
208 return OSSwapHostToLittleInt16(x
);
210 return OSSwapHostToBigInt16(x
);
217 _dispatch_transform_utf8_length(uint8_t byte
)
219 if ((byte
& 0x80) == 0) {
221 } else if ((byte
& 0xe0) == 0xc0) {
223 } else if ((byte
& 0xf0) == 0xe0) {
225 } else if ((byte
& 0xf8) == 0xf0) {
232 _dispatch_transform_read_utf8_sequence(const uint8_t *bytes
)
235 uint8_t seq_length
= _dispatch_transform_utf8_length(*bytes
);
237 switch (seq_length
) {
239 wch
|= (*bytes
& 0x7);
243 wch
|= (*bytes
& 0xf);
247 wch
|= (*bytes
& 0x1f);
251 wch
= (*bytes
& 0x7f);
254 // Not a utf-8 sequence
261 while (seq_length
> 0) {
262 wch
|= (*bytes
& 0x3f);
266 if (seq_length
> 0) {
276 static dispatch_data_t
277 _dispatch_transform_to_utf16(dispatch_data_t data
, int32_t byteOrder
)
279 __block
size_t skip
= 0;
281 __block dispatch_transform_buffer_s buffer
= {
282 .data
= dispatch_data_empty
,
285 bool success
= dispatch_data_apply(data
, ^(
286 DISPATCH_UNUSED dispatch_data_t region
,
287 size_t offset
, const void *_buffer
, size_t size
) {
288 const uint8_t *src
= _buffer
;
292 size_t dest_size
= 2 + _dispatch_transform_sizet_mul(size
,
294 if (!_dispatch_transform_buffer_new(&buffer
, dest_size
, 0)) {
298 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(0xfeff,
302 // Skip is incremented if the previous block read-ahead into our block
306 } else if (skip
> 0) {
312 for (i
= 0; i
< size
;) {
314 uint8_t byte_size
= _dispatch_transform_utf8_length(*src
);
316 if (byte_size
== 0) {
318 } else if (byte_size
+ i
> size
) {
319 // UTF-8 byte sequence spans over into the next block(s)
321 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
, &p
,
322 offset
+ i
, byte_size
);
323 if (subrange
== NULL
) {
327 wch
= _dispatch_transform_read_utf8_sequence(p
);
328 skip
+= byte_size
- (size
- i
);
332 dispatch_release(subrange
);
334 wch
= _dispatch_transform_read_utf8_sequence(src
);
339 size_t next
= _dispatch_transform_sizet_mul(size
- i
, sizeof(uint16_t));
340 if (wch
>= 0xd800 && wch
< 0xdfff) {
341 // Illegal range (surrogate pair)
343 } else if (wch
>= 0x10000) {
345 if (!_dispatch_transform_buffer_new(&buffer
, 2 *
346 sizeof(uint16_t), next
)) {
350 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(
351 ((wch
>> 10) & 0x3ff) + 0xd800, byteOrder
);
352 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(
353 (wch
& 0x3ff) + 0xdc00, byteOrder
);
355 if (!_dispatch_transform_buffer_new(&buffer
, 1 *
356 sizeof(uint16_t), next
)) {
359 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(
360 (wch
& 0xffff), byteOrder
);
364 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
370 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
371 dispatch_release(buffer
.data
);
378 static dispatch_data_t
379 _dispatch_transform_from_utf16(dispatch_data_t data
, int32_t byteOrder
)
381 __block
size_t skip
= 0;
383 __block dispatch_transform_buffer_s buffer
= {
384 .data
= dispatch_data_empty
,
387 bool success
= dispatch_data_apply(data
, ^(
388 DISPATCH_UNUSED dispatch_data_t region
, size_t offset
,
389 const void *_buffer
, size_t size
) {
390 const uint16_t *src
= _buffer
;
393 // Assume first buffer will be mostly single-byte UTF-8 sequences
394 size_t dest_size
= _dispatch_transform_sizet_mul(size
, 2) / 3;
395 if (!_dispatch_transform_buffer_new(&buffer
, dest_size
, 0)) {
400 size_t i
= 0, max
= size
/ 2;
402 // Skip is incremented if the previous block read-ahead into our block
406 } else if (skip
> 0) {
407 src
= (uint16_t *)(((uint8_t *)src
) + skip
);
413 // If the buffer is an odd size, allow read ahead into the next region
414 if ((size
% 2) != 0) {
418 for (i
= 0; i
< max
; i
++) {
422 if ((i
== (max
- 1)) && (max
> (size
/ 2))) {
423 // Last byte of an odd sized range
425 dispatch_data_t range
= _dispatch_data_subrange_map(data
, &p
,
426 offset
+ (i
* 2), 2);
430 ch
= _dispatch_transform_swap_to_host((uint16_t)*(uint64_t*)p
,
432 dispatch_release(range
);
435 ch
= _dispatch_transform_swap_to_host(src
[i
], byteOrder
);
438 if (ch
== 0xfffe && offset
== 0 && i
== 0) {
439 // Wrong-endian BOM at beginning of data
441 } else if (ch
== 0xfeff && offset
== 0 && i
== 0) {
442 // Correct-endian BOM, skip it
446 if ((ch
>= 0xd800) && (ch
<= 0xdbff)) {
448 wch
= ((ch
- 0xd800u
) << 10);
450 // Surrogate byte isn't in this block
452 dispatch_data_t range
= _dispatch_data_subrange_map(data
,
453 &p
, offset
+ (i
* 2), 2);
457 ch
= _dispatch_transform_swap_to_host(*(uint16_t *)p
,
459 dispatch_release(range
);
462 ch
= _dispatch_transform_swap_to_host(src
[i
], byteOrder
);
464 if (!((ch
>= 0xdc00) && (ch
<= 0xdfff))) {
467 wch
= (wch
| (ch
& 0x3ff));
469 } else if ((ch
>= 0xdc00) && (ch
<= 0xdfff)) {
475 size_t next
= _dispatch_transform_sizet_mul(max
- i
, 2);
477 if (!_dispatch_transform_buffer_new(&buffer
, 1, next
)) {
480 *(buffer
.ptr
.u8
)++ = (uint8_t)(wch
& 0xff);
481 } else if (wch
< 0x800) {
482 if (!_dispatch_transform_buffer_new(&buffer
, 2, next
)) {
485 *(buffer
.ptr
.u8
)++ = (uint8_t)(0xc0 | (wch
>> 6));
486 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | (wch
& 0x3f));
487 } else if (wch
< 0x10000) {
488 if (!_dispatch_transform_buffer_new(&buffer
, 3, next
)) {
491 *(buffer
.ptr
.u8
)++ = (uint8_t)(0xe0 | (wch
>> 12));
492 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | ((wch
>> 6) & 0x3f));
493 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | (wch
& 0x3f));
494 } else if (wch
< 0x200000) {
495 if (!_dispatch_transform_buffer_new(&buffer
, 4, next
)) {
498 *(buffer
.ptr
.u8
)++ = (uint8_t)(0xf0 | (wch
>> 18));
499 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | ((wch
>> 12) & 0x3f));
500 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | ((wch
>> 6) & 0x3f));
501 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | (wch
& 0x3f));
505 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
511 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
512 dispatch_release(buffer
.data
);
519 static dispatch_data_t
520 _dispatch_transform_from_utf16le(dispatch_data_t data
)
522 return _dispatch_transform_from_utf16(data
, OSLittleEndian
);
525 static dispatch_data_t
526 _dispatch_transform_from_utf16be(dispatch_data_t data
)
528 return _dispatch_transform_from_utf16(data
, OSBigEndian
);
531 static dispatch_data_t
532 _dispatch_transform_to_utf16le(dispatch_data_t data
)
534 return _dispatch_transform_to_utf16(data
, OSLittleEndian
);
537 static dispatch_data_t
538 _dispatch_transform_to_utf16be(dispatch_data_t data
)
540 return _dispatch_transform_to_utf16(data
, OSBigEndian
);
546 static dispatch_data_t
547 _dispatch_transform_from_base32_with_table(dispatch_data_t data
,
548 const char* table
, ssize_t table_size
)
550 __block
uint64_t x
= 0, count
= 0, pad
= 0;
552 __block dispatch_data_t rv
= dispatch_data_empty
;
554 bool success
= dispatch_data_apply(data
, ^(
555 DISPATCH_UNUSED dispatch_data_t region
,
556 DISPATCH_UNUSED
size_t offset
, const void *buffer
, size_t size
) {
557 size_t i
, dest_size
= (size
* 5) / 8;
559 uint8_t *dest
= (uint8_t*)malloc(dest_size
* sizeof(uint8_t));
565 const uint8_t *bytes
= buffer
;
567 for (i
= 0; i
< size
; i
++) {
568 if (bytes
[i
] == '\n' || bytes
[i
] == '\t' || bytes
[i
] == ' ') {
572 ssize_t index
= bytes
[i
];
573 if (index
>= table_size
|| table
[index
] == -1) {
579 char value
= table
[index
];
586 x
+= (uint64_t)value
;
588 if ((count
& 0x7) == 0) {
589 *ptr
++ = (x
>> 32) & 0xff;
590 *ptr
++ = (x
>> 24) & 0xff;
591 *ptr
++ = (x
>> 16) & 0xff;
592 *ptr
++ = (x
>> 8) & 0xff;
597 size_t final
= (size_t)(ptr
- dest
);
613 dispatch_data_t val
= dispatch_data_create(dest
, final
, NULL
,
614 DISPATCH_DATA_DESTRUCTOR_FREE
);
615 dispatch_data_t concat
= dispatch_data_create_concat(rv
, val
);
617 dispatch_release(val
);
618 dispatch_release(rv
);
625 dispatch_release(rv
);
632 static dispatch_data_t
633 _dispatch_transform_to_base32_with_table(dispatch_data_t data
, const unsigned char* table
)
635 size_t total
= dispatch_data_get_size(data
);
636 __block
size_t count
= 0;
638 if (total
> SIZE_T_MAX
-4 || ((total
+4)/5 > SIZE_T_MAX
/8)) {
639 /* We can't hold larger than size_t in a dispatch_data_t
640 * and we want to avoid an integer overflow in the next
646 size_t dest_size
= (total
+ 4) / 5 * 8;
647 uint8_t *dest
= (uint8_t*)malloc(dest_size
);
652 __block
uint8_t *ptr
= dest
;
656 8-bit bytes: xxxxxxxx yyyyyyyy zzzzzzzz xxxxxxxx yyyyyyyy
657 5-bit chunks: aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh
660 bool success
= dispatch_data_apply(data
, ^(
661 DISPATCH_UNUSED dispatch_data_t region
,
662 size_t offset
, const void *buffer
, size_t size
) {
663 const uint8_t *bytes
= buffer
;
666 for (i
= 0; i
< size
; i
++, count
++) {
667 uint8_t curr
= bytes
[i
], last
= 0;
669 if ((count
% 5) != 0) {
672 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
,
674 if (subrange
== NULL
) {
678 dispatch_release(subrange
);
687 *ptr
++ = table
[(curr
>> 3) & 0x1fu
];
691 *ptr
++ = table
[((last
<< 2)|(curr
>> 6)) & 0x1f];
692 *ptr
++ = table
[(curr
>> 1) & 0x1f];
696 *ptr
++ = table
[((last
<< 4)|(curr
>> 4)) & 0x1f];
700 *ptr
++ = table
[((last
<< 1)|(curr
>> 7)) & 0x1f];
701 *ptr
++ = table
[(curr
>> 2) & 0x1f];
705 *ptr
++ = table
[((last
<< 3)|(curr
>> 5)) & 0x1f];
706 *ptr
++ = table
[curr
& 0x1f];
711 // Last region, insert padding bytes, if needed
712 if (offset
+ size
== total
) {
718 *ptr
++ = table
[(bytes
[size
-1] << 2) & 0x1c];
722 *ptr
++ = table
[(bytes
[size
-1] << 4) & 0x10];
726 *ptr
++ = table
[(bytes
[size
-1] << 1) & 0x1e];
730 *ptr
++ = table
[(bytes
[size
-1] << 3) & 0x18];
757 return dispatch_data_create(dest
, dest_size
, NULL
,
758 DISPATCH_DATA_DESTRUCTOR_FREE
);
761 static dispatch_data_t
762 _dispatch_transform_from_base32(dispatch_data_t data
)
764 return _dispatch_transform_from_base32_with_table(data
, base32_decode_table
,
765 base32_decode_table_size
);
768 static dispatch_data_t
769 _dispatch_transform_to_base32(dispatch_data_t data
)
771 return _dispatch_transform_to_base32_with_table(data
, base32_encode_table
);
774 static dispatch_data_t
775 _dispatch_transform_from_base32hex(dispatch_data_t data
)
777 return _dispatch_transform_from_base32_with_table(data
,
778 base32hex_decode_table
, base32hex_decode_table_size
);
781 static dispatch_data_t
782 _dispatch_transform_to_base32hex(dispatch_data_t data
)
784 return _dispatch_transform_to_base32_with_table(data
,
785 base32hex_encode_table
);
791 static dispatch_data_t
792 _dispatch_transform_from_base64(dispatch_data_t data
)
794 __block
uint64_t x
= 0, count
= 0;
795 __block
size_t pad
= 0;
797 __block dispatch_data_t rv
= dispatch_data_empty
;
799 bool success
= dispatch_data_apply(data
, ^(
800 DISPATCH_UNUSED dispatch_data_t region
,
801 DISPATCH_UNUSED
size_t offset
, const void *buffer
, size_t size
) {
802 size_t i
, dest_size
= (size
* 3) / 4;
804 uint8_t *dest
= (uint8_t*)malloc(dest_size
* sizeof(uint8_t));
810 const uint8_t *bytes
= buffer
;
812 for (i
= 0; i
< size
; i
++) {
813 if (bytes
[i
] == '\n' || bytes
[i
] == '\t' || bytes
[i
] == ' ') {
817 ssize_t index
= bytes
[i
];
818 if (index
>= base64_decode_table_size
||
819 base64_decode_table
[index
] == -1) {
825 char value
= base64_decode_table
[index
];
832 x
+= (uint64_t)value
;
834 if ((count
& 0x3) == 0) {
835 *ptr
++ = (x
>> 16) & 0xff;
836 *ptr
++ = (x
>> 8) & 0xff;
841 size_t final
= (size_t)(ptr
- dest
);
843 // 2 bytes of pad means only had one char in final group
847 dispatch_data_t val
= dispatch_data_create(dest
, final
, NULL
,
848 DISPATCH_DATA_DESTRUCTOR_FREE
);
849 dispatch_data_t concat
= dispatch_data_create_concat(rv
, val
);
851 dispatch_release(val
);
852 dispatch_release(rv
);
859 dispatch_release(rv
);
866 static dispatch_data_t
867 _dispatch_transform_to_base64(dispatch_data_t data
)
869 // RFC 4648 states that we should not linebreak
870 // http://tools.ietf.org/html/rfc4648
871 size_t total
= dispatch_data_get_size(data
);
872 __block
size_t count
= 0;
874 if (total
> SIZE_T_MAX
-2 || ((total
+2)/3> SIZE_T_MAX
/4)) {
875 /* We can't hold larger than size_t in a dispatch_data_t
876 * and we want to avoid an integer overflow in the next
882 size_t dest_size
= (total
+ 2) / 3 * 4;
883 uint8_t *dest
= (uint8_t*)malloc(dest_size
);
888 __block
uint8_t *ptr
= dest
;
891 * 3 8-bit bytes: xxxxxxxx yyyyyyyy zzzzzzzz
892 * 4 6-bit chunks: aaaaaabb bbbbcccc ccdddddd
895 bool success
= dispatch_data_apply(data
, ^(
896 DISPATCH_UNUSED dispatch_data_t region
,
897 size_t offset
, const void *buffer
, size_t size
) {
898 const uint8_t *bytes
= buffer
;
901 for (i
= 0; i
< size
; i
++, count
++) {
902 uint8_t curr
= bytes
[i
], last
= 0;
904 if ((count
% 3) != 0) {
907 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
,
909 if (subrange
== NULL
) {
913 dispatch_release(subrange
);
921 *ptr
++ = base64_encode_table
[(curr
>> 2) & 0x3f];
924 *ptr
++ = base64_encode_table
[((last
<< 4)|(curr
>> 4)) & 0x3f];
927 *ptr
++ = base64_encode_table
[((last
<< 2)|(curr
>> 6)) & 0x3f];
928 *ptr
++ = base64_encode_table
[(curr
& 0x3f)];
933 // Last region, insert padding bytes, if needed
934 if (offset
+ size
== total
) {
939 *ptr
++ = base64_encode_table
[(bytes
[size
-1] << 4) & 0x30];
944 *ptr
++ = base64_encode_table
[(bytes
[size
-1] << 2) & 0x3c];
957 return dispatch_data_create(dest
, dest_size
, NULL
,
958 DISPATCH_DATA_DESTRUCTOR_FREE
);
962 #pragma mark dispatch_data_transform
965 dispatch_data_create_with_transform(dispatch_data_t data
,
966 dispatch_data_format_type_t input
, dispatch_data_format_type_t output
)
968 if (input
->type
== _DISPATCH_DATA_FORMAT_UTF_ANY
) {
969 input
= _dispatch_transform_detect_utf(data
);
975 if ((input
->type
& ~output
->input_mask
) != 0) {
979 if ((output
->type
& ~input
->output_mask
) != 0) {
983 if (dispatch_data_get_size(data
) == 0) {
987 dispatch_data_t temp1
;
989 temp1
= input
->decode(data
);
991 dispatch_retain(data
);
999 dispatch_data_t temp2
;
1000 if (output
->encode
) {
1001 temp2
= output
->encode(temp1
);
1003 dispatch_retain(temp1
);
1007 dispatch_release(temp1
);
1011 const struct dispatch_data_format_type_s _dispatch_data_format_type_none
= {
1012 .type
= _DISPATCH_DATA_FORMAT_NONE
,
1019 const struct dispatch_data_format_type_s _dispatch_data_format_type_base32
= {
1020 .type
= _DISPATCH_DATA_FORMAT_BASE32
,
1021 .input_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1022 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1023 .output_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1024 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1025 .decode
= _dispatch_transform_from_base32
,
1026 .encode
= _dispatch_transform_to_base32
,
1029 const struct dispatch_data_format_type_s _dispatch_data_format_type_base32hex
=
1031 .type
= _DISPATCH_DATA_FORMAT_BASE32HEX
,
1032 .input_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1033 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1034 .output_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1035 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1036 .decode
= _dispatch_transform_from_base32hex
,
1037 .encode
= _dispatch_transform_to_base32hex
,
1040 const struct dispatch_data_format_type_s _dispatch_data_format_type_base64
= {
1041 .type
= _DISPATCH_DATA_FORMAT_BASE64
,
1042 .input_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1043 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1044 .output_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1045 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1046 .decode
= _dispatch_transform_from_base64
,
1047 .encode
= _dispatch_transform_to_base64
,
1050 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf16le
= {
1051 .type
= _DISPATCH_DATA_FORMAT_UTF16LE
,
1052 .input_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1053 _DISPATCH_DATA_FORMAT_UTF16LE
),
1054 .output_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1055 _DISPATCH_DATA_FORMAT_UTF16LE
),
1056 .decode
= _dispatch_transform_from_utf16le
,
1057 .encode
= _dispatch_transform_to_utf16le
,
1060 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf16be
= {
1061 .type
= _DISPATCH_DATA_FORMAT_UTF16BE
,
1062 .input_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1063 _DISPATCH_DATA_FORMAT_UTF16LE
),
1064 .output_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1065 _DISPATCH_DATA_FORMAT_UTF16LE
),
1066 .decode
= _dispatch_transform_from_utf16be
,
1067 .encode
= _dispatch_transform_to_utf16be
,
1070 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf8
= {
1071 .type
= _DISPATCH_DATA_FORMAT_UTF8
,
1072 .input_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1073 _DISPATCH_DATA_FORMAT_UTF16LE
),
1074 .output_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1075 _DISPATCH_DATA_FORMAT_UTF16LE
),
1080 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf_any
= {
1081 .type
= _DISPATCH_DATA_FORMAT_UTF_ANY
,