Home | History | Annotate | Line # | Download | only in generic
      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