1 /* 2 * number.h -- integer parsing routines 3 * 4 * Copyright (c) 2022-2023, NLnet Labs. All rights reserved. 5 * 6 * SPDX-License-Identifier: BSD-3-Clause 7 * 8 */ 9 #ifndef NUMBER_H 10 #define NUMBER_H 11 12 nonnull((1,3)) 13 static really_inline int32_t scan_int8( 14 const char *data, size_t length, uint8_t *number) 15 { 16 uint32_t sum = (uint8_t)data[0] - '0'; 17 18 if (sum > 9 || !length || length > 3) 19 return 0; 20 21 for (size_t count=1; count < length; count++) { 22 const uint8_t digit = (uint8_t)data[count] - '0'; 23 sum = sum * 10 + digit; 24 if (digit > 9) 25 return 0; 26 } 27 28 *number = (uint8_t)sum; 29 return sum <= 255u; 30 } 31 32 nonnull((1,3)) 33 static really_inline int32_t scan_int16( 34 const char *data, size_t length, uint16_t *number) 35 { 36 uint32_t sum = (uint8_t)data[0] - '0'; 37 38 if (sum > 9 || !length || length > 5) 39 return 0; 40 41 for (size_t count=1; count < length; count++) { 42 const uint8_t digit = (uint8_t)data[count] - '0'; 43 sum = sum * 10 + digit; 44 if (digit > 9) 45 return 0; 46 } 47 48 *number = (uint16_t)sum; 49 return sum <= 65535u; 50 } 51 52 nonnull((1,3)) 53 static really_inline int32_t scan_int32( 54 const char *data, size_t length, uint32_t *number) 55 { 56 uint64_t sum = (uint8_t)data[0] - '0'; 57 58 if (sum > 9 || !length || length > 10) 59 return 0; 60 61 for (size_t count=1; count < length; count++) { 62 const uint8_t digit = (uint8_t)data[count] - '0'; 63 sum = sum * 10 + digit; 64 if (digit > 9) 65 return 0; 66 } 67 68 *number = (uint32_t)sum; 69 return sum <= 4294967295u; 70 } 71 72 nonnull((1,3)) 73 static really_inline int32_t scan_int64( 74 const char *data, size_t length, uint64_t *number) 75 { 76 uint64_t sum = (uint8_t)data[0] - '0'; 77 78 if (sum > 9 || !length || length > 20) 79 return 0; 80 81 for (size_t count=1; count < length; count++) { 82 const uint8_t digit = (uint8_t)data[count] - '0'; 83 sum = sum * 10 + digit; 84 if (digit > 9) 85 return 0; 86 } 87 88 *number = sum; 89 return 1; /* TODO: detect overflow */ 90 } 91 92 nonnull_all 93 static really_inline int32_t parse_int8( 94 parser_t *parser, 95 const type_info_t *type, 96 const rdata_info_t *field, 97 rdata_t *rdata, 98 const token_t *token) 99 { 100 uint8_t number; 101 if (!scan_int8(token->data, token->length, &number)) 102 SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); 103 *rdata->octets++ = number; 104 return 0; 105 } 106 107 nonnull_all 108 static really_inline int32_t parse_int16( 109 parser_t *parser, 110 const type_info_t *type, 111 const rdata_info_t *field, 112 rdata_t *rdata, 113 const token_t *token) 114 { 115 uint16_t number; 116 if (!scan_int16(token->data, token->length, &number)) 117 SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); 118 number = htobe16(number); 119 memcpy(rdata->octets, &number, 2); 120 rdata->octets += 2; 121 return 0; 122 } 123 124 nonnull_all 125 static really_inline int32_t parse_int32( 126 parser_t *parser, 127 const type_info_t *type, 128 const rdata_info_t *field, 129 rdata_t *rdata, 130 const token_t *token) 131 { 132 uint32_t number; 133 if (!scan_int32(token->data, token->length, &number)) 134 SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); 135 number = htobe32(number); 136 memcpy(rdata->octets, &number, 4); 137 rdata->octets += 4; 138 return 0; 139 } 140 141 nonnull_all 142 static really_inline int32_t parse_int64( 143 parser_t *parser, 144 const type_info_t *type, 145 const rdata_info_t *field, 146 rdata_t *rdata, 147 const token_t *token) 148 { 149 uint64_t number; 150 if (!scan_int64(token->data, token->length, &number)) 151 SYNTAX_ERROR(parser, "Invalid %s in %s", NAME(field), NAME(type)); 152 number = htobe64(number); 153 memcpy(rdata->octets, &number, 8); 154 rdata->octets += 8; 155 return 0; 156 } 157 158 #endif // NUMBER_H 159