VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strtonum.cpp

Last change on this file was 99758, checked in by vboxsync, 12 months ago

IPRT: Make doxygen 1.9.6 happy. Mostly removing duplicate docs (iprt is documented in the header files). bugref:10442

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 26.2 KB
Line 
1/* $Id: strtonum.cpp 99758 2023-05-11 21:37:59Z vboxsync $ */
2/** @file
3 * IPRT - String To Number Conversion.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/string.h>
42#include "internal/iprt.h"
43
44#include <iprt/assert.h>
45#include <iprt/ctype.h> /* needed for RT_C_IS_DIGIT */
46#include <iprt/err.h>
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52extern const unsigned char g_auchDigits[256]; /* shared with strtofloat.cpp - add header? */
53
54/** 8-bit char -> digit.
55 * Non-digits have values 255 (most), 254 (zero), 253 (colon), 252 (space), 251 (dot).
56 *
57 * @note Also used by strtofloat.cpp
58 */
59const unsigned char g_auchDigits[256] =
60{
61 254,255,255,255,255,255,255,255,255,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
62 252,255,255,255,255,255,255,255,255,255,255,255,255,255,251,255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,253,255,255,255,255,255,
63 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255,
64 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255,
65 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
66 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
67 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
68 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
69};
70
71#define DIGITS_ZERO_TERM 254
72#define DIGITS_COLON 253
73#define DIGITS_SPACE 252
74#define DIGITS_DOT 251
75
76/** Approximated overflow shift checks. */
77static const char g_auchShift[36] =
78{
79 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 */
80 64, 64, 63, 63, 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 59, 59, 59, 59
81};
82
83/*
84#include <stdio.h>
85int main()
86{
87 int i;
88 printf("static const unsigned char g_auchDigits[256] =\n"
89 "{");
90 for (i = 0; i < 256; i++)
91 {
92 int ch = 255;
93 if (i >= '0' && i <= '9')
94 ch = i - '0';
95 else if (i >= 'a' && i <= 'z')
96 ch = i - 'a' + 10;
97 else if (i >= 'A' && i <= 'Z')
98 ch = i - 'A' + 10;
99 else if (i == 0)
100 ch = 254;
101 else if (i == ':')
102 ch = 253;
103 else if (i == ' ' || i == '\t')
104 ch = 252;
105 else if (i == '.')
106 ch = 251;
107 if (i == 0)
108 printf("\n %3d", ch);
109 else if ((i % 32) == 0)
110 printf(",\n %3d", ch);
111 else
112 printf(",%3d", ch);
113 }
114 printf("\n"
115 "};\n");
116 return 0;
117}
118*/
119
120
121RTDECL(int) RTStrToUInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint64_t *pu64)
122{
123 const char *psz = pszValue;
124 int iShift;
125 int rc;
126 uint64_t u64;
127 unsigned char uch;
128 bool fPositive;
129
130 /*
131 * Split the base and length limit (latter is chiefly for sscanf).
132 */
133 unsigned uBase = uBaseAndMaxLen & 0xff;
134 unsigned cchMax = uBaseAndMaxLen >> 8;
135 if (cchMax == 0)
136 cchMax = ~0U;
137 AssertStmt(uBase < RT_ELEMENTS(g_auchShift), uBase = 0);
138
139 /*
140 * Positive/Negative stuff.
141 */
142 fPositive = true;
143 while (cchMax > 0)
144 {
145 if (*psz == '+')
146 fPositive = true;
147 else if (*psz == '-')
148 fPositive = !fPositive;
149 else
150 break;
151 psz++;
152 cchMax--;
153 }
154
155 /*
156 * Check for hex prefix.
157 */
158 if (!uBase)
159 {
160 uBase = 10;
161 if (psz[0] == '0')
162 {
163 if ( psz[0] == '0'
164 && cchMax > 1
165 && (psz[1] == 'x' || psz[1] == 'X')
166 && g_auchDigits[(unsigned char)psz[2]] < 16)
167 {
168 uBase = 16;
169 psz += 2;
170 cchMax -= 2;
171 }
172 else if ( psz[0] == '0'
173 && g_auchDigits[(unsigned char)psz[1]] < 8)
174 uBase = 8; /* don't skip the zero, in case it's alone. */
175 }
176 }
177 else if ( uBase == 16
178 && psz[0] == '0'
179 && cchMax > 1
180 && (psz[1] == 'x' || psz[1] == 'X')
181 && g_auchDigits[(unsigned char)psz[2]] < 16)
182 {
183 cchMax -= 2;
184 psz += 2;
185 }
186
187 /*
188 * Interpret the value.
189 * Note: We only support ascii digits at this time... :-)
190 */
191 pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
192 iShift = g_auchShift[uBase];
193 rc = VINF_SUCCESS;
194 u64 = 0;
195 while (cchMax > 0 && (uch = (unsigned char)*psz) != 0)
196 {
197 unsigned char chDigit = g_auchDigits[uch];
198 uint64_t u64Prev;
199
200 if (chDigit >= uBase)
201 break;
202
203 u64Prev = u64;
204 u64 *= uBase;
205 u64 += chDigit;
206 if (u64Prev > u64 || (u64Prev >> iShift))
207 rc = VWRN_NUMBER_TOO_BIG;
208 psz++;
209 cchMax--;
210 }
211
212 if (!fPositive)
213 {
214 if (rc == VINF_SUCCESS)
215 rc = VWRN_NEGATIVE_UNSIGNED;
216 u64 = -(int64_t)u64;
217 }
218
219 if (pu64)
220 *pu64 = u64;
221
222 if (psz == pszValue)
223 rc = VERR_NO_DIGITS;
224
225 if (ppszNext)
226 *ppszNext = (char *)psz;
227
228 /*
229 * Warn about trailing chars/spaces.
230 */
231 if ( rc == VINF_SUCCESS
232 && *psz
233 && cchMax > 0)
234 {
235 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
236 psz++, cchMax--;
237 rc = cchMax > 0 && *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
238 }
239
240 return rc;
241}
242RT_EXPORT_SYMBOL(RTStrToUInt64Ex);
243
244
245RTDECL(int) RTStrToUInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, uint64_t *pu64)
246{
247 char *psz;
248 int rc = RTStrToUInt64Ex(pszValue, &psz, uBaseAndMaxLen, pu64);
249 if (RT_SUCCESS(rc) && *psz)
250 {
251 if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
252 rc = -rc;
253 else if (rc != VINF_SUCCESS)
254 {
255 unsigned cchMax = uBaseAndMaxLen >> 8;
256 if (!cchMax)
257 cchMax = ~0U;
258 else
259 cchMax -= (unsigned)(psz - pszValue);
260 if (cchMax > 0)
261 {
262 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
263 psz++, cchMax--;
264 rc = cchMax > 0 && *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
265 }
266 }
267 }
268 return rc;
269}
270RT_EXPORT_SYMBOL(RTStrToUInt64Full);
271
272
273RTDECL(uint64_t) RTStrToUInt64(const char *pszValue)
274{
275 uint64_t u64;
276 int rc = RTStrToUInt64Ex(pszValue, NULL, 0, &u64);
277 if (RT_SUCCESS(rc))
278 return u64;
279 return 0;
280}
281RT_EXPORT_SYMBOL(RTStrToUInt64);
282
283
284RTDECL(int) RTStrToUInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint32_t *pu32)
285{
286 uint64_t u64;
287 int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &u64);
288 if (RT_SUCCESS(rc))
289 {
290 if (u64 & ~0xffffffffULL)
291 rc = VWRN_NUMBER_TOO_BIG;
292 }
293 if (pu32)
294 *pu32 = (uint32_t)u64;
295 return rc;
296}
297RT_EXPORT_SYMBOL(RTStrToUInt32Ex);
298
299
300RTDECL(int) RTStrToUInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, uint32_t *pu32)
301{
302 uint64_t u64;
303 int rc = RTStrToUInt64Full(pszValue, uBaseAndMaxLen, &u64);
304 if (RT_SUCCESS(rc))
305 {
306 if (u64 & ~0xffffffffULL)
307 rc = VWRN_NUMBER_TOO_BIG;
308 }
309 if (pu32)
310 *pu32 = (uint32_t)u64;
311 return rc;
312}
313RT_EXPORT_SYMBOL(RTStrToUInt32Full);
314
315
316RTDECL(uint32_t) RTStrToUInt32(const char *pszValue)
317{
318 uint32_t u32;
319 int rc = RTStrToUInt32Ex(pszValue, NULL, 0, &u32);
320 if (RT_SUCCESS(rc))
321 return u32;
322 return 0;
323}
324RT_EXPORT_SYMBOL(RTStrToUInt32);
325
326
327RTDECL(int) RTStrToUInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint16_t *pu16)
328{
329 uint64_t u64;
330 int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &u64);
331 if (RT_SUCCESS(rc))
332 {
333 if (u64 & ~0xffffULL)
334 rc = VWRN_NUMBER_TOO_BIG;
335 }
336 if (pu16)
337 *pu16 = (uint16_t)u64;
338 return rc;
339}
340RT_EXPORT_SYMBOL(RTStrToUInt16Ex);
341
342
343RTDECL(int) RTStrToUInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, uint16_t *pu16)
344{
345 uint64_t u64;
346 int rc = RTStrToUInt64Full(pszValue, uBaseAndMaxLen, &u64);
347 if (RT_SUCCESS(rc))
348 {
349 if (u64 & ~0xffffULL)
350 rc = VWRN_NUMBER_TOO_BIG;
351 }
352 if (pu16)
353 *pu16 = (uint16_t)u64;
354 return rc;
355}
356RT_EXPORT_SYMBOL(RTStrToUInt16Full);
357
358
359RTDECL(uint16_t) RTStrToUInt16(const char *pszValue)
360{
361 uint16_t u16;
362 int rc = RTStrToUInt16Ex(pszValue, NULL, 0, &u16);
363 if (RT_SUCCESS(rc))
364 return u16;
365 return 0;
366}
367RT_EXPORT_SYMBOL(RTStrToUInt16);
368
369
370RTDECL(int) RTStrToUInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint8_t *pu8)
371{
372 uint64_t u64;
373 int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &u64);
374 if (RT_SUCCESS(rc))
375 {
376 if (u64 & ~0xffULL)
377 rc = VWRN_NUMBER_TOO_BIG;
378 }
379 if (pu8)
380 *pu8 = (uint8_t)u64;
381 return rc;
382}
383RT_EXPORT_SYMBOL(RTStrToUInt8Ex);
384
385
386RTDECL(int) RTStrToUInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, uint8_t *pu8)
387{
388 uint64_t u64;
389 int rc = RTStrToUInt64Full(pszValue, uBaseAndMaxLen, &u64);
390 if (RT_SUCCESS(rc))
391 {
392 if (u64 & ~0xffULL)
393 rc = VWRN_NUMBER_TOO_BIG;
394 }
395 if (pu8)
396 *pu8 = (uint8_t)u64;
397 return rc;
398}
399RT_EXPORT_SYMBOL(RTStrToUInt8Full);
400
401
402RTDECL(uint8_t) RTStrToUInt8(const char *pszValue)
403{
404 uint8_t u8;
405 int rc = RTStrToUInt8Ex(pszValue, NULL, 0, &u8);
406 if (RT_SUCCESS(rc))
407 return u8;
408 return 0;
409}
410RT_EXPORT_SYMBOL(RTStrToUInt8);
411
412
413RTDECL(int) RTStrToInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int64_t *pi64)
414{
415 const char *psz = pszValue;
416 int iShift;
417 int rc;
418 uint64_t u64;
419 unsigned char uch;
420 bool fPositive;
421
422 /*
423 * Split the base and length limit (latter is chiefly for sscanf).
424 */
425 unsigned uBase = uBaseAndMaxLen & 0xff;
426 unsigned cchMax = uBaseAndMaxLen >> 8;
427 if (cchMax == 0)
428 cchMax = ~0U;
429 AssertStmt(uBase < RT_ELEMENTS(g_auchShift), uBase = 0);
430
431 /*
432 * Positive/Negative stuff.
433 */
434 fPositive = true;
435 while (cchMax > 0)
436 {
437 if (*psz == '+')
438 fPositive = true;
439 else if (*psz == '-')
440 fPositive = !fPositive;
441 else
442 break;
443 psz++;
444 cchMax--;
445 }
446
447 /*
448 * Check for hex prefix.
449 */
450 if (!uBase)
451 {
452 uBase = 10;
453 if (psz[0] == '0')
454 {
455 if ( psz[0] == '0'
456 && cchMax > 1
457 && (psz[1] == 'x' || psz[1] == 'X')
458 && g_auchDigits[(unsigned char)psz[2]] < 16)
459 {
460 uBase = 16;
461 psz += 2;
462 cchMax -= 2;
463 }
464 else if ( psz[0] == '0'
465 && g_auchDigits[(unsigned char)psz[1]] < 8)
466 uBase = 8; /* don't skip the zero, in case it's alone. */
467 }
468 }
469 else if ( uBase == 16
470 && psz[0] == '0'
471 && cchMax > 1
472 && (psz[1] == 'x' || psz[1] == 'X')
473 && g_auchDigits[(unsigned char)psz[2]] < 16)
474 {
475 cchMax -= 2;
476 psz += 2;
477 }
478
479 /*
480 * Interpret the value.
481 * Note: We only support ascii digits at this time... :-)
482 */
483 pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
484 iShift = g_auchShift[uBase];
485 rc = VINF_SUCCESS;
486 u64 = 0;
487 while (cchMax > 0 && (uch = (unsigned char)*psz) != 0)
488 {
489 unsigned char chDigit = g_auchDigits[uch];
490 uint64_t u64Prev;
491
492 if (chDigit >= uBase)
493 break;
494
495 u64Prev = u64;
496 u64 *= uBase;
497 u64 += chDigit;
498 if (u64Prev > u64 || (u64Prev >> iShift))
499 rc = VWRN_NUMBER_TOO_BIG;
500 psz++;
501 cchMax--;
502 }
503
504 /* Mixing pi64 assigning and overflow checks is to pacify a tstRTCRest-1
505 asan overflow warning. */
506 if (!(u64 & RT_BIT_64(63)))
507 {
508 if (psz == pszValue)
509 rc = VERR_NO_DIGITS;
510 if (pi64)
511 *pi64 = fPositive ? u64 : -(int64_t)u64;
512 }
513 else if (!fPositive && u64 == RT_BIT_64(63))
514 {
515 if (pi64)
516 *pi64 = INT64_MIN;
517 }
518 else
519 {
520 rc = VWRN_NUMBER_TOO_BIG;
521 if (pi64)
522 *pi64 = fPositive ? u64 : -(int64_t)u64;
523 }
524
525 if (ppszNext)
526 *ppszNext = (char *)psz;
527
528 /*
529 * Warn about trailing chars/spaces.
530 */
531 if ( rc == VINF_SUCCESS
532 && cchMax > 0
533 && *psz)
534 {
535 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
536 psz++, cchMax--;
537 rc = cchMax > 0 && *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
538 }
539
540 return rc;
541}
542RT_EXPORT_SYMBOL(RTStrToInt64Ex);
543
544
545RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, int64_t *pi64)
546{
547 char *psz;
548 int rc = RTStrToInt64Ex(pszValue, &psz, uBaseAndMaxLen, pi64);
549 if (RT_SUCCESS(rc) && *psz)
550 {
551 if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
552 rc = -rc;
553 else if (rc != VINF_SUCCESS)
554 {
555 unsigned cchMax = uBaseAndMaxLen >> 8;
556 if (!cchMax)
557 cchMax = ~0U;
558 else
559 cchMax -= (unsigned)(psz - pszValue);
560 if (cchMax > 0)
561 {
562 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
563 psz++, cchMax--;
564 rc = cchMax > 0 && *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
565 }
566 }
567 }
568 return rc;
569}
570RT_EXPORT_SYMBOL(RTStrToInt64Full);
571
572
573RTDECL(int64_t) RTStrToInt64(const char *pszValue)
574{
575 int64_t i64;
576 int rc = RTStrToInt64Ex(pszValue, NULL, 0, &i64);
577 if (RT_SUCCESS(rc))
578 return i64;
579 return 0;
580}
581RT_EXPORT_SYMBOL(RTStrToInt64);
582
583
584RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int32_t *pi32)
585{
586 int64_t i64;
587 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
588 if (RT_SUCCESS(rc))
589 {
590 int32_t i32 = (int32_t)i64;
591 if (i64 != (int64_t)i32)
592 rc = VWRN_NUMBER_TOO_BIG;
593 }
594 if (pi32)
595 *pi32 = (int32_t)i64;
596 return rc;
597}
598RT_EXPORT_SYMBOL(RTStrToInt32Ex);
599
600
601RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, int32_t *pi32)
602{
603 int64_t i64;
604 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
605 if (RT_SUCCESS(rc))
606 {
607 int32_t i32 = (int32_t)i64;
608 if (i64 != (int64_t)i32)
609 rc = VWRN_NUMBER_TOO_BIG;
610 }
611 if (pi32)
612 *pi32 = (int32_t)i64;
613 return rc;
614}
615RT_EXPORT_SYMBOL(RTStrToInt32Full);
616
617
618RTDECL(int32_t) RTStrToInt32(const char *pszValue)
619{
620 int32_t i32;
621 int rc = RTStrToInt32Ex(pszValue, NULL, 0, &i32);
622 if (RT_SUCCESS(rc))
623 return i32;
624 return 0;
625}
626RT_EXPORT_SYMBOL(RTStrToInt32);
627
628
629RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int16_t *pi16)
630{
631 int64_t i64;
632 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
633 if (RT_SUCCESS(rc))
634 {
635 int16_t i16 = (int16_t)i64;
636 if (i64 != (int64_t)i16)
637 rc = VWRN_NUMBER_TOO_BIG;
638 }
639 if (pi16)
640 *pi16 = (int16_t)i64;
641 return rc;
642}
643RT_EXPORT_SYMBOL(RTStrToInt16Ex);
644
645
646RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, int16_t *pi16)
647{
648 int64_t i64;
649 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
650 if (RT_SUCCESS(rc))
651 {
652 int16_t i16 = (int16_t)i64;
653 if (i64 != (int64_t)i16)
654 rc = VWRN_NUMBER_TOO_BIG;
655 }
656 if (pi16)
657 *pi16 = (int16_t)i64;
658 return rc;
659}
660RT_EXPORT_SYMBOL(RTStrToInt16Full);
661
662
663RTDECL(int16_t) RTStrToInt16(const char *pszValue)
664{
665 int16_t i16;
666 int rc = RTStrToInt16Ex(pszValue, NULL, 0, &i16);
667 if (RT_SUCCESS(rc))
668 return i16;
669 return 0;
670}
671RT_EXPORT_SYMBOL(RTStrToInt16);
672
673
674RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int8_t *pi8)
675{
676 int64_t i64;
677 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
678 if (RT_SUCCESS(rc))
679 {
680 int8_t i8 = (int8_t)i64;
681 if (i64 != (int64_t)i8)
682 rc = VWRN_NUMBER_TOO_BIG;
683 }
684 if (pi8)
685 *pi8 = (int8_t)i64;
686 return rc;
687}
688RT_EXPORT_SYMBOL(RTStrToInt8Ex);
689
690
691RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, int8_t *pi8)
692{
693 int64_t i64;
694 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
695 if (RT_SUCCESS(rc))
696 {
697 int8_t i8 = (int8_t)i64;
698 if (i64 != (int64_t)i8)
699 rc = VWRN_NUMBER_TOO_BIG;
700 }
701 if (pi8)
702 *pi8 = (int8_t)i64;
703 return rc;
704}
705RT_EXPORT_SYMBOL(RTStrToInt8Full);
706
707
708RTDECL(int8_t) RTStrToInt8(const char *pszValue)
709{
710 int8_t i8;
711 int rc = RTStrToInt8Ex(pszValue, NULL, 0, &i8);
712 if (RT_SUCCESS(rc))
713 return i8;
714 return 0;
715}
716RT_EXPORT_SYMBOL(RTStrToInt8);
717
718
719RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags,
720 const char **ppszNext, size_t *pcbReturned)
721{
722 size_t cbDst = cb;
723 uint8_t *pbDst = (uint8_t *)pv;
724 const unsigned char *pszSrc = (const unsigned char *)pszHex;
725 unsigned char uchDigit;
726
727 if (pcbReturned)
728 *pcbReturned = 0;
729 if (ppszNext)
730 *ppszNext = NULL;
731 AssertPtrReturn(pszHex, VERR_INVALID_POINTER);
732 AssertReturn(!(fFlags & ~RTSTRCONVERTHEXBYTES_F_SEP_COLON), VERR_INVALID_FLAGS);
733
734 if (fFlags & RTSTRCONVERTHEXBYTES_F_SEP_COLON)
735 {
736 /*
737 * Optional colon separators.
738 */
739 bool fPrevColon = true; /* leading colon is taken to mean leading zero byte */
740 for (;;)
741 {
742 /* Pick the next two digit from the string. */
743 uchDigit = g_auchDigits[*pszSrc++];
744 if (uchDigit >= 16)
745 {
746 if (uchDigit == 253 /* colon */)
747 {
748 Assert(pszSrc[-1] == ':');
749 if (!fPrevColon)
750 fPrevColon = true;
751 /* Add zero byte if there is room. */
752 else if (cbDst > 0)
753 {
754 cbDst--;
755 *pbDst++ = 0;
756 }
757 else
758 {
759 if (pcbReturned)
760 *pcbReturned = pbDst - (uint8_t *)pv;
761 if (ppszNext)
762 *ppszNext = (const char *)pszSrc - 1;
763 return VERR_BUFFER_OVERFLOW;
764 }
765 continue;
766 }
767 else
768 break;
769 }
770 else
771 {
772 /* Got one digit, check what comes next: */
773 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
774 if (uchDigit2 < 16)
775 {
776 if (cbDst > 0)
777 {
778 *pbDst++ = (uchDigit << 4) | uchDigit2;
779 cbDst--;
780 fPrevColon = false;
781 }
782 else
783 {
784 if (pcbReturned)
785 *pcbReturned = pbDst - (uint8_t *)pv;
786 if (ppszNext)
787 *ppszNext = (const char *)pszSrc - 1;
788 return VERR_BUFFER_OVERFLOW;
789 }
790 }
791 /* Lone digits are only allowed if following a colon or at the very start, because
792 if there is more than one byte it ambigious whether it is the lead or tail byte
793 that only has one digit in it.
794 Note! This also ensures better compatibility with the no-separator variant
795 (except for single digit strings, which are accepted here but not below). */
796 else if (fPrevColon)
797 {
798 if (cbDst > 0)
799 {
800 *pbDst++ = uchDigit;
801 cbDst--;
802 }
803 else
804 {
805 if (pcbReturned)
806 *pcbReturned = pbDst - (uint8_t *)pv;
807 if (ppszNext)
808 *ppszNext = (const char *)pszSrc - 1;
809 return VERR_BUFFER_OVERFLOW;
810 }
811 if (uchDigit2 == 253 /* colon */)
812 {
813 Assert(pszSrc[-1] == ':');
814 fPrevColon = true;
815 }
816 else
817 {
818 fPrevColon = false;
819 uchDigit = uchDigit2;
820 break;
821 }
822 }
823 else
824 {
825 if (pcbReturned)
826 *pcbReturned = pbDst - (uint8_t *)pv;
827 if (ppszNext)
828 *ppszNext = (const char *)pszSrc - 2;
829 return VERR_UNEVEN_INPUT;
830 }
831 }
832 }
833
834 /* Trailing colon means trailing zero byte: */
835 if (fPrevColon)
836 {
837 if (cbDst > 0)
838 {
839 *pbDst++ = 0;
840 cbDst--;
841 }
842 else
843 {
844 if (pcbReturned)
845 *pcbReturned = pbDst - (uint8_t *)pv;
846 if (ppszNext)
847 *ppszNext = (const char *)pszSrc - 1;
848 return VERR_BUFFER_OVERFLOW;
849 }
850 }
851 }
852 else
853 {
854 /*
855 * No separators.
856 */
857 for (;;)
858 {
859 /* Pick the next two digit from the string. */
860 uchDigit = g_auchDigits[*pszSrc++];
861 if (uchDigit < 16)
862 {
863 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
864 if (uchDigit2 < 16)
865 {
866 /* Add the byte to the output buffer. */
867 if (cbDst)
868 {
869 cbDst--;
870 *pbDst++ = (uchDigit << 4) | uchDigit2;
871 }
872 else
873 {
874 if (pcbReturned)
875 *pcbReturned = pbDst - (uint8_t *)pv;
876 if (ppszNext)
877 *ppszNext = (const char *)pszSrc - 2;
878 return VERR_BUFFER_OVERFLOW;
879 }
880 }
881 else
882 {
883 if (pcbReturned)
884 *pcbReturned = pbDst - (uint8_t *)pv;
885 if (ppszNext)
886 *ppszNext = (const char *)pszSrc - 2;
887 return VERR_UNEVEN_INPUT;
888 }
889 }
890 else
891 break;
892 }
893 }
894
895 /*
896 * End of hex bytes, look what comes next and figure out what to return.
897 */
898 if (pcbReturned)
899 *pcbReturned = pbDst - (uint8_t *)pv;
900 if (ppszNext)
901 *ppszNext = (const char *)pszSrc - 1;
902
903 if (uchDigit == 254)
904 {
905 Assert(pszSrc[-1] == '\0');
906 if (cbDst == 0)
907 return VINF_SUCCESS;
908 return pcbReturned ? VINF_BUFFER_UNDERFLOW : VERR_BUFFER_UNDERFLOW;
909 }
910 Assert(pszSrc[-1] != '\0');
911
912 if (cbDst != 0 && !pcbReturned)
913 return VERR_BUFFER_UNDERFLOW;
914
915 while (uchDigit == 252)
916 {
917 Assert(pszSrc[-1] == ' ' || pszSrc[-1] == '\t');
918 uchDigit = g_auchDigits[*pszSrc++];
919 }
920
921 Assert(pszSrc[-1] == '\0' ? uchDigit == 254 : uchDigit != 254);
922 return uchDigit == 254 ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
923
924}
925RT_EXPORT_SYMBOL(RTStrConvertHexBytesEx);
926
927
928RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags)
929{
930 return RTStrConvertHexBytesEx(pszHex, pv, cb, fFlags, NULL /*ppszNext*/, NULL /*pcbReturned*/);
931
932}
933RT_EXPORT_SYMBOL(RTStrConvertHexBytes);
934
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use