blob: 322ed24766e250d87e3072f506810e4ea8e92a54 (
plain) (
tree)
|
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
static uint16_t
parse16(const char *data)
{
uint16_t b1 = (uint16_t)((const uint8_t *)data)[0];
uint16_t b2 = (uint16_t)((const uint8_t *)data)[1];
b1 = (uint16_t)(b1 << 8);
b2 = (uint16_t)(b2 << 0);
return (uint16_t)(b1 | b2);
}
static uint32_t
parse32(const char *data)
{
uint32_t b1 = (uint32_t)((const uint8_t *)data)[0];
uint32_t b2 = (uint32_t)((const uint8_t *)data)[1];
uint32_t b3 = (uint32_t)((const uint8_t *)data)[2];
uint32_t b4 = (uint32_t)((const uint8_t *)data)[3];
b1 = (uint32_t)(b1 << 24);
b2 = (uint32_t)(b2 << 16);
b3 = (uint32_t)(b3 << 8);
b4 = (uint32_t)(b4 << 0);
return (uint32_t)(b1 | b2 | b3 | b4);
}
static uint64_t
parse64(const char *data)
{
uint64_t b1 = (uint64_t)((const uint8_t *)data)[0];
uint64_t b2 = (uint64_t)((const uint8_t *)data)[1];
uint64_t b3 = (uint64_t)((const uint8_t *)data)[2];
uint64_t b4 = (uint64_t)((const uint8_t *)data)[3];
uint64_t b5 = (uint64_t)((const uint8_t *)data)[4];
uint64_t b6 = (uint64_t)((const uint8_t *)data)[5];
uint64_t b7 = (uint64_t)((const uint8_t *)data)[6];
uint64_t b8 = (uint64_t)((const uint8_t *)data)[7];
b1 = (uint32_t)(b1 << 56);
b2 = (uint32_t)(b2 << 48);
b3 = (uint32_t)(b3 << 40);
b4 = (uint32_t)(b4 << 32);
b5 = (uint32_t)(b5 << 24);
b6 = (uint32_t)(b6 << 16);
b7 = (uint32_t)(b7 << 8);
b8 = (uint32_t)(b8 << 0);
return (uint32_t)(b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8);
}
static void
sign8(union {uint8_t u; int8_t s;} *info)
{
info->s = ((info->u >> 7) ? -(int8_t)(~info->u + 1) : (int8_t)info->u);
}
static void
sign16(union {uint16_t u; int16_t s;} *info)
{
info->s = ((info->u >> 15) ? -(int16_t)(~info->u + 1) : (int16_t)info->u);
}
static void
sign32(union {uint32_t u; int32_t s;} *info)
{
info->s = ((info->u >> 31) ? -(int32_t)(~info->u + 1) : (int32_t)info->u);
}
static void
sign64(union {uint64_t u; int64_t s;} *info)
{
info->s = ((info->u >> 63) ? -(int64_t)(~info->u + 1) : (int64_t)info->u);
}
int
libparsesfnt_parse___(const char *data, size_t size, void *infop, size_t esize,
const char *fmt, size_t offset, size_t offset2, size_t offset3,
size_t first, size_t count, const struct libparsesfnt_tabdir_entry *tag)
{
const char *s;
size_t tag_offset = 0;
size_t need = 0;
size_t padding = 0;
size_t multiplier = 1;
int is_signed = 0;
char *info = infop;
if (offset > size || offset2 > size - offset)
goto ebfont;
offset += offset2;
if (offset3 > size - offset)
goto ebfont;
offset += offset3;
if (tag)
tag_offset = offset - tag->offset;
for (s = fmt; *s; s++) {
if (*s == 'p') {
padding += multiplier * 1;
} else if (*s == '1' || *s == '.') {
need += multiplier * 1;
} else if (*s == '2') {
need += multiplier * 2;
} else if (*s == '4') {
need += multiplier * 4;
} else if (*s == '8') {
need += multiplier * 8;
} else if (*s == '{') {
multiplier = strtoul(s, (void *)&s, 10);
continue;
}
multiplier = 1;
}
if (count > SIZE_MAX - first ||
first > (SIZE_MAX - offset) / need)
goto efbig;
offset += first * need;
if (offset > size || need > size - offset)
goto ebfont;
if (count > (SIZE_MAX - offset) / need)
goto efbig;
if (offset + count * need > size ||
(tag && (tag->length < count * need ||
tag->length > size ||
tag->offset > size - tag->length ||
tag_offset > tag->length ||
first + count > (tag->length - tag_offset) / need)))
goto ebfont;
data = &data[offset];
padding = esize - need - padding;
for (; count--; info = &info[padding]) {
for (s = fmt; *s; s++) {
while (multiplier--) {
if (*s == 'p') {
*info++ = 0;
} else if (*s == '.') {
*info++ = *data++;
} else if (*s == '1') {
*(uint8_t *)info = *(const uint8_t *)data;
if (is_signed)
sign8((void *)info);
data = &data[1];
info = &info[1];
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align" /* in practice alignment will be correct */
#endif
} else if (*s == '2') {
*(uint16_t *)info = parse16(data);
if (is_signed)
sign16((void *)info);
data = &data[2];
info = &info[2];
} else if (*s == '4') {
*(uint32_t *)info = parse32(data);
if (is_signed)
sign32((void *)info);
data = &data[4];
info = &info[4];
} else if (*s == '8') {
*(uint64_t *)info = parse64(data);
if (is_signed)
sign64((void *)info);
data = &data[8];
info = &info[8];
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
} else if (*s == '-') {
is_signed = 1;
} else if (*s == '+') {
is_signed = 0;
} else if (*s == '{') {
multiplier = strtoul(s, (void *)&s, 10);
goto continue_s;
} else {
abort();
}
}
multiplier = 1;
continue_s:;
}
}
return 0;
efbig:
errno = EFBIG;
return -1;
ebfont:
errno = EBFONT;
return -1;
}
|