Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-number.cc
Line
Count
Source
1
/*
2
 * Copyright © 2019-2026  Ebrahim Byagowi
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 */
25
26
#ifndef HB_NUMBER_CC
27
#define HB_NUMBER_CC
28
#ifdef HB_NUMBER_CC /* Pacify -Wunused-macros. */
29
30
#include "hb.hh"
31
#include "hb-number.hh"
32
#include "hb-number-parser.hh"
33
34
bool
35
hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer)
36
0
{
37
0
  const char *pend = end;
38
0
  double value = hb_strtod (*pp, &pend);
39
0
  if (unlikely (*pp == pend)) return false;
40
0
  if (unlikely (whole_buffer && end != pend)) return false;
41
0
  *pv = value;
42
0
  *pp = pend;
43
0
  return true;
44
0
}
45
46
/* Returns the digit value of c in the given base (2..36), or -1 if c
47
 * isn't a digit in that base. */
48
static int
49
_hb_digit_value (char c, int base)
50
291k
{
51
291k
  int d;
52
291k
  if ('0' <= c && c <= '9')      d = c - '0';
53
184k
  else if ('a' <= c && c <= 'z') d = c - 'a' + 10;
54
177k
  else if ('A' <= c && c <= 'Z') d = c - 'A' + 10;
55
161k
  else return -1;
56
130k
  return d < base ? d : -1;
57
291k
}
58
59
/* Consumes digits in [p, pe) into *value (magnitude).  Sets *overflow
60
 * if the value would exceed UINT64_MAX.  Sets *any_digits if at least
61
 * one digit was consumed.  Returns the position past the last digit. */
62
static const char *
63
_hb_scan_digits (const char *p, const char *pe, int base,
64
                 uint64_t *value, bool *overflow, bool *any_digits)
65
554k
{
66
554k
  const uint64_t cutoff = UINT64_MAX / (unsigned) base;
67
554k
  const uint64_t cutlim = UINT64_MAX % (unsigned) base;
68
554k
  uint64_t v = 0;
69
554k
  bool ov = false, any = false;
70
71
661k
  for (; p < pe; p++)
72
291k
  {
73
291k
    int d = _hb_digit_value (*p, base);
74
291k
    if (d < 0) break;
75
106k
    any = true;
76
106k
    if (v > cutoff || (v == cutoff && (uint64_t) d > cutlim))
77
191
      ov = true;
78
106k
    else
79
106k
      v = v * (unsigned) base + (uint64_t) d;
80
106k
  }
81
82
554k
  *value = v;
83
554k
  *overflow = ov;
84
554k
  *any_digits = any;
85
554k
  return p;
86
554k
}
87
88
template<typename T, typename Postprocess>
89
static bool
90
_parse_number (const char **pp, const char *end, T *pv,
91
               bool whole_buffer, int base, Postprocess post)
92
554k
{
93
554k
  const char *pend = end;
94
554k
  const char *p = *pp;
95
554k
  bool neg = false, any = false, overflow = false;
96
97
577k
  while (p < pend && ISSPACE (*p)) p++;
98
554k
  if (p < pend && (*p == '+' || *p == '-')) { neg = (*p == '-'); p++; }
99
100
  /* Skip an optional "0x"/"0X" prefix for base 16, but only when a hex
101
   * digit follows — "0x" alone parses as the digit 0, matching strtoul. */
102
554k
  if (base == 16 && p + 2 < pend && p[0] == '0' &&
103
0
      (p[1] == 'x' || p[1] == 'X') && _hb_digit_value (p[2], 16) >= 0)
104
0
    p += 2;
105
106
554k
  uint64_t v = 0;
107
554k
  p = _hb_scan_digits (p, pend, base, &v, &overflow, &any);
108
554k
  if (unlikely (!any || overflow)) return false;
109
110
53.3k
  T out;
111
53.3k
  if (unlikely (!post (v, neg, &out))) return false;
112
53.0k
  if (unlikely (whole_buffer && p != pend)) return false;
113
114
53.0k
  *pv = out;
115
53.0k
  *pp = p;
116
53.0k
  return true;
117
53.0k
}
hb-number.cc:bool _parse_number<int, hb_parse_int(char const**, char const*, int*, bool)::$_0>(char const**, char const*, int*, bool, int, hb_parse_int(char const**, char const*, int*, bool)::$_0)
Line
Count
Source
92
554k
{
93
554k
  const char *pend = end;
94
554k
  const char *p = *pp;
95
554k
  bool neg = false, any = false, overflow = false;
96
97
577k
  while (p < pend && ISSPACE (*p)) p++;
98
554k
  if (p < pend && (*p == '+' || *p == '-')) { neg = (*p == '-'); p++; }
99
100
  /* Skip an optional "0x"/"0X" prefix for base 16, but only when a hex
101
   * digit follows — "0x" alone parses as the digit 0, matching strtoul. */
102
554k
  if (base == 16 && p + 2 < pend && p[0] == '0' &&
103
0
      (p[1] == 'x' || p[1] == 'X') && _hb_digit_value (p[2], 16) >= 0)
104
0
    p += 2;
105
106
554k
  uint64_t v = 0;
107
554k
  p = _hb_scan_digits (p, pend, base, &v, &overflow, &any);
108
554k
  if (unlikely (!any || overflow)) return false;
109
110
53.3k
  T out;
111
53.3k
  if (unlikely (!post (v, neg, &out))) return false;
112
53.0k
  if (unlikely (whole_buffer && p != pend)) return false;
113
114
53.0k
  *pv = out;
115
53.0k
  *pp = p;
116
53.0k
  return true;
117
53.0k
}
Unexecuted instantiation: hb-number.cc:bool _parse_number<unsigned int, hb_parse_uint(char const**, char const*, unsigned int*, bool, int)::$_0>(char const**, char const*, unsigned int*, bool, int, hb_parse_uint(char const**, char const*, unsigned int*, bool, int)::$_0)
118
119
bool
120
hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer)
121
554k
{
122
554k
  return _parse_number (pp, end, pv, whole_buffer, 10,
123
554k
                        [] (uint64_t v, bool neg, int *out) {
124
    /* INT_MAX = 2^31-1, INT_MIN magnitude = 2^31 */
125
53.3k
    uint64_t limit = neg ? (uint64_t) INT_MAX + 1 : (uint64_t) INT_MAX;
126
53.3k
    if (unlikely (v > limit)) return false;
127
53.0k
    *out = (int) (neg ? -(int64_t) v : (int64_t) v);
128
53.0k
    return true;
129
53.3k
  });
130
554k
}
131
132
bool
133
hb_parse_uint (const char **pp, const char *end, unsigned *pv,
134
               bool whole_buffer, int base)
135
0
{
136
0
  return _parse_number (pp, end, pv, whole_buffer, base,
137
0
                        [] (uint64_t v, bool neg, unsigned *out) {
138
0
    if (unlikely (v > UINT_MAX)) return false;
139
    /* Negate in unsigned so -1 wraps to UINT_MAX, matching strtoul
140
     * truncated to unsigned. */
141
0
    unsigned u = (unsigned) v;
142
0
    *out = neg ? (unsigned) (0u - u) : u;
143
0
    return true;
144
0
  });
145
0
}
146
147
#endif /* HB_NUMBER_CC pacify */
148
#endif /* HB_NUMBER_CC guard */