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@
24 #include <libkern/OSByteOrder.h>
27 #define OSLittleEndian __LITTLE_ENDIAN
28 #define OSBigEndian __BIG_ENDIAN
29 #define OSSwapLittleToHostInt16 le16toh
30 #define OSSwapBigToHostInt16 be16toh
31 #define OSSwapHostToLittleInt16 htole16
32 #define OSSwapHostToBigInt16 htobe16
35 #if defined(__LITTLE_ENDIAN__)
36 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST DISPATCH_DATA_FORMAT_TYPE_UTF16LE
37 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_REV DISPATCH_DATA_FORMAT_TYPE_UTF16BE
38 #elif defined(__BIG_ENDIAN__)
39 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST DISPATCH_DATA_FORMAT_TYPE_UTF16BE
40 #define DISPATCH_DATA_FORMAT_TYPE_UTF16_REV DISPATCH_DATA_FORMAT_TYPE_UTF16LE
42 #error Unsupported Endianness
46 _DISPATCH_DATA_FORMAT_NONE
= 0x1,
47 _DISPATCH_DATA_FORMAT_UTF8
= 0x2,
48 _DISPATCH_DATA_FORMAT_UTF16LE
= 0x4,
49 _DISPATCH_DATA_FORMAT_UTF16BE
= 0x8,
50 _DISPATCH_DATA_FORMAT_UTF_ANY
= 0x10,
51 _DISPATCH_DATA_FORMAT_BASE32
= 0x20,
52 _DISPATCH_DATA_FORMAT_BASE32HEX
= 0x40,
53 _DISPATCH_DATA_FORMAT_BASE64
= 0x80,
57 #pragma mark baseXX tables
59 static const unsigned char base32_encode_table
[] =
60 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
62 static const char base32_decode_table
[] = {
63 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
65 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26,
66 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2,
67 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
68 20, 21, 22, 23, 24, 25
70 static const ssize_t base32_decode_table_size
= sizeof(base32_decode_table
)
71 / sizeof(*base32_decode_table
);
73 static const unsigned char base32hex_encode_table
[] =
74 "0123456789ABCDEFGHIJKLMNOPQRSTUV";
76 static const char base32hex_decode_table
[] = {
77 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
78 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
79 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2,
80 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -2, -1, -1, -1, 10, 11, 12,
81 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
84 static const ssize_t base32hex_decode_table_size
=
85 sizeof(base32hex_encode_table
) / sizeof(*base32hex_encode_table
);
87 static const unsigned char base64_encode_table
[] =
88 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
90 static const char base64_decode_table
[] = {
91 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
92 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
93 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
94 -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
95 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4,
96 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
97 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26,
98 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
99 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
102 static const ssize_t base64_decode_table_size
= sizeof(base64_decode_table
)
103 / sizeof(*base64_decode_table
);
106 #pragma mark dispatch_transform_buffer
108 typedef struct dispatch_transform_buffer_s
{
109 dispatch_data_t data
;
116 } dispatch_transform_buffer_s
;
118 #define BUFFER_MALLOC_MAX (100*1024*1024)
121 _dispatch_transform_buffer_new(dispatch_transform_buffer_s
*buffer
,
122 size_t required
, size_t size
)
124 size_t remaining
= buffer
->size
- (size_t)(buffer
->ptr
.u8
- buffer
->start
);
125 if (required
== 0 || remaining
< required
) {
127 if (buffer
->ptr
.u8
> buffer
->start
) {
128 dispatch_data_t _new
= dispatch_data_create(buffer
->start
,
129 (size_t)(buffer
->ptr
.u8
- buffer
->start
), NULL
,
130 DISPATCH_DATA_DESTRUCTOR_FREE
);
131 dispatch_data_t _concat
= dispatch_data_create_concat(
133 dispatch_release(_new
);
134 dispatch_release(buffer
->data
);
135 buffer
->data
= _concat
;
140 buffer
->size
= required
+ size
;
141 buffer
->start
= NULL
;
142 if (buffer
->size
> 0) {
143 if (buffer
->size
> BUFFER_MALLOC_MAX
) {
146 buffer
->start
= (uint8_t*)malloc(buffer
->size
);
147 if (buffer
->start
== NULL
) {
151 buffer
->ptr
.u8
= buffer
->start
;
157 #pragma mark dispatch_transform_helpers
159 static dispatch_data_t
160 _dispatch_data_subrange_map(dispatch_data_t data
, const void **ptr
,
161 size_t offset
, size_t size
)
163 dispatch_data_t subrange
, map
= NULL
;
165 subrange
= dispatch_data_create_subrange(data
, offset
, size
);
166 if (dispatch_data_get_size(subrange
) == size
) {
167 map
= dispatch_data_create_map(subrange
, ptr
, NULL
);
169 dispatch_release(subrange
);
173 static dispatch_data_format_type_t
174 _dispatch_transform_detect_utf(dispatch_data_t data
)
177 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
, &p
, 0, 2);
179 if (subrange
== NULL
) {
183 const uint16_t ch
= *(const uint16_t *)p
;
184 dispatch_data_format_type_t type
= DISPATCH_DATA_FORMAT_TYPE_UTF8
;
187 type
= DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST
;
188 } else if (ch
== 0xfffe) {
189 type
= DISPATCH_DATA_FORMAT_TYPE_UTF16_REV
;
192 dispatch_release(subrange
);
198 _dispatch_transform_swap_to_host(uint16_t x
, int32_t byteOrder
)
200 if (byteOrder
== OSLittleEndian
) {
201 return OSSwapLittleToHostInt16(x
);
203 return OSSwapBigToHostInt16(x
);
207 _dispatch_transform_swap_from_host(uint16_t x
, int32_t byteOrder
)
209 if (byteOrder
== OSLittleEndian
) {
210 return OSSwapHostToLittleInt16(x
);
212 return OSSwapHostToBigInt16(x
);
219 _dispatch_transform_utf8_length(uint8_t byte
)
221 if ((byte
& 0x80) == 0) {
223 } else if ((byte
& 0xe0) == 0xc0) {
225 } else if ((byte
& 0xf0) == 0xe0) {
227 } else if ((byte
& 0xf8) == 0xf0) {
234 _dispatch_transform_read_utf8_sequence(const uint8_t *bytes
)
237 uint8_t seq_length
= _dispatch_transform_utf8_length(*bytes
);
239 switch (seq_length
) {
241 wch
|= (*bytes
& 0x7);
245 wch
|= (*bytes
& 0xf);
249 wch
|= (*bytes
& 0x1f);
253 wch
= (*bytes
& 0x7f);
256 // Not a utf-8 sequence
263 while (seq_length
> 0) {
264 wch
|= (*bytes
& 0x3f);
268 if (seq_length
> 0) {
278 static dispatch_data_t
279 _dispatch_transform_to_utf16(dispatch_data_t data
, int32_t byteOrder
)
281 __block
size_t skip
= 0;
283 __block dispatch_transform_buffer_s buffer
= {
284 .data
= dispatch_data_empty
,
287 bool success
= dispatch_data_apply(data
, ^(
288 DISPATCH_UNUSED dispatch_data_t region
,
289 size_t offset
, const void *_buffer
, size_t size
) {
290 const uint8_t *src
= _buffer
;
294 if (os_mul_and_add_overflow(size
, sizeof(uint16_t),
295 sizeof(uint16_t), &dest_size
)) {
298 if (!_dispatch_transform_buffer_new(&buffer
, dest_size
, 0)) {
302 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(0xfeff,
306 // Skip is incremented if the previous block read-ahead into our block
310 } else if (skip
> 0) {
316 for (i
= 0; i
< size
;) {
318 uint8_t byte_size
= _dispatch_transform_utf8_length(*src
);
321 if (byte_size
== 0) {
323 } else if (byte_size
+ i
> size
) {
324 // UTF-8 byte sequence spans over into the next block(s)
326 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
, &p
,
327 offset
+ i
, byte_size
);
328 if (subrange
== NULL
) {
332 wch
= _dispatch_transform_read_utf8_sequence(p
);
333 skip
+= byte_size
- (size
- i
);
337 dispatch_release(subrange
);
339 wch
= _dispatch_transform_read_utf8_sequence(src
);
344 if (os_mul_overflow(size
- i
, sizeof(uint16_t), &next
)) {
347 if (wch
>= 0xd800 && wch
< 0xdfff) {
348 // Illegal range (surrogate pair)
350 } else if (wch
>= 0x10000) {
352 if (!_dispatch_transform_buffer_new(&buffer
, 2 *
353 sizeof(uint16_t), next
)) {
357 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(
358 ((wch
>> 10) & 0x3ff) + 0xd800, byteOrder
);
359 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(
360 (wch
& 0x3ff) + 0xdc00, byteOrder
);
362 if (!_dispatch_transform_buffer_new(&buffer
, 1 *
363 sizeof(uint16_t), next
)) {
366 *(buffer
.ptr
.u16
)++ = _dispatch_transform_swap_from_host(
367 (wch
& 0xffff), byteOrder
);
371 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
377 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
378 dispatch_release(buffer
.data
);
385 static dispatch_data_t
386 _dispatch_transform_from_utf16(dispatch_data_t data
, int32_t byteOrder
)
388 __block
size_t skip
= 0;
390 __block dispatch_transform_buffer_s buffer
= {
391 .data
= dispatch_data_empty
,
394 bool success
= dispatch_data_apply(data
, ^(
395 DISPATCH_UNUSED dispatch_data_t region
, size_t offset
,
396 const void *_buffer
, size_t size
) {
397 const uint16_t *src
= _buffer
;
400 size_t dest_size
= howmany(size
, 3) * 2;
401 // Assume first buffer will be mostly single-byte UTF-8 sequences
402 if (!_dispatch_transform_buffer_new(&buffer
, dest_size
, 0)) {
407 size_t i
= 0, max
= size
/ 2;
409 // Skip is incremented if the previous block read-ahead into our block
413 } else if (skip
> 0) {
414 src
= (uint16_t *)(((uint8_t *)src
) + skip
);
420 // If the buffer is an odd size, allow read ahead into the next region
421 if ((size
% 2) != 0) {
425 for (i
= 0; i
< max
; i
++) {
430 if ((i
== (max
- 1)) && (max
> (size
/ 2))) {
431 // Last byte of an odd sized range
433 dispatch_data_t range
= _dispatch_data_subrange_map(data
, &p
,
434 offset
+ (i
* 2), 2);
438 ch
= _dispatch_transform_swap_to_host((uint16_t)*(uint64_t*)p
,
440 dispatch_release(range
);
443 ch
= _dispatch_transform_swap_to_host(src
[i
], byteOrder
);
446 if (ch
== 0xfffe && offset
== 0 && i
== 0) {
447 // Wrong-endian BOM at beginning of data
449 } else if (ch
== 0xfeff && offset
== 0 && i
== 0) {
450 // Correct-endian BOM, skip it
454 if ((ch
>= 0xd800) && (ch
<= 0xdbff)) {
456 wch
= ((ch
- 0xd800u
) << 10);
458 // Surrogate byte isn't in this block
460 dispatch_data_t range
= _dispatch_data_subrange_map(data
,
461 &p
, offset
+ (i
* 2), 2);
465 ch
= _dispatch_transform_swap_to_host(*(uint16_t *)p
,
467 dispatch_release(range
);
470 ch
= _dispatch_transform_swap_to_host(src
[i
], byteOrder
);
472 if (!((ch
>= 0xdc00) && (ch
<= 0xdfff))) {
475 wch
= (wch
| (ch
& 0x3ff));
477 } else if ((ch
>= 0xdc00) && (ch
<= 0xdfff)) {
483 if (os_mul_overflow(max
- i
, 2, &next
)) {
487 if (!_dispatch_transform_buffer_new(&buffer
, 1, next
)) {
490 *(buffer
.ptr
.u8
)++ = (uint8_t)(wch
& 0xff);
491 } else if (wch
< 0x800) {
492 if (!_dispatch_transform_buffer_new(&buffer
, 2, next
)) {
495 *(buffer
.ptr
.u8
)++ = (uint8_t)(0xc0 | (wch
>> 6));
496 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | (wch
& 0x3f));
497 } else if (wch
< 0x10000) {
498 if (!_dispatch_transform_buffer_new(&buffer
, 3, next
)) {
501 *(buffer
.ptr
.u8
)++ = (uint8_t)(0xe0 | (wch
>> 12));
502 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | ((wch
>> 6) & 0x3f));
503 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | (wch
& 0x3f));
504 } else if (wch
< 0x200000) {
505 if (!_dispatch_transform_buffer_new(&buffer
, 4, next
)) {
508 *(buffer
.ptr
.u8
)++ = (uint8_t)(0xf0 | (wch
>> 18));
509 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | ((wch
>> 12) & 0x3f));
510 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | ((wch
>> 6) & 0x3f));
511 *(buffer
.ptr
.u8
)++ = (uint8_t)(0x80 | (wch
& 0x3f));
515 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
521 (void)_dispatch_transform_buffer_new(&buffer
, 0, 0);
522 dispatch_release(buffer
.data
);
529 static dispatch_data_t
530 _dispatch_transform_from_utf16le(dispatch_data_t data
)
532 return _dispatch_transform_from_utf16(data
, OSLittleEndian
);
535 static dispatch_data_t
536 _dispatch_transform_from_utf16be(dispatch_data_t data
)
538 return _dispatch_transform_from_utf16(data
, OSBigEndian
);
541 static dispatch_data_t
542 _dispatch_transform_to_utf16le(dispatch_data_t data
)
544 return _dispatch_transform_to_utf16(data
, OSLittleEndian
);
547 static dispatch_data_t
548 _dispatch_transform_to_utf16be(dispatch_data_t data
)
550 return _dispatch_transform_to_utf16(data
, OSBigEndian
);
556 static dispatch_data_t
557 _dispatch_transform_from_base32_with_table(dispatch_data_t data
,
558 const char* table
, ssize_t table_size
)
560 __block
uint64_t x
= 0, count
= 0, pad
= 0;
562 __block dispatch_data_t rv
= dispatch_data_empty
;
564 bool success
= dispatch_data_apply(data
, ^(
565 DISPATCH_UNUSED dispatch_data_t region
,
566 DISPATCH_UNUSED
size_t offset
, const void *buffer
, size_t size
) {
567 size_t i
, dest_size
= howmany(size
, 8) * 5;
568 uint8_t *dest
= (uint8_t*)malloc(dest_size
* sizeof(uint8_t));
574 const uint8_t *bytes
= buffer
;
576 for (i
= 0; i
< size
; i
++) {
577 if (bytes
[i
] == '\n' || bytes
[i
] == '\t' || bytes
[i
] == ' ') {
581 ssize_t index
= bytes
[i
];
582 if (index
>= table_size
|| table
[index
] == -1) {
588 char value
= table
[index
];
595 x
+= (uint64_t)value
;
597 if ((count
& 0x7) == 0) {
598 *ptr
++ = (x
>> 32) & 0xff;
599 *ptr
++ = (x
>> 24) & 0xff;
600 *ptr
++ = (x
>> 16) & 0xff;
601 *ptr
++ = (x
>> 8) & 0xff;
606 size_t final
= (size_t)(ptr
- dest
);
622 dispatch_data_t val
= dispatch_data_create(dest
, final
, NULL
,
623 DISPATCH_DATA_DESTRUCTOR_FREE
);
624 dispatch_data_t concat
= dispatch_data_create_concat(rv
, val
);
626 dispatch_release(val
);
627 dispatch_release(rv
);
634 dispatch_release(rv
);
641 static dispatch_data_t
642 _dispatch_transform_to_base32_with_table(dispatch_data_t data
, const unsigned char* table
)
644 size_t total
= dispatch_data_get_size(data
), dest_size
;
645 __block
size_t count
= 0;
647 dest_size
= howmany(total
, 5);
648 // <rdar://problem/25676583>
649 // os_mul_overflow(dest_size, 8, &dest_size)
650 if (dest_size
> SIZE_T_MAX
/ 8) {
655 uint8_t *dest
= (uint8_t*)malloc(dest_size
);
660 __block
uint8_t *ptr
= dest
;
664 8-bit bytes: xxxxxxxx yyyyyyyy zzzzzzzz xxxxxxxx yyyyyyyy
665 5-bit chunks: aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh
668 bool success
= dispatch_data_apply(data
, ^(
669 DISPATCH_UNUSED dispatch_data_t region
,
670 size_t offset
, const void *buffer
, size_t size
) {
671 const uint8_t *bytes
= buffer
;
674 for (i
= 0; i
< size
; i
++, count
++) {
675 uint8_t curr
= bytes
[i
], last
= 0;
677 if ((count
% 5) != 0) {
680 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
,
682 if (subrange
== NULL
) {
686 dispatch_release(subrange
);
695 *ptr
++ = table
[(curr
>> 3) & 0x1fu
];
699 *ptr
++ = table
[((last
<< 2)|(curr
>> 6)) & 0x1f];
700 *ptr
++ = table
[(curr
>> 1) & 0x1f];
704 *ptr
++ = table
[((last
<< 4)|(curr
>> 4)) & 0x1f];
708 *ptr
++ = table
[((last
<< 1)|(curr
>> 7)) & 0x1f];
709 *ptr
++ = table
[(curr
>> 2) & 0x1f];
713 *ptr
++ = table
[((last
<< 3)|(curr
>> 5)) & 0x1f];
714 *ptr
++ = table
[curr
& 0x1f];
719 // Last region, insert padding bytes, if needed
720 if (offset
+ size
== total
) {
726 *ptr
++ = table
[(bytes
[size
-1] << 2) & 0x1c];
730 *ptr
++ = table
[(bytes
[size
-1] << 4) & 0x10];
734 *ptr
++ = table
[(bytes
[size
-1] << 1) & 0x1e];
738 *ptr
++ = table
[(bytes
[size
-1] << 3) & 0x18];
765 return dispatch_data_create(dest
, dest_size
, NULL
,
766 DISPATCH_DATA_DESTRUCTOR_FREE
);
769 static dispatch_data_t
770 _dispatch_transform_from_base32(dispatch_data_t data
)
772 return _dispatch_transform_from_base32_with_table(data
, base32_decode_table
,
773 base32_decode_table_size
);
776 static dispatch_data_t
777 _dispatch_transform_to_base32(dispatch_data_t data
)
779 return _dispatch_transform_to_base32_with_table(data
, base32_encode_table
);
782 static dispatch_data_t
783 _dispatch_transform_from_base32hex(dispatch_data_t data
)
785 return _dispatch_transform_from_base32_with_table(data
,
786 base32hex_decode_table
, base32hex_decode_table_size
);
789 static dispatch_data_t
790 _dispatch_transform_to_base32hex(dispatch_data_t data
)
792 return _dispatch_transform_to_base32_with_table(data
,
793 base32hex_encode_table
);
799 static dispatch_data_t
800 _dispatch_transform_from_base64(dispatch_data_t data
)
802 __block
uint64_t x
= 0, count
= 0;
803 __block
size_t pad
= 0;
805 __block dispatch_data_t rv
= dispatch_data_empty
;
807 bool success
= dispatch_data_apply(data
, ^(
808 DISPATCH_UNUSED dispatch_data_t region
,
809 DISPATCH_UNUSED
size_t offset
, const void *buffer
, size_t size
) {
810 size_t i
, dest_size
= howmany(size
, 4) * 3;
812 uint8_t *dest
= (uint8_t*)malloc(dest_size
* sizeof(uint8_t));
818 const uint8_t *bytes
= buffer
;
820 for (i
= 0; i
< size
; i
++) {
821 if (bytes
[i
] == '\n' || bytes
[i
] == '\t' || bytes
[i
] == ' ') {
825 ssize_t index
= bytes
[i
];
826 if (index
>= base64_decode_table_size
||
827 base64_decode_table
[index
] == -1) {
833 char value
= base64_decode_table
[index
];
840 x
+= (uint64_t)value
;
842 if ((count
& 0x3) == 0) {
843 *ptr
++ = (x
>> 16) & 0xff;
844 *ptr
++ = (x
>> 8) & 0xff;
849 size_t final
= (size_t)(ptr
- dest
);
851 // 2 bytes of pad means only had one char in final group
855 dispatch_data_t val
= dispatch_data_create(dest
, final
, NULL
,
856 DISPATCH_DATA_DESTRUCTOR_FREE
);
857 dispatch_data_t concat
= dispatch_data_create_concat(rv
, val
);
859 dispatch_release(val
);
860 dispatch_release(rv
);
867 dispatch_release(rv
);
874 static dispatch_data_t
875 _dispatch_transform_to_base64(dispatch_data_t data
)
877 // RFC 4648 states that we should not linebreak
878 // http://tools.ietf.org/html/rfc4648
879 size_t total
= dispatch_data_get_size(data
), dest_size
;
880 __block
size_t count
= 0;
882 dest_size
= howmany(total
, 3);
883 // <rdar://problem/25676583>
884 // os_mul_overflow(dest_size, 4, &dest_size)
885 if (dest_size
> SIZE_T_MAX
/ 4) {
890 uint8_t *dest
= (uint8_t*)malloc(dest_size
);
895 __block
uint8_t *ptr
= dest
;
898 * 3 8-bit bytes: xxxxxxxx yyyyyyyy zzzzzzzz
899 * 4 6-bit chunks: aaaaaabb bbbbcccc ccdddddd
902 bool success
= dispatch_data_apply(data
, ^(
903 DISPATCH_UNUSED dispatch_data_t region
,
904 size_t offset
, const void *buffer
, size_t size
) {
905 const uint8_t *bytes
= buffer
;
908 for (i
= 0; i
< size
; i
++, count
++) {
909 uint8_t curr
= bytes
[i
], last
= 0;
911 if ((count
% 3) != 0) {
914 dispatch_data_t subrange
= _dispatch_data_subrange_map(data
,
916 if (subrange
== NULL
) {
920 dispatch_release(subrange
);
928 *ptr
++ = base64_encode_table
[(curr
>> 2) & 0x3f];
931 *ptr
++ = base64_encode_table
[((last
<< 4)|(curr
>> 4)) & 0x3f];
934 *ptr
++ = base64_encode_table
[((last
<< 2)|(curr
>> 6)) & 0x3f];
935 *ptr
++ = base64_encode_table
[(curr
& 0x3f)];
940 // Last region, insert padding bytes, if needed
941 if (offset
+ size
== total
) {
946 *ptr
++ = base64_encode_table
[(bytes
[size
-1] << 4) & 0x30];
951 *ptr
++ = base64_encode_table
[(bytes
[size
-1] << 2) & 0x3c];
964 return dispatch_data_create(dest
, dest_size
, NULL
,
965 DISPATCH_DATA_DESTRUCTOR_FREE
);
969 #pragma mark dispatch_data_transform
972 dispatch_data_create_with_transform(dispatch_data_t data
,
973 dispatch_data_format_type_t input
, dispatch_data_format_type_t output
)
975 if (input
->type
== _DISPATCH_DATA_FORMAT_UTF_ANY
) {
976 input
= _dispatch_transform_detect_utf(data
);
978 return DISPATCH_BAD_INPUT
;
982 if ((input
->type
& ~output
->input_mask
) != 0) {
983 return DISPATCH_BAD_INPUT
;
986 if ((output
->type
& ~input
->output_mask
) != 0) {
987 return DISPATCH_BAD_INPUT
;
990 if (dispatch_data_get_size(data
) == 0) {
994 dispatch_data_t temp1
;
996 temp1
= input
->decode(data
);
998 dispatch_retain(data
);
1003 return DISPATCH_BAD_INPUT
;
1006 dispatch_data_t temp2
;
1007 if (output
->encode
) {
1008 temp2
= output
->encode(temp1
);
1010 dispatch_retain(temp1
);
1014 dispatch_release(temp1
);
1018 const struct dispatch_data_format_type_s _dispatch_data_format_type_none
= {
1019 .type
= _DISPATCH_DATA_FORMAT_NONE
,
1026 const struct dispatch_data_format_type_s _dispatch_data_format_type_base32
= {
1027 .type
= _DISPATCH_DATA_FORMAT_BASE32
,
1028 .input_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1029 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1030 .output_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1031 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1032 .decode
= _dispatch_transform_from_base32
,
1033 .encode
= _dispatch_transform_to_base32
,
1036 const struct dispatch_data_format_type_s _dispatch_data_format_type_base32hex
=
1038 .type
= _DISPATCH_DATA_FORMAT_BASE32HEX
,
1039 .input_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1040 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1041 .output_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1042 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1043 .decode
= _dispatch_transform_from_base32hex
,
1044 .encode
= _dispatch_transform_to_base32hex
,
1047 const struct dispatch_data_format_type_s _dispatch_data_format_type_base64
= {
1048 .type
= _DISPATCH_DATA_FORMAT_BASE64
,
1049 .input_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1050 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1051 .output_mask
= (_DISPATCH_DATA_FORMAT_NONE
| _DISPATCH_DATA_FORMAT_BASE32
|
1052 _DISPATCH_DATA_FORMAT_BASE32HEX
| _DISPATCH_DATA_FORMAT_BASE64
),
1053 .decode
= _dispatch_transform_from_base64
,
1054 .encode
= _dispatch_transform_to_base64
,
1057 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf16le
= {
1058 .type
= _DISPATCH_DATA_FORMAT_UTF16LE
,
1059 .input_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1060 _DISPATCH_DATA_FORMAT_UTF16LE
),
1061 .output_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1062 _DISPATCH_DATA_FORMAT_UTF16LE
),
1063 .decode
= _dispatch_transform_from_utf16le
,
1064 .encode
= _dispatch_transform_to_utf16le
,
1067 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf16be
= {
1068 .type
= _DISPATCH_DATA_FORMAT_UTF16BE
,
1069 .input_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1070 _DISPATCH_DATA_FORMAT_UTF16LE
),
1071 .output_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1072 _DISPATCH_DATA_FORMAT_UTF16LE
),
1073 .decode
= _dispatch_transform_from_utf16be
,
1074 .encode
= _dispatch_transform_to_utf16be
,
1077 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf8
= {
1078 .type
= _DISPATCH_DATA_FORMAT_UTF8
,
1079 .input_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1080 _DISPATCH_DATA_FORMAT_UTF16LE
),
1081 .output_mask
= (_DISPATCH_DATA_FORMAT_UTF8
| _DISPATCH_DATA_FORMAT_UTF16BE
|
1082 _DISPATCH_DATA_FORMAT_UTF16LE
),
1087 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf_any
= {
1088 .type
= _DISPATCH_DATA_FORMAT_UTF_ANY
,