diff options
author | Mattias Andrée <maandree@kth.se> | 2021-08-13 18:06:45 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2021-08-13 18:06:45 +0200 |
commit | fcffe4810f59de6a4f39596a37242022b68e7bc5 (patch) | |
tree | d91ef754fe3b24ecfea8270ef4ef0c070de8c359 /libparsesfnt_parse___.c | |
download | libparsesfnt-fcffe4810f59de6a4f39596a37242022b68e7bc5.tar.gz libparsesfnt-fcffe4810f59de6a4f39596a37242022b68e7bc5.tar.bz2 libparsesfnt-fcffe4810f59de6a4f39596a37242022b68e7bc5.tar.xz |
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r-- | libparsesfnt_parse___.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/libparsesfnt_parse___.c b/libparsesfnt_parse___.c new file mode 100644 index 0000000..17ee018 --- /dev/null +++ b/libparsesfnt_parse___.c @@ -0,0 +1,188 @@ +/* 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; + 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 += 1; + else if (*s == '1' || *s == '.') + need += 1; + else if (*s == '2') + need += 2; + else if (*s == '4') + need += 4; + else if (*s == '8') + need += 8; + } + + 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 > 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++) { + 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 { + abort(); + } + } + } + + return 0; + +efbig: + errno = EFBIG; + return -1; + +ebfont: + errno = EBFONT; + return -1; +} |