]> git.saurik.com Git - apple/libdispatch.git/blob - src/transform.c
libdispatch-228.18.tar.gz
[apple/libdispatch.git] / src / transform.c
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 #include "internal.h"
22
23 #include <libkern/OSByteOrder.h>
24
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
31 #endif
32
33 enum {
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_BASE64 = 0x40,
41 };
42
43 #pragma mark -
44 #pragma mark baseXX tables
45
46 static const char base32_encode_table[] =
47 "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789";
48
49 static const char base32_decode_table[] = {
50 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
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, 26,
53 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2,
54 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
55 20, 21, 22, 23, 24, 25
56 };
57 static const ssize_t base32_decode_table_size = sizeof(base32_decode_table)
58 / sizeof(*base32_decode_table);
59
60 static const char base64_encode_table[] =
61 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
62
63 static const char base64_decode_table[] = {
64 -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,
66 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
67 -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
68 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4,
69 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
70 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26,
71 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
72 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
73 };
74
75 static const ssize_t base64_decode_table_size = sizeof(base64_decode_table)
76 / sizeof(*base64_decode_table);
77
78 #pragma mark -
79 #pragma mark dispatch_transform_buffer
80
81 typedef struct dispatch_transform_buffer_s {
82 dispatch_data_t data;
83 uint8_t *start;
84 union {
85 uint8_t *u8;
86 uint16_t *u16;
87 } ptr;
88 size_t size;
89 } dispatch_transform_buffer_s;
90
91 static size_t
92 _dispatch_transform_sizet_mul(size_t a, size_t b)
93 {
94 size_t rv = SIZE_MAX;
95 if (a == 0 || rv/a >= b) {
96 rv = a * b;
97 }
98 return rv;
99 }
100
101 #define BUFFER_MALLOC_MAX (100*1024*1024)
102
103 static bool
104 _dispatch_transform_buffer_new(dispatch_transform_buffer_s *buffer,
105 size_t required, size_t size)
106 {
107 size_t remaining = buffer->size - (buffer->ptr.u8 - buffer->start);
108 if (required == 0 || remaining < required) {
109 if (buffer->start) {
110 if (buffer->ptr.u8 > buffer->start) {
111 dispatch_data_t _new = dispatch_data_create(buffer->start,
112 buffer->ptr.u8 - buffer->start, NULL,
113 DISPATCH_DATA_DESTRUCTOR_FREE);
114 dispatch_data_t _concat = dispatch_data_create_concat(
115 buffer->data, _new);
116 dispatch_release(_new);
117 dispatch_release(buffer->data);
118 buffer->data = _concat;
119 } else {
120 free(buffer->start);
121 }
122 }
123 buffer->size = required + size;
124 buffer->start = NULL;
125 if (buffer->size > 0) {
126 if (buffer->size > BUFFER_MALLOC_MAX) {
127 return false;
128 }
129 buffer->start = (uint8_t*)malloc(buffer->size);
130 if (buffer->start == NULL) {
131 return false;
132 }
133 }
134 buffer->ptr.u8 = buffer->start;
135 }
136 return true;
137 }
138
139 #pragma mark -
140 #pragma mark dispatch_transform_helpers
141
142 static dispatch_data_t
143 _dispatch_data_subrange_map(dispatch_data_t data, const void **ptr,
144 size_t offset, size_t size)
145 {
146 dispatch_data_t subrange, map = NULL;
147
148 subrange = dispatch_data_create_subrange(data, offset, size);
149 if (dispatch_data_get_size(subrange) == size) {
150 map = dispatch_data_create_map(subrange, ptr, NULL);
151 }
152 dispatch_release(subrange);
153 return map;
154 }
155
156 static dispatch_data_format_type_t
157 _dispatch_transform_detect_utf(dispatch_data_t data)
158 {
159 const void *p;
160 dispatch_data_t subrange = _dispatch_data_subrange_map(data, &p, 0, 2);
161
162 if (subrange == NULL) {
163 return NULL;
164 }
165
166 const uint16_t ch = *(const uint16_t *)p;
167 dispatch_data_format_type_t type = DISPATCH_DATA_FORMAT_TYPE_UTF8;
168
169 if (ch == 0xfeff) {
170 type = DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST;
171 } else if (ch == 0xfffe) {
172 type = DISPATCH_DATA_FORMAT_TYPE_UTF16_REV;
173 }
174
175 dispatch_release(subrange);
176
177 return type;
178 }
179
180 static uint16_t
181 _dispatch_transform_swap_to_host(uint16_t x, int32_t byteOrder)
182 {
183 if (byteOrder == OSLittleEndian) {
184 return OSSwapLittleToHostInt16(x);
185 }
186 return OSSwapBigToHostInt16(x);
187 }
188
189 static uint16_t
190 _dispatch_transform_swap_from_host(uint16_t x, int32_t byteOrder)
191 {
192 if (byteOrder == OSLittleEndian) {
193 return OSSwapHostToLittleInt16(x);
194 }
195 return OSSwapHostToBigInt16(x);
196 }
197
198 #pragma mark -
199 #pragma mark UTF-8
200
201 static uint8_t
202 _dispatch_transform_utf8_length(uint8_t byte)
203 {
204 if ((byte & 0x80) == 0) {
205 return 1;
206 } else if ((byte & 0xe0) == 0xc0) {
207 return 2;
208 } else if ((byte & 0xf0) == 0xe0) {
209 return 3;
210 } else if ((byte & 0xf8) == 0xf0) {
211 return 4;
212 }
213 return 0;
214 }
215
216 static uint32_t
217 _dispatch_transform_read_utf8_sequence(const uint8_t *bytes)
218 {
219 uint32_t wch = 0;
220 uint8_t seq_length = _dispatch_transform_utf8_length(*bytes);
221
222 switch (seq_length) {
223 case 4:
224 wch |= (*bytes & 0x7);
225 wch <<= 6;
226 break;
227 case 3:
228 wch |= (*bytes & 0xf);
229 wch <<= 6;
230 break;
231 case 2:
232 wch |= (*bytes & 0x1f);
233 wch <<= 6;
234 break;
235 case 1:
236 wch = (*bytes & 0x7f);
237 break;
238 default:
239 // Not a utf-8 sequence
240 break;
241 }
242
243 bytes++;
244 seq_length--;
245
246 while (seq_length > 0) {
247 wch |= (*bytes & 0x3f);
248 bytes++;
249 seq_length--;
250
251 if (seq_length > 0) {
252 wch <<= 6;
253 }
254 }
255 return wch;
256 }
257
258 #pragma mark -
259 #pragma mark UTF-16
260
261 static dispatch_data_t
262 _dispatch_transform_to_utf16(dispatch_data_t data, int32_t byteOrder)
263 {
264 __block size_t skip = 0;
265
266 __block dispatch_transform_buffer_s buffer = {
267 .data = dispatch_data_empty,
268 };
269
270 bool success = dispatch_data_apply(data, ^(
271 DISPATCH_UNUSED dispatch_data_t region,
272 size_t offset, const void *_buffer, size_t size) {
273 const uint8_t *src = _buffer;
274 size_t i;
275
276 if (offset == 0) {
277 size_t dest_size = 2 + _dispatch_transform_sizet_mul(size,
278 sizeof(uint16_t));
279 if (!_dispatch_transform_buffer_new(&buffer, dest_size, 0)) {
280 return (bool)false;
281 }
282 // Insert BOM
283 *(buffer.ptr.u16)++ = _dispatch_transform_swap_from_host(0xfeff,
284 byteOrder);
285 }
286
287 // Skip is incremented if the previous block read-ahead into our block
288 if (skip >= size) {
289 skip -= size;
290 return (bool)true;
291 } else if (skip > 0) {
292 src += skip;
293 size -= skip;
294 skip = 0;
295 }
296
297 for (i = 0; i < size;) {
298 uint32_t wch = 0;
299 uint8_t byte_size = _dispatch_transform_utf8_length(*src);
300
301 if (byte_size == 0) {
302 return (bool)false;
303 } else if (byte_size + i > size) {
304 // UTF-8 byte sequence spans over into the next block(s)
305 const void *p;
306 dispatch_data_t subrange = _dispatch_data_subrange_map(data, &p,
307 offset + i, byte_size);
308 if (subrange == NULL) {
309 return (bool)false;
310 }
311
312 wch = _dispatch_transform_read_utf8_sequence(p);
313 skip += byte_size - (size - i);
314 src += byte_size;
315 i = size;
316
317 dispatch_release(subrange);
318 } else {
319 wch = _dispatch_transform_read_utf8_sequence(src);
320 src += byte_size;
321 i += byte_size;
322 }
323
324 size_t next = _dispatch_transform_sizet_mul(size - i, sizeof(uint16_t));
325 if (wch >= 0xd800 && wch < 0xdfff) {
326 // Illegal range (surrogate pair)
327 return (bool)false;
328 } else if (wch >= 0x10000) {
329 // Surrogate pair
330 if (!_dispatch_transform_buffer_new(&buffer, 2 *
331 sizeof(uint16_t), next)) {
332 return (bool)false;
333 }
334 wch -= 0x10000;
335 *(buffer.ptr.u16)++ = _dispatch_transform_swap_from_host(
336 ((wch >> 10) & 0x3ff) + 0xd800, byteOrder);
337 *(buffer.ptr.u16)++ = _dispatch_transform_swap_from_host(
338 (wch & 0x3ff) + 0xdc00, byteOrder);
339 } else {
340 if (!_dispatch_transform_buffer_new(&buffer, 1 *
341 sizeof(uint16_t), next)) {
342 return (bool)false;
343 }
344 *(buffer.ptr.u16)++ = _dispatch_transform_swap_from_host(
345 (wch & 0xffff), byteOrder);
346 }
347 }
348
349 (void)_dispatch_transform_buffer_new(&buffer, 0, 0);
350
351 return (bool)true;
352 });
353
354 if (!success) {
355 dispatch_release(buffer.data);
356 return NULL;
357 }
358
359 return buffer.data;
360 }
361
362 static dispatch_data_t
363 _dispatch_transform_from_utf16(dispatch_data_t data, int32_t byteOrder)
364 {
365 __block size_t skip = 0;
366
367 __block dispatch_transform_buffer_s buffer = {
368 .data = dispatch_data_empty,
369 };
370
371 bool success = dispatch_data_apply(data, ^(
372 DISPATCH_UNUSED dispatch_data_t region, size_t offset,
373 const void *_buffer, size_t size) {
374 const uint16_t *src = _buffer;
375
376 if (offset == 0) {
377 // Assume first buffer will be mostly single-byte UTF-8 sequences
378 size_t dest_size = _dispatch_transform_sizet_mul(size, 2) / 3;
379 if (!_dispatch_transform_buffer_new(&buffer, dest_size, 0)) {
380 return (bool)false;
381 }
382 }
383
384 size_t i = 0, max = size / 2;
385
386 // Skip is incremented if the previous block read-ahead into our block
387 if (skip >= size) {
388 skip -= size;
389 return (bool)true;
390 } else if (skip > 0) {
391 src = (uint16_t *)(((uint8_t *)src) + skip);
392 size -= skip;
393 max = (size / 2);
394 skip = 0;
395 }
396
397 // If the buffer is an odd size, allow read ahead into the next region
398 if ((size % 2) != 0) {
399 max += 1;
400 }
401
402 for (i = 0; i < max; i++) {
403 uint32_t wch = 0;
404 uint16_t ch;
405
406 if ((i == (max - 1)) && (max > (size / 2))) {
407 // Last byte of an odd sized range
408 const void *p;
409 dispatch_data_t range = _dispatch_data_subrange_map(data, &p,
410 offset + (i * 2), 2);
411 if (range == NULL) {
412 return (bool)false;
413 }
414 ch = _dispatch_transform_swap_to_host(*(uint64_t*)p, byteOrder);
415 dispatch_release(range);
416 skip += 1;
417 } else {
418 ch = _dispatch_transform_swap_to_host(src[i], byteOrder);
419 }
420
421 if (ch == 0xfffe && offset == 0 && i == 0) {
422 // Wrong-endian BOM at beginning of data
423 return (bool)false;
424 } else if (ch == 0xfeff && offset == 0 && i == 0) {
425 // Correct-endian BOM, skip it
426 continue;
427 }
428
429 if ((ch >= 0xd800) && (ch <= 0xdbff)) {
430 // Surrogate pair
431 wch = ((ch - 0xd800) << 10);
432 if (++i >= max) {
433 // Surrogate byte isn't in this block
434 const void *p;
435 dispatch_data_t range = _dispatch_data_subrange_map(data,
436 &p, offset + (i * 2), 2);
437 if (range == NULL) {
438 return (bool)false;
439 }
440 ch = _dispatch_transform_swap_to_host(*(uint16_t *)p,
441 byteOrder);
442 dispatch_release(range);
443 skip += 2;
444 } else {
445 ch = _dispatch_transform_swap_to_host(src[i], byteOrder);
446 }
447 if (!((ch >= 0xdc00) && (ch <= 0xdfff))) {
448 return (bool)false;
449 }
450 wch = (wch | (ch & 0x3ff));
451 wch += 0x10000;
452 } else if ((ch >= 0xdc00) && (ch <= 0xdfff)) {
453 return (bool)false;
454 } else {
455 wch = ch;
456 }
457
458 size_t next = _dispatch_transform_sizet_mul(max - i, 2);
459 if (wch < 0x80) {
460 if (!_dispatch_transform_buffer_new(&buffer, 1, next)) {
461 return (bool)false;
462 }
463 *(buffer.ptr.u8)++ = (uint8_t)(wch & 0xff);
464 } else if (wch < 0x800) {
465 if (!_dispatch_transform_buffer_new(&buffer, 2, next)) {
466 return (bool)false;
467 }
468 *(buffer.ptr.u8)++ = (uint8_t)(0xc0 | (wch >> 6));
469 *(buffer.ptr.u8)++ = (uint8_t)(0x80 | (wch & 0x3f));
470 } else if (wch < 0x10000) {
471 if (!_dispatch_transform_buffer_new(&buffer, 3, next)) {
472 return (bool)false;
473 }
474 *(buffer.ptr.u8)++ = (uint8_t)(0xe0 | (wch >> 12));
475 *(buffer.ptr.u8)++ = (uint8_t)(0x80 | ((wch >> 6) & 0x3f));
476 *(buffer.ptr.u8)++ = (uint8_t)(0x80 | (wch & 0x3f));
477 } else if (wch < 0x200000) {
478 if (!_dispatch_transform_buffer_new(&buffer, 4, next)) {
479 return (bool)false;
480 }
481 *(buffer.ptr.u8)++ = (uint8_t)(0xf0 | (wch >> 18));
482 *(buffer.ptr.u8)++ = (uint8_t)(0x80 | ((wch >> 12) & 0x3f));
483 *(buffer.ptr.u8)++ = (uint8_t)(0x80 | ((wch >> 6) & 0x3f));
484 *(buffer.ptr.u8)++ = (uint8_t)(0x80 | (wch & 0x3f));
485 }
486 }
487
488 (void)_dispatch_transform_buffer_new(&buffer, 0, 0);
489
490 return (bool)true;
491 });
492
493 if (!success) {
494 dispatch_release(buffer.data);
495 return NULL;
496 }
497
498 return buffer.data;
499 }
500
501 static dispatch_data_t
502 _dispatch_transform_from_utf16le(dispatch_data_t data)
503 {
504 return _dispatch_transform_from_utf16(data, OSLittleEndian);
505 }
506
507 static dispatch_data_t
508 _dispatch_transform_from_utf16be(dispatch_data_t data)
509 {
510 return _dispatch_transform_from_utf16(data, OSBigEndian);
511 }
512
513 static dispatch_data_t
514 _dispatch_transform_to_utf16le(dispatch_data_t data)
515 {
516 return _dispatch_transform_to_utf16(data, OSLittleEndian);
517 }
518
519 static dispatch_data_t
520 _dispatch_transform_to_utf16be(dispatch_data_t data)
521 {
522 return _dispatch_transform_to_utf16(data, OSBigEndian);
523 }
524
525 #pragma mark -
526 #pragma mark base32
527
528 static dispatch_data_t
529 _dispatch_transform_from_base32(dispatch_data_t data)
530 {
531 __block uint64_t x = 0, count = 0, pad = 0;
532
533 __block dispatch_data_t rv = dispatch_data_empty;
534
535 bool success = dispatch_data_apply(data, ^(
536 DISPATCH_UNUSED dispatch_data_t region,
537 DISPATCH_UNUSED size_t offset, const void *buffer, size_t size) {
538 size_t i, dest_size = (size * 5) / 8;
539
540 uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(char));
541 uint8_t *ptr = dest;
542 if (dest == NULL) {
543 return (bool)false;
544 }
545
546 const uint8_t *bytes = buffer;
547
548 for (i = 0; i < size; i++) {
549 if (bytes[i] == '\n' || bytes[i] == '\t' || bytes[i] == ' ') {
550 continue;
551 }
552
553 ssize_t index = bytes[i];
554 if (index >= base32_decode_table_size ||
555 base32_decode_table[index] == -1) {
556 free(dest);
557 return (bool)false;
558 }
559 count++;
560
561 char value = base32_decode_table[index];
562 if (value == -2) {
563 value = 0;
564 pad++;
565 }
566
567 x <<= 5;
568 x += value;
569
570 if ((count & 0x7) == 0) {
571 *ptr++ = (x >> 32) & 0xff;
572 *ptr++ = (x >> 24) & 0xff;
573 *ptr++ = (x >> 16) & 0xff;
574 *ptr++ = (x >> 8) & 0xff;
575 *ptr++ = x & 0xff;
576 }
577 }
578
579 size_t final = (ptr - dest);
580 switch (pad) {
581 case 1:
582 final -= 1;
583 break;
584 case 3:
585 final -= 2;
586 break;
587 case 4:
588 final -= 3;
589 break;
590 case 6:
591 final -= 4;
592 break;
593 }
594
595 dispatch_data_t val = dispatch_data_create(dest, final, NULL,
596 DISPATCH_DATA_DESTRUCTOR_FREE);
597 dispatch_data_t concat = dispatch_data_create_concat(rv, val);
598
599 dispatch_release(val);
600 dispatch_release(rv);
601 rv = concat;
602
603 return (bool)true;
604 });
605
606 if (!success) {
607 dispatch_release(rv);
608 return NULL;
609 }
610
611 return rv;
612 }
613
614 static dispatch_data_t
615 _dispatch_transform_to_base32(dispatch_data_t data)
616 {
617 size_t total = dispatch_data_get_size(data);
618 __block size_t count = 0;
619
620 size_t dest_size = ((total + 4) * 8) / 5;
621 dest_size -= dest_size % 8;
622
623 uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t));
624 if (dest == NULL) {
625 return NULL;
626 }
627
628 __block uint8_t *ptr = dest;
629
630 /*
631 0 1 2 3 4
632 8-bit bytes: xxxxxxxx yyyyyyyy zzzzzzzz xxxxxxxx yyyyyyyy
633 5-bit chunks: aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh
634 */
635
636 bool success = dispatch_data_apply(data, ^(
637 DISPATCH_UNUSED dispatch_data_t region,
638 size_t offset, const void *buffer, size_t size) {
639 const uint8_t *bytes = buffer;
640 size_t i;
641
642 for (i = 0; i < size; i++, count++) {
643 uint8_t curr = bytes[i], last = 0;
644
645 if ((count % 5) != 0) {
646 if (i == 0) {
647 const void *p;
648 dispatch_data_t subrange = _dispatch_data_subrange_map(data,
649 &p, offset - 1, 1);
650 if (subrange == NULL) {
651 return (bool)false;
652 }
653 last = *(uint8_t*)p;
654 dispatch_release(subrange);
655 } else {
656 last = bytes[i - 1];
657 }
658 }
659
660 switch (count % 5) {
661 case 0:
662 // a
663 *ptr++ = base32_encode_table[(curr >> 3) & 0x1f];
664 break;
665 case 1:
666 // b + c
667 *ptr++ = base32_encode_table[((last << 2)|(curr >> 6)) & 0x1f];
668 *ptr++ = base32_encode_table[(curr >> 1) & 0x1f];
669 break;
670 case 2:
671 // d
672 *ptr++ = base32_encode_table[((last << 4)|(curr >> 4)) & 0x1f];
673 break;
674 case 3:
675 // e + f
676 *ptr++ = base32_encode_table[((last << 1)|(curr >> 7)) & 0x1f];
677 *ptr++ = base32_encode_table[(curr >> 2) & 0x1f];
678 break;
679 case 4:
680 // g + h
681 *ptr++ = base32_encode_table[((last << 3)|(curr >> 5)) & 0x1f];
682 *ptr++ = base32_encode_table[curr & 0x1f];
683 break;
684 }
685 }
686
687 // Last region, insert padding bytes, if needed
688 if (offset + size == total) {
689 switch (count % 5) {
690 case 0:
691 break;
692 case 1:
693 // b[4:2]
694 *ptr++ = base32_encode_table[(bytes[size-1] << 2) & 0x1c];
695 break;
696 case 2:
697 // d[4]
698 *ptr++ = base32_encode_table[(bytes[size-1] << 4) & 0x10];
699 break;
700 case 3:
701 // e[4:1]
702 *ptr++ = base32_encode_table[(bytes[size-1] << 1) & 0x1e];
703 break;
704 case 4:
705 // g[4:3]
706 *ptr++ = base32_encode_table[bytes[size-1] & 0x18];
707 break;
708 }
709 switch (count % 5) {
710 case 0:
711 break;
712 case 1:
713 *ptr++ = '='; // c
714 *ptr++ = '='; // d
715 case 2:
716 *ptr++ = '='; // e
717 case 3:
718 *ptr++ = '='; // f
719 *ptr++ = '='; // g
720 case 4:
721 *ptr++ = '='; // h
722 break;
723 }
724 }
725
726 return (bool)true;
727 });
728
729 if (!success) {
730 free(dest);
731 return NULL;
732 }
733 return dispatch_data_create(dest, dest_size, NULL,
734 DISPATCH_DATA_DESTRUCTOR_FREE);
735 }
736
737 #pragma mark -
738 #pragma mark base64
739
740 static dispatch_data_t
741 _dispatch_transform_from_base64(dispatch_data_t data)
742 {
743 __block uint64_t x = 0, count = 0;
744 __block size_t pad = 0;
745
746 __block dispatch_data_t rv = dispatch_data_empty;
747
748 bool success = dispatch_data_apply(data, ^(
749 DISPATCH_UNUSED dispatch_data_t region,
750 DISPATCH_UNUSED size_t offset, const void *buffer, size_t size) {
751 size_t i, dest_size = (size * 3) / 4;
752
753 uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t));
754 uint8_t *ptr = dest;
755 if (dest == NULL) {
756 return (bool)false;
757 }
758
759 const uint8_t *bytes = buffer;
760
761 for (i = 0; i < size; i++) {
762 if (bytes[i] == '\n' || bytes[i] == '\t' || bytes[i] == ' ') {
763 continue;
764 }
765
766 ssize_t index = bytes[i];
767 if (index >= base64_decode_table_size ||
768 base64_decode_table[index] == -1) {
769 free(dest);
770 return (bool)false;
771 }
772 count++;
773
774 char value = base64_decode_table[index];
775 if (value == -2) {
776 value = 0;
777 pad++;
778 }
779
780 x <<= 6;
781 x += value;
782
783 if ((count & 0x3) == 0) {
784 *ptr++ = (x >> 16) & 0xff;
785 *ptr++ = (x >> 8) & 0xff;
786 *ptr++ = x & 0xff;
787 }
788 }
789
790 size_t final = (ptr - dest);
791 if (pad > 0) {
792 // 2 bytes of pad means only had one char in final group
793 final -= pad;
794 }
795
796 dispatch_data_t val = dispatch_data_create(dest, final, NULL,
797 DISPATCH_DATA_DESTRUCTOR_FREE);
798 dispatch_data_t concat = dispatch_data_create_concat(rv, val);
799
800 dispatch_release(val);
801 dispatch_release(rv);
802 rv = concat;
803
804 return (bool)true;
805 });
806
807 if (!success) {
808 dispatch_release(rv);
809 return NULL;
810 }
811
812 return rv;
813 }
814
815 static dispatch_data_t
816 _dispatch_transform_to_base64(dispatch_data_t data)
817 {
818 // RFC 4648 states that we should not linebreak
819 // http://tools.ietf.org/html/rfc4648
820 size_t total = dispatch_data_get_size(data);
821 __block size_t count = 0;
822
823 size_t dest_size = ((total + 2) * 4) / 3;
824 dest_size -= dest_size % 4;
825
826 uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t));
827 if (dest == NULL) {
828 return NULL;
829 }
830
831 __block uint8_t *ptr = dest;
832
833 /*
834 * 3 8-bit bytes: xxxxxxxx yyyyyyyy zzzzzzzz
835 * 4 6-bit chunks: aaaaaabb bbbbcccc ccdddddd
836 */
837
838 bool success = dispatch_data_apply(data, ^(
839 DISPATCH_UNUSED dispatch_data_t region,
840 size_t offset, const void *buffer, size_t size) {
841 const uint8_t *bytes = buffer;
842 size_t i;
843
844 for (i = 0; i < size; i++, count++) {
845 uint8_t curr = bytes[i], last = 0;
846
847 if ((count % 3) != 0) {
848 if (i == 0) {
849 const void *p;
850 dispatch_data_t subrange = _dispatch_data_subrange_map(data,
851 &p, offset - 1, 1);
852 if (subrange == NULL) {
853 return (bool)false;
854 }
855 last = *(uint8_t*)p;
856 dispatch_release(subrange);
857 } else {
858 last = bytes[i - 1];
859 }
860 }
861
862 switch (count % 3) {
863 case 0:
864 *ptr++ = base64_encode_table[(curr >> 2) & 0x3f];
865 break;
866 case 1:
867 *ptr++ = base64_encode_table[((last << 4)|(curr >> 4)) & 0x3f];
868 break;
869 case 2:
870 *ptr++ = base64_encode_table[((last << 2)|(curr >> 6)) & 0x3f];
871 *ptr++ = base64_encode_table[(curr & 0x3f)];
872 break;
873 }
874 }
875
876 // Last region, insert padding bytes, if needed
877 if (offset + size == total) {
878 switch (count % 3) {
879 case 0:
880 break;
881 case 1:
882 *ptr++ = base64_encode_table[(bytes[size-1] << 4) & 0x30];
883 *ptr++ = '=';
884 *ptr++ = '=';
885 break;
886 case 2:
887 *ptr++ = base64_encode_table[(bytes[size-1] << 2) & 0x3c];
888 *ptr++ = '=';
889 break;
890 }
891 }
892
893 return (bool)true;
894 });
895
896 if (!success) {
897 free(dest);
898 return NULL;
899 }
900 return dispatch_data_create(dest, dest_size, NULL,
901 DISPATCH_DATA_DESTRUCTOR_FREE);
902 }
903
904 #pragma mark -
905 #pragma mark dispatch_data_transform
906
907 dispatch_data_t
908 dispatch_data_create_with_transform(dispatch_data_t data,
909 dispatch_data_format_type_t input, dispatch_data_format_type_t output)
910 {
911 if (input->type == _DISPATCH_DATA_FORMAT_UTF_ANY) {
912 input = _dispatch_transform_detect_utf(data);
913 }
914
915 if ((input->type & ~output->input_mask) != 0) {
916 return NULL;
917 }
918
919 if ((output->type & ~input->output_mask) != 0) {
920 return NULL;
921 }
922
923 if (dispatch_data_get_size(data) == 0) {
924 return data;
925 }
926
927 dispatch_data_t temp1;
928 if (input->decode) {
929 temp1 = input->decode(data);
930 } else {
931 dispatch_retain(data);
932 temp1 = data;
933 }
934
935 if (!temp1) {
936 return NULL;
937 }
938
939 dispatch_data_t temp2;
940 if (output->encode) {
941 temp2 = output->encode(temp1);
942 } else {
943 dispatch_retain(temp1);
944 temp2 = temp1;
945 }
946
947 dispatch_release(temp1);
948 return temp2;
949 }
950
951 const struct dispatch_data_format_type_s _dispatch_data_format_type_none = {
952 .type = _DISPATCH_DATA_FORMAT_NONE,
953 .input_mask = ~0,
954 .output_mask = ~0,
955 .decode = NULL,
956 .encode = NULL,
957 };
958
959 const struct dispatch_data_format_type_s _dispatch_data_format_type_base32 = {
960 .type = _DISPATCH_DATA_FORMAT_BASE32,
961 .input_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 |
962 _DISPATCH_DATA_FORMAT_BASE64),
963 .output_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 |
964 _DISPATCH_DATA_FORMAT_BASE64),
965 .decode = _dispatch_transform_from_base32,
966 .encode = _dispatch_transform_to_base32,
967 };
968
969 const struct dispatch_data_format_type_s _dispatch_data_format_type_base64 = {
970 .type = _DISPATCH_DATA_FORMAT_BASE64,
971 .input_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 |
972 _DISPATCH_DATA_FORMAT_BASE64),
973 .output_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 |
974 _DISPATCH_DATA_FORMAT_BASE64),
975 .decode = _dispatch_transform_from_base64,
976 .encode = _dispatch_transform_to_base64,
977 };
978
979 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf16le = {
980 .type = _DISPATCH_DATA_FORMAT_UTF16LE,
981 .input_mask = (_DISPATCH_DATA_FORMAT_UTF8 | _DISPATCH_DATA_FORMAT_UTF16BE |
982 _DISPATCH_DATA_FORMAT_UTF16LE),
983 .output_mask = (_DISPATCH_DATA_FORMAT_UTF8 | _DISPATCH_DATA_FORMAT_UTF16BE |
984 _DISPATCH_DATA_FORMAT_UTF16LE),
985 .decode = _dispatch_transform_from_utf16le,
986 .encode = _dispatch_transform_to_utf16le,
987 };
988
989 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf16be = {
990 .type = _DISPATCH_DATA_FORMAT_UTF16BE,
991 .input_mask = (_DISPATCH_DATA_FORMAT_UTF8 | _DISPATCH_DATA_FORMAT_UTF16BE |
992 _DISPATCH_DATA_FORMAT_UTF16LE),
993 .output_mask = (_DISPATCH_DATA_FORMAT_UTF8 | _DISPATCH_DATA_FORMAT_UTF16BE |
994 _DISPATCH_DATA_FORMAT_UTF16LE),
995 .decode = _dispatch_transform_from_utf16be,
996 .encode = _dispatch_transform_to_utf16be,
997 };
998
999 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf8 = {
1000 .type = _DISPATCH_DATA_FORMAT_UTF8,
1001 .input_mask = (_DISPATCH_DATA_FORMAT_UTF8 | _DISPATCH_DATA_FORMAT_UTF16BE |
1002 _DISPATCH_DATA_FORMAT_UTF16LE),
1003 .output_mask = (_DISPATCH_DATA_FORMAT_UTF8 | _DISPATCH_DATA_FORMAT_UTF16BE |
1004 _DISPATCH_DATA_FORMAT_UTF16LE),
1005 .decode = NULL,
1006 .encode = NULL,
1007 };
1008
1009 const struct dispatch_data_format_type_s _dispatch_data_format_type_utf_any = {
1010 .type = _DISPATCH_DATA_FORMAT_UTF_ANY,
1011 .input_mask = 0,
1012 .output_mask = 0,
1013 .decode = NULL,
1014 .encode = NULL,
1015 };