X-Git-Url: https://git.saurik.com/apple/libdispatch.git/blobdiff_plain/fe4ce08b25268ab7a007bb9eb2dd578ca5a9d5e8..refs/heads/master:/src/transform.c diff --git a/src/transform.c b/src/transform.c index 3bb1e3e..2c885ca 100644 --- a/src/transform.c +++ b/src/transform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Apple Inc. All rights reserved. + * Copyright (c) 2011-2013 Apple Inc. All rights reserved. * * @APPLE_APACHE_LICENSE_HEADER_START@ * @@ -20,7 +20,17 @@ #include "internal.h" +#ifdef __APPLE__ #include +#elif __linux__ +#include +#define OSLittleEndian __LITTLE_ENDIAN +#define OSBigEndian __BIG_ENDIAN +#define OSSwapLittleToHostInt16 le16toh +#define OSSwapBigToHostInt16 be16toh +#define OSSwapHostToLittleInt16 htole16 +#define OSSwapHostToBigInt16 htobe16 +#endif #if defined(__LITTLE_ENDIAN__) #define DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST DISPATCH_DATA_FORMAT_TYPE_UTF16LE @@ -28,6 +38,8 @@ #elif defined(__BIG_ENDIAN__) #define DISPATCH_DATA_FORMAT_TYPE_UTF16_HOST DISPATCH_DATA_FORMAT_TYPE_UTF16BE #define DISPATCH_DATA_FORMAT_TYPE_UTF16_REV DISPATCH_DATA_FORMAT_TYPE_UTF16LE +#else +#error Unsupported Endianness #endif enum { @@ -37,14 +49,15 @@ enum { _DISPATCH_DATA_FORMAT_UTF16BE = 0x8, _DISPATCH_DATA_FORMAT_UTF_ANY = 0x10, _DISPATCH_DATA_FORMAT_BASE32 = 0x20, - _DISPATCH_DATA_FORMAT_BASE64 = 0x40, + _DISPATCH_DATA_FORMAT_BASE32HEX = 0x40, + _DISPATCH_DATA_FORMAT_BASE64 = 0x80, }; #pragma mark - #pragma mark baseXX tables -static const char base32_encode_table[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; +static const unsigned char base32_encode_table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; static const char base32_decode_table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -57,7 +70,21 @@ static const char base32_decode_table[] = { static const ssize_t base32_decode_table_size = sizeof(base32_decode_table) / sizeof(*base32_decode_table); -static const char base64_encode_table[] = +static const unsigned char base32hex_encode_table[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + +static const char base32hex_decode_table[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -2, -1, -1, -1, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31 +}; +static const ssize_t base32hex_decode_table_size = + sizeof(base32hex_encode_table) / sizeof(*base32hex_encode_table); + +static const unsigned char base64_encode_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char base64_decode_table[] = { @@ -88,28 +115,18 @@ typedef struct dispatch_transform_buffer_s { size_t size; } dispatch_transform_buffer_s; -static size_t -_dispatch_transform_sizet_mul(size_t a, size_t b) -{ - size_t rv = SIZE_MAX; - if (a == 0 || rv/a >= b) { - rv = a * b; - } - return rv; -} - #define BUFFER_MALLOC_MAX (100*1024*1024) static bool _dispatch_transform_buffer_new(dispatch_transform_buffer_s *buffer, size_t required, size_t size) { - size_t remaining = buffer->size - (buffer->ptr.u8 - buffer->start); + size_t remaining = buffer->size - (size_t)(buffer->ptr.u8 - buffer->start); if (required == 0 || remaining < required) { if (buffer->start) { if (buffer->ptr.u8 > buffer->start) { dispatch_data_t _new = dispatch_data_create(buffer->start, - buffer->ptr.u8 - buffer->start, NULL, + (size_t)(buffer->ptr.u8 - buffer->start), NULL, DISPATCH_DATA_DESTRUCTOR_FREE); dispatch_data_t _concat = dispatch_data_create_concat( buffer->data, _new); @@ -271,11 +288,13 @@ _dispatch_transform_to_utf16(dispatch_data_t data, int32_t byteOrder) DISPATCH_UNUSED dispatch_data_t region, size_t offset, const void *_buffer, size_t size) { const uint8_t *src = _buffer; - size_t i; + size_t i, dest_size; if (offset == 0) { - size_t dest_size = 2 + _dispatch_transform_sizet_mul(size, - sizeof(uint16_t)); + if (os_mul_and_add_overflow(size, sizeof(uint16_t), + sizeof(uint16_t), &dest_size)) { + return (bool)false; + } if (!_dispatch_transform_buffer_new(&buffer, dest_size, 0)) { return (bool)false; } @@ -297,6 +316,7 @@ _dispatch_transform_to_utf16(dispatch_data_t data, int32_t byteOrder) for (i = 0; i < size;) { uint32_t wch = 0; uint8_t byte_size = _dispatch_transform_utf8_length(*src); + size_t next; if (byte_size == 0) { return (bool)false; @@ -321,7 +341,9 @@ _dispatch_transform_to_utf16(dispatch_data_t data, int32_t byteOrder) i += byte_size; } - size_t next = _dispatch_transform_sizet_mul(size - i, sizeof(uint16_t)); + if (os_mul_overflow(size - i, sizeof(uint16_t), &next)) { + return (bool)false; + } if (wch >= 0xd800 && wch < 0xdfff) { // Illegal range (surrogate pair) return (bool)false; @@ -375,8 +397,8 @@ _dispatch_transform_from_utf16(dispatch_data_t data, int32_t byteOrder) const uint16_t *src = _buffer; if (offset == 0) { + size_t dest_size = howmany(size, 3) * 2; // Assume first buffer will be mostly single-byte UTF-8 sequences - size_t dest_size = _dispatch_transform_sizet_mul(size, 2) / 3; if (!_dispatch_transform_buffer_new(&buffer, dest_size, 0)) { return (bool)false; } @@ -403,6 +425,7 @@ _dispatch_transform_from_utf16(dispatch_data_t data, int32_t byteOrder) for (i = 0; i < max; i++) { uint32_t wch = 0; uint16_t ch; + size_t next; if ((i == (max - 1)) && (max > (size / 2))) { // Last byte of an odd sized range @@ -412,7 +435,8 @@ _dispatch_transform_from_utf16(dispatch_data_t data, int32_t byteOrder) if (range == NULL) { return (bool)false; } - ch = _dispatch_transform_swap_to_host(*(uint64_t*)p, byteOrder); + ch = _dispatch_transform_swap_to_host((uint16_t)*(uint64_t*)p, + byteOrder); dispatch_release(range); skip += 1; } else { @@ -429,7 +453,7 @@ _dispatch_transform_from_utf16(dispatch_data_t data, int32_t byteOrder) if ((ch >= 0xd800) && (ch <= 0xdbff)) { // Surrogate pair - wch = ((ch - 0xd800) << 10); + wch = ((ch - 0xd800u) << 10); if (++i >= max) { // Surrogate byte isn't in this block const void *p; @@ -456,7 +480,9 @@ _dispatch_transform_from_utf16(dispatch_data_t data, int32_t byteOrder) wch = ch; } - size_t next = _dispatch_transform_sizet_mul(max - i, 2); + if (os_mul_overflow(max - i, 2, &next)) { + return (bool)false; + } if (wch < 0x80) { if (!_dispatch_transform_buffer_new(&buffer, 1, next)) { return (bool)false; @@ -528,7 +554,8 @@ _dispatch_transform_to_utf16be(dispatch_data_t data) #pragma mark base32 static dispatch_data_t -_dispatch_transform_from_base32(dispatch_data_t data) +_dispatch_transform_from_base32_with_table(dispatch_data_t data, + const char* table, ssize_t table_size) { __block uint64_t x = 0, count = 0, pad = 0; @@ -537,9 +564,8 @@ _dispatch_transform_from_base32(dispatch_data_t data) bool success = dispatch_data_apply(data, ^( DISPATCH_UNUSED dispatch_data_t region, DISPATCH_UNUSED size_t offset, const void *buffer, size_t size) { - size_t i, dest_size = (size * 5) / 8; - - uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(char)); + size_t i, dest_size = howmany(size, 8) * 5; + uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t)); uint8_t *ptr = dest; if (dest == NULL) { return (bool)false; @@ -553,21 +579,20 @@ _dispatch_transform_from_base32(dispatch_data_t data) } ssize_t index = bytes[i]; - if (index >= base32_decode_table_size || - base32_decode_table[index] == -1) { + if (index >= table_size || table[index] == -1) { free(dest); return (bool)false; } count++; - char value = base32_decode_table[index]; + char value = table[index]; if (value == -2) { value = 0; pad++; } x <<= 5; - x += value; + x += (uint64_t)value; if ((count & 0x7) == 0) { *ptr++ = (x >> 32) & 0xff; @@ -578,7 +603,7 @@ _dispatch_transform_from_base32(dispatch_data_t data) } } - size_t final = (ptr - dest); + size_t final = (size_t)(ptr - dest); switch (pad) { case 1: final -= 1; @@ -614,15 +639,20 @@ _dispatch_transform_from_base32(dispatch_data_t data) } static dispatch_data_t -_dispatch_transform_to_base32(dispatch_data_t data) +_dispatch_transform_to_base32_with_table(dispatch_data_t data, const unsigned char* table) { - size_t total = dispatch_data_get_size(data); + size_t total = dispatch_data_get_size(data), dest_size; __block size_t count = 0; - size_t dest_size = ((total + 4) * 8) / 5; - dest_size -= dest_size % 8; + dest_size = howmany(total, 5); + // + // os_mul_overflow(dest_size, 8, &dest_size) + if (dest_size > SIZE_T_MAX / 8) { + return NULL; + } + dest_size *= 8; - uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t)); + uint8_t *dest = (uint8_t*)malloc(dest_size); if (dest == NULL) { return NULL; } @@ -662,26 +692,26 @@ _dispatch_transform_to_base32(dispatch_data_t data) switch (count % 5) { case 0: // a - *ptr++ = base32_encode_table[(curr >> 3) & 0x1f]; + *ptr++ = table[(curr >> 3) & 0x1fu]; break; case 1: // b + c - *ptr++ = base32_encode_table[((last << 2)|(curr >> 6)) & 0x1f]; - *ptr++ = base32_encode_table[(curr >> 1) & 0x1f]; + *ptr++ = table[((last << 2)|(curr >> 6)) & 0x1f]; + *ptr++ = table[(curr >> 1) & 0x1f]; break; case 2: // d - *ptr++ = base32_encode_table[((last << 4)|(curr >> 4)) & 0x1f]; + *ptr++ = table[((last << 4)|(curr >> 4)) & 0x1f]; break; case 3: // e + f - *ptr++ = base32_encode_table[((last << 1)|(curr >> 7)) & 0x1f]; - *ptr++ = base32_encode_table[(curr >> 2) & 0x1f]; + *ptr++ = table[((last << 1)|(curr >> 7)) & 0x1f]; + *ptr++ = table[(curr >> 2) & 0x1f]; break; case 4: // g + h - *ptr++ = base32_encode_table[((last << 3)|(curr >> 5)) & 0x1f]; - *ptr++ = base32_encode_table[curr & 0x1f]; + *ptr++ = table[((last << 3)|(curr >> 5)) & 0x1f]; + *ptr++ = table[curr & 0x1f]; break; } } @@ -693,19 +723,19 @@ _dispatch_transform_to_base32(dispatch_data_t data) break; case 1: // b[4:2] - *ptr++ = base32_encode_table[(bytes[size-1] << 2) & 0x1c]; + *ptr++ = table[(bytes[size-1] << 2) & 0x1c]; break; case 2: // d[4] - *ptr++ = base32_encode_table[(bytes[size-1] << 4) & 0x10]; + *ptr++ = table[(bytes[size-1] << 4) & 0x10]; break; case 3: // e[4:1] - *ptr++ = base32_encode_table[(bytes[size-1] << 1) & 0x1e]; + *ptr++ = table[(bytes[size-1] << 1) & 0x1e]; break; case 4: - // g[4:3] - *ptr++ = base32_encode_table[bytes[size-1] & 0x18]; + // g[2:3] + *ptr++ = table[(bytes[size-1] << 3) & 0x18]; break; } switch (count % 5) { @@ -736,6 +766,33 @@ _dispatch_transform_to_base32(dispatch_data_t data) DISPATCH_DATA_DESTRUCTOR_FREE); } +static dispatch_data_t +_dispatch_transform_from_base32(dispatch_data_t data) +{ + return _dispatch_transform_from_base32_with_table(data, base32_decode_table, + base32_decode_table_size); +} + +static dispatch_data_t +_dispatch_transform_to_base32(dispatch_data_t data) +{ + return _dispatch_transform_to_base32_with_table(data, base32_encode_table); +} + +static dispatch_data_t +_dispatch_transform_from_base32hex(dispatch_data_t data) +{ + return _dispatch_transform_from_base32_with_table(data, + base32hex_decode_table, base32hex_decode_table_size); +} + +static dispatch_data_t +_dispatch_transform_to_base32hex(dispatch_data_t data) +{ + return _dispatch_transform_to_base32_with_table(data, + base32hex_encode_table); +} + #pragma mark - #pragma mark base64 @@ -750,7 +807,7 @@ _dispatch_transform_from_base64(dispatch_data_t data) bool success = dispatch_data_apply(data, ^( DISPATCH_UNUSED dispatch_data_t region, DISPATCH_UNUSED size_t offset, const void *buffer, size_t size) { - size_t i, dest_size = (size * 3) / 4; + size_t i, dest_size = howmany(size, 4) * 3; uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t)); uint8_t *ptr = dest; @@ -780,7 +837,7 @@ _dispatch_transform_from_base64(dispatch_data_t data) } x <<= 6; - x += value; + x += (uint64_t)value; if ((count & 0x3) == 0) { *ptr++ = (x >> 16) & 0xff; @@ -789,7 +846,7 @@ _dispatch_transform_from_base64(dispatch_data_t data) } } - size_t final = (ptr - dest); + size_t final = (size_t)(ptr - dest); if (pad > 0) { // 2 bytes of pad means only had one char in final group final -= pad; @@ -819,13 +876,18 @@ _dispatch_transform_to_base64(dispatch_data_t data) { // RFC 4648 states that we should not linebreak // http://tools.ietf.org/html/rfc4648 - size_t total = dispatch_data_get_size(data); + size_t total = dispatch_data_get_size(data), dest_size; __block size_t count = 0; - size_t dest_size = ((total + 2) * 4) / 3; - dest_size -= dest_size % 4; + dest_size = howmany(total, 3); + // + // os_mul_overflow(dest_size, 4, &dest_size) + if (dest_size > SIZE_T_MAX / 4) { + return NULL; + } + dest_size *= 4; - uint8_t *dest = (uint8_t*)malloc(dest_size * sizeof(uint8_t)); + uint8_t *dest = (uint8_t*)malloc(dest_size); if (dest == NULL) { return NULL; } @@ -913,16 +975,16 @@ dispatch_data_create_with_transform(dispatch_data_t data, if (input->type == _DISPATCH_DATA_FORMAT_UTF_ANY) { input = _dispatch_transform_detect_utf(data); if (input == NULL) { - return NULL; + return DISPATCH_BAD_INPUT; } } if ((input->type & ~output->input_mask) != 0) { - return NULL; + return DISPATCH_BAD_INPUT; } if ((output->type & ~input->output_mask) != 0) { - return NULL; + return DISPATCH_BAD_INPUT; } if (dispatch_data_get_size(data) == 0) { @@ -938,7 +1000,7 @@ dispatch_data_create_with_transform(dispatch_data_t data, } if (!temp1) { - return NULL; + return DISPATCH_BAD_INPUT; } dispatch_data_t temp2; @@ -955,8 +1017,8 @@ dispatch_data_create_with_transform(dispatch_data_t data, const struct dispatch_data_format_type_s _dispatch_data_format_type_none = { .type = _DISPATCH_DATA_FORMAT_NONE, - .input_mask = ~0, - .output_mask = ~0, + .input_mask = ~0u, + .output_mask = ~0u, .decode = NULL, .encode = NULL, }; @@ -964,19 +1026,30 @@ const struct dispatch_data_format_type_s _dispatch_data_format_type_none = { const struct dispatch_data_format_type_s _dispatch_data_format_type_base32 = { .type = _DISPATCH_DATA_FORMAT_BASE32, .input_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 | - _DISPATCH_DATA_FORMAT_BASE64), + _DISPATCH_DATA_FORMAT_BASE32HEX | _DISPATCH_DATA_FORMAT_BASE64), .output_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 | - _DISPATCH_DATA_FORMAT_BASE64), + _DISPATCH_DATA_FORMAT_BASE32HEX | _DISPATCH_DATA_FORMAT_BASE64), .decode = _dispatch_transform_from_base32, .encode = _dispatch_transform_to_base32, }; +const struct dispatch_data_format_type_s _dispatch_data_format_type_base32hex = +{ + .type = _DISPATCH_DATA_FORMAT_BASE32HEX, + .input_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 | + _DISPATCH_DATA_FORMAT_BASE32HEX | _DISPATCH_DATA_FORMAT_BASE64), + .output_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 | + _DISPATCH_DATA_FORMAT_BASE32HEX | _DISPATCH_DATA_FORMAT_BASE64), + .decode = _dispatch_transform_from_base32hex, + .encode = _dispatch_transform_to_base32hex, +}; + const struct dispatch_data_format_type_s _dispatch_data_format_type_base64 = { .type = _DISPATCH_DATA_FORMAT_BASE64, .input_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 | - _DISPATCH_DATA_FORMAT_BASE64), + _DISPATCH_DATA_FORMAT_BASE32HEX | _DISPATCH_DATA_FORMAT_BASE64), .output_mask = (_DISPATCH_DATA_FORMAT_NONE | _DISPATCH_DATA_FORMAT_BASE32 | - _DISPATCH_DATA_FORMAT_BASE64), + _DISPATCH_DATA_FORMAT_BASE32HEX | _DISPATCH_DATA_FORMAT_BASE64), .decode = _dispatch_transform_from_base64, .encode = _dispatch_transform_to_base64, };