/*
- * Copyright (c) 2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
#include "internal.h"
+#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
+#elif __linux__
+#include <endian.h>
+#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
#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 {
_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,
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[] = {
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);
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;
}
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;
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;
});
if (!success) {
+ (void)_dispatch_transform_buffer_new(&buffer, 0, 0);
dispatch_release(buffer.data);
return NULL;
}
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;
}
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
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 {
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;
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;
});
if (!success) {
+ (void)_dispatch_transform_buffer_new(&buffer, 0, 0);
dispatch_release(buffer.data);
return NULL;
}
#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;
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;
}
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;
}
}
- size_t final = (ptr - dest);
+ size_t final = (size_t)(ptr - dest);
switch (pad) {
case 1:
final -= 1;
}
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);
+ // <rdar://problem/25676583>
+ // 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;
}
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;
}
}
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) {
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
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;
}
x <<= 6;
- x += value;
+ x += (uint64_t)value;
if ((count & 0x3) == 0) {
*ptr++ = (x >> 16) & 0xff;
}
}
- 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;
{
// 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);
+ // <rdar://problem/25676583>
+ // 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;
}
{
if (input->type == _DISPATCH_DATA_FORMAT_UTF_ANY) {
input = _dispatch_transform_detect_utf(data);
+ if (input == 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) {
}
if (!temp1) {
- return NULL;
+ return DISPATCH_BAD_INPUT;
}
dispatch_data_t temp2;
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,
};
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,
};