VirtualBox

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

Last change on this file was 107694, checked in by vboxsync, 6 days ago

Runtime/common/string/strtonum.cpp: Remove redundant conditions in if, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 26.1 KB
Line 
1/* $Id: strtonum.cpp 107694 2025-01-10 16:52:48Z vboxsync $ */
2/** @file
3 * IPRT - String To Number Conversion.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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 ( cchMax > 1
164 && (psz[1] == 'x' || psz[1] == 'X')
165 && g_auchDigits[(unsigned char)psz[2]] < 16)
166 {
167 uBase = 16;
168 psz += 2;
169 cchMax -= 2;
170 }
171 else if (g_auchDigits[(unsigned char)psz[1]] < 8)
172 uBase = 8; /* don't skip the zero, in case it's alone. */
173 }
174 }
175 else if ( uBase == 16
176 && psz[0] == '0'
177 && cchMax > 1
178 && (psz[1] == 'x' || psz[1] == 'X')
179 && g_auchDigits[(unsigned char)psz[2]] < 16)
180 {
181 cchMax -= 2;
182 psz += 2;
183 }
184
185 /*
186 * Interpret the value.
187 * Note: We only support ascii digits at this time... :-)
188 */
189 pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
190 iShift = g_auchShift[uBase];
191 rc = VINF_SUCCESS;
192 u64 = 0;
193 while (cchMax > 0 && (uch = (unsigned char)*psz) != 0)
194 {
195 unsigned char chDigit = g_auchDigits[uch];
196 uint64_t u64Prev;
197
198 if (chDigit >= uBase)
199 break;
200
201 u64Prev = u64;
202 u64 *= uBase;
203 u64 += chDigit;
204 if (u64Prev > u64 || (u64Prev >> iShift))
205 rc = VWRN_NUMBER_TOO_BIG;
206 psz++;
207 cchMax--;
208 }
209
210 if (!fPositive)
211 {
212 if (rc == VINF_SUCCESS)
213 rc = VWRN_NEGATIVE_UNSIGNED;
214 u64 = -(int64_t)u64;
215 }
216
217 if (pu64)
218 *pu64 = u64;
219
220 if (psz == pszValue)
221 rc = VERR_NO_DIGITS;
222
223 if (ppszNext)
224 *ppszNext = (char *)psz;
225
226 /*
227 * Warn about trailing chars/spaces.
228 */
229 if ( rc == VINF_SUCCESS
230 && *psz
231 && cchMax > 0)
232 {
233 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
234 psz++, cchMax--;
235 rc = cchMax > 0 && *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
236 }
237
238 return rc;
239}
240RT_EXPORT_SYMBOL(RTStrToUInt64Ex);
241
242
243RTDECL(int) RTStrToUInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, uint64_t *pu64)
244{
245 char *psz;
246 int rc = RTStrToUInt64Ex(pszValue, &psz, uBaseAndMaxLen, pu64);
247 if (RT_SUCCESS(rc) && *psz)
248 {
249 if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
250 rc = -rc;
251 else if (rc != VINF_SUCCESS)
252 {
253 unsigned cchMax = uBaseAndMaxLen >> 8;
254 if (!cchMax)
255 cchMax = ~0U;
256 else
257 cchMax -= (unsigned)(psz - pszValue);
258 if (cchMax > 0)
259 {
260 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
261 psz++, cchMax--;
262 rc = cchMax > 0 && *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
263 }
264 }
265 }
266 return rc;
267}
268RT_EXPORT_SYMBOL(RTStrToUInt64Full);
269
270
271RTDECL(uint64_t) RTStrToUInt64(const char *pszValue)
272{
273 uint64_t u64;
274 int rc = RTStrToUInt64Ex(pszValue, NULL, 0, &u64);
275 if (RT_SUCCESS(rc))
276 return u64;
277 return 0;
278}
279RT_EXPORT_SYMBOL(RTStrToUInt64);
280
281
282RTDECL(int) RTStrToUInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint32_t *pu32)
283{
284 uint64_t u64;
285 int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &u64);
286 if (RT_SUCCESS(rc))
287 {
288 if (u64 & ~0xffffffffULL)
289 rc = VWRN_NUMBER_TOO_BIG;
290 }
291 if (pu32)
292 *pu32 = (uint32_t)u64;
293 return rc;
294}
295RT_EXPORT_SYMBOL(RTStrToUInt32Ex);
296
297
298RTDECL(int) RTStrToUInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, uint32_t *pu32)
299{
300 uint64_t u64;
301 int rc = RTStrToUInt64Full(pszValue, uBaseAndMaxLen, &u64);
302 if (RT_SUCCESS(rc))
303 {
304 if (u64 & ~0xffffffffULL)
305 rc = VWRN_NUMBER_TOO_BIG;
306 }
307 if (pu32)
308 *pu32 = (uint32_t)u64;
309 return rc;
310}
311RT_EXPORT_SYMBOL(RTStrToUInt32Full);
312
313
314RTDECL(uint32_t) RTStrToUInt32(const char *pszValue)
315{
316 uint32_t u32;
317 int rc = RTStrToUInt32Ex(pszValue, NULL, 0, &u32);
318 if (RT_SUCCESS(rc))
319 return u32;
320 return 0;
321}
322RT_EXPORT_SYMBOL(RTStrToUInt32);
323
324
325RTDECL(int) RTStrToUInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint16_t *pu16)
326{
327 uint64_t u64;
328 int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &u64);
329 if (RT_SUCCESS(rc))
330 {
331 if (u64 & ~0xffffULL)
332 rc = VWRN_NUMBER_TOO_BIG;
333 }
334 if (pu16)
335 *pu16 = (uint16_t)u64;
336 return rc;
337}
338RT_EXPORT_SYMBOL(RTStrToUInt16Ex);
339
340
341RTDECL(int) RTStrToUInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, uint16_t *pu16)
342{
343 uint64_t u64;
344 int rc = RTStrToUInt64Full(pszValue, uBaseAndMaxLen, &u64);
345 if (RT_SUCCESS(rc))
346 {
347 if (u64 & ~0xffffULL)
348 rc = VWRN_NUMBER_TOO_BIG;
349 }
350 if (pu16)
351 *pu16 = (uint16_t)u64;
352 return rc;
353}
354RT_EXPORT_SYMBOL(RTStrToUInt16Full);
355
356
357RTDECL(uint16_t) RTStrToUInt16(const char *pszValue)
358{
359 uint16_t u16;
360 int rc = RTStrToUInt16Ex(pszValue, NULL, 0, &u16);
361 if (RT_SUCCESS(rc))
362 return u16;
363 return 0;
364}
365RT_EXPORT_SYMBOL(RTStrToUInt16);
366
367
368RTDECL(int) RTStrToUInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, uint8_t *pu8)
369{
370 uint64_t u64;
371 int rc = RTStrToUInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &u64);
372 if (RT_SUCCESS(rc))
373 {
374 if (u64 & ~0xffULL)
375 rc = VWRN_NUMBER_TOO_BIG;
376 }
377 if (pu8)
378 *pu8 = (uint8_t)u64;
379 return rc;
380}
381RT_EXPORT_SYMBOL(RTStrToUInt8Ex);
382
383
384RTDECL(int) RTStrToUInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, uint8_t *pu8)
385{
386 uint64_t u64;
387 int rc = RTStrToUInt64Full(pszValue, uBaseAndMaxLen, &u64);
388 if (RT_SUCCESS(rc))
389 {
390 if (u64 & ~0xffULL)
391 rc = VWRN_NUMBER_TOO_BIG;
392 }
393 if (pu8)
394 *pu8 = (uint8_t)u64;
395 return rc;
396}
397RT_EXPORT_SYMBOL(RTStrToUInt8Full);
398
399
400RTDECL(uint8_t) RTStrToUInt8(const char *pszValue)
401{
402 uint8_t u8;
403 int rc = RTStrToUInt8Ex(pszValue, NULL, 0, &u8);
404 if (RT_SUCCESS(rc))
405 return u8;
406 return 0;
407}
408RT_EXPORT_SYMBOL(RTStrToUInt8);
409
410
411RTDECL(int) RTStrToInt64Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int64_t *pi64)
412{
413 const char *psz = pszValue;
414 int iShift;
415 int rc;
416 uint64_t u64;
417 unsigned char uch;
418 bool fPositive;
419
420 /*
421 * Split the base and length limit (latter is chiefly for sscanf).
422 */
423 unsigned uBase = uBaseAndMaxLen & 0xff;
424 unsigned cchMax = uBaseAndMaxLen >> 8;
425 if (cchMax == 0)
426 cchMax = ~0U;
427 AssertStmt(uBase < RT_ELEMENTS(g_auchShift), uBase = 0);
428
429 /*
430 * Positive/Negative stuff.
431 */
432 fPositive = true;
433 while (cchMax > 0)
434 {
435 if (*psz == '+')
436 fPositive = true;
437 else if (*psz == '-')
438 fPositive = !fPositive;
439 else
440 break;
441 psz++;
442 cchMax--;
443 }
444
445 /*
446 * Check for hex prefix.
447 */
448 if (!uBase)
449 {
450 uBase = 10;
451 if (psz[0] == '0')
452 {
453 if ( cchMax > 1
454 && (psz[1] == 'x' || psz[1] == 'X')
455 && g_auchDigits[(unsigned char)psz[2]] < 16)
456 {
457 uBase = 16;
458 psz += 2;
459 cchMax -= 2;
460 }
461 else if (g_auchDigits[(unsigned char)psz[1]] < 8)
462 uBase = 8; /* don't skip the zero, in case it's alone. */
463 }
464 }
465 else if ( uBase == 16
466 && psz[0] == '0'
467 && cchMax > 1
468 && (psz[1] == 'x' || psz[1] == 'X')
469 && g_auchDigits[(unsigned char)psz[2]] < 16)
470 {
471 cchMax -= 2;
472 psz += 2;
473 }
474
475 /*
476 * Interpret the value.
477 * Note: We only support ascii digits at this time... :-)
478 */
479 pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
480 iShift = g_auchShift[uBase];
481 rc = VINF_SUCCESS;
482 u64 = 0;
483 while (cchMax > 0 && (uch = (unsigned char)*psz) != 0)
484 {
485 unsigned char chDigit = g_auchDigits[uch];
486 uint64_t u64Prev;
487
488 if (chDigit >= uBase)
489 break;
490
491 u64Prev = u64;
492 u64 *= uBase;
493 u64 += chDigit;
494 if (u64Prev > u64 || (u64Prev >> iShift))
495 rc = VWRN_NUMBER_TOO_BIG;
496 psz++;
497 cchMax--;
498 }
499
500 /* Mixing pi64 assigning and overflow checks is to pacify a tstRTCRest-1
501 asan overflow warning. */
502 if (!(u64 & RT_BIT_64(63)))
503 {
504 if (psz == pszValue)
505 rc = VERR_NO_DIGITS;
506 if (pi64)
507 *pi64 = fPositive ? u64 : -(int64_t)u64;
508 }
509 else if (!fPositive && u64 == RT_BIT_64(63))
510 {
511 if (pi64)
512 *pi64 = INT64_MIN;
513 }
514 else
515 {
516 rc = VWRN_NUMBER_TOO_BIG;
517 if (pi64)
518 *pi64 = fPositive ? u64 : -(int64_t)u64;
519 }
520
521 if (ppszNext)
522 *ppszNext = (char *)psz;
523
524 /*
525 * Warn about trailing chars/spaces.
526 */
527 if ( rc == VINF_SUCCESS
528 && cchMax > 0
529 && *psz)
530 {
531 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
532 psz++, cchMax--;
533 rc = cchMax > 0 && *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
534 }
535
536 return rc;
537}
538RT_EXPORT_SYMBOL(RTStrToInt64Ex);
539
540
541RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, int64_t *pi64)
542{
543 char *psz;
544 int rc = RTStrToInt64Ex(pszValue, &psz, uBaseAndMaxLen, pi64);
545 if (RT_SUCCESS(rc) && *psz)
546 {
547 if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
548 rc = -rc;
549 else if (rc != VINF_SUCCESS)
550 {
551 unsigned cchMax = uBaseAndMaxLen >> 8;
552 if (!cchMax)
553 cchMax = ~0U;
554 else
555 cchMax -= (unsigned)(psz - pszValue);
556 if (cchMax > 0)
557 {
558 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
559 psz++, cchMax--;
560 rc = cchMax > 0 && *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
561 }
562 }
563 }
564 return rc;
565}
566RT_EXPORT_SYMBOL(RTStrToInt64Full);
567
568
569RTDECL(int64_t) RTStrToInt64(const char *pszValue)
570{
571 int64_t i64;
572 int rc = RTStrToInt64Ex(pszValue, NULL, 0, &i64);
573 if (RT_SUCCESS(rc))
574 return i64;
575 return 0;
576}
577RT_EXPORT_SYMBOL(RTStrToInt64);
578
579
580RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int32_t *pi32)
581{
582 int64_t i64;
583 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
584 if (RT_SUCCESS(rc))
585 {
586 int32_t i32 = (int32_t)i64;
587 if (i64 != (int64_t)i32)
588 rc = VWRN_NUMBER_TOO_BIG;
589 }
590 if (pi32)
591 *pi32 = (int32_t)i64;
592 return rc;
593}
594RT_EXPORT_SYMBOL(RTStrToInt32Ex);
595
596
597RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, int32_t *pi32)
598{
599 int64_t i64;
600 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
601 if (RT_SUCCESS(rc))
602 {
603 int32_t i32 = (int32_t)i64;
604 if (i64 != (int64_t)i32)
605 rc = VWRN_NUMBER_TOO_BIG;
606 }
607 if (pi32)
608 *pi32 = (int32_t)i64;
609 return rc;
610}
611RT_EXPORT_SYMBOL(RTStrToInt32Full);
612
613
614RTDECL(int32_t) RTStrToInt32(const char *pszValue)
615{
616 int32_t i32;
617 int rc = RTStrToInt32Ex(pszValue, NULL, 0, &i32);
618 if (RT_SUCCESS(rc))
619 return i32;
620 return 0;
621}
622RT_EXPORT_SYMBOL(RTStrToInt32);
623
624
625RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int16_t *pi16)
626{
627 int64_t i64;
628 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
629 if (RT_SUCCESS(rc))
630 {
631 int16_t i16 = (int16_t)i64;
632 if (i64 != (int64_t)i16)
633 rc = VWRN_NUMBER_TOO_BIG;
634 }
635 if (pi16)
636 *pi16 = (int16_t)i64;
637 return rc;
638}
639RT_EXPORT_SYMBOL(RTStrToInt16Ex);
640
641
642RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, int16_t *pi16)
643{
644 int64_t i64;
645 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
646 if (RT_SUCCESS(rc))
647 {
648 int16_t i16 = (int16_t)i64;
649 if (i64 != (int64_t)i16)
650 rc = VWRN_NUMBER_TOO_BIG;
651 }
652 if (pi16)
653 *pi16 = (int16_t)i64;
654 return rc;
655}
656RT_EXPORT_SYMBOL(RTStrToInt16Full);
657
658
659RTDECL(int16_t) RTStrToInt16(const char *pszValue)
660{
661 int16_t i16;
662 int rc = RTStrToInt16Ex(pszValue, NULL, 0, &i16);
663 if (RT_SUCCESS(rc))
664 return i16;
665 return 0;
666}
667RT_EXPORT_SYMBOL(RTStrToInt16);
668
669
670RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int8_t *pi8)
671{
672 int64_t i64;
673 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
674 if (RT_SUCCESS(rc))
675 {
676 int8_t i8 = (int8_t)i64;
677 if (i64 != (int64_t)i8)
678 rc = VWRN_NUMBER_TOO_BIG;
679 }
680 if (pi8)
681 *pi8 = (int8_t)i64;
682 return rc;
683}
684RT_EXPORT_SYMBOL(RTStrToInt8Ex);
685
686
687RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, int8_t *pi8)
688{
689 int64_t i64;
690 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
691 if (RT_SUCCESS(rc))
692 {
693 int8_t i8 = (int8_t)i64;
694 if (i64 != (int64_t)i8)
695 rc = VWRN_NUMBER_TOO_BIG;
696 }
697 if (pi8)
698 *pi8 = (int8_t)i64;
699 return rc;
700}
701RT_EXPORT_SYMBOL(RTStrToInt8Full);
702
703
704RTDECL(int8_t) RTStrToInt8(const char *pszValue)
705{
706 int8_t i8;
707 int rc = RTStrToInt8Ex(pszValue, NULL, 0, &i8);
708 if (RT_SUCCESS(rc))
709 return i8;
710 return 0;
711}
712RT_EXPORT_SYMBOL(RTStrToInt8);
713
714
715RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags,
716 const char **ppszNext, size_t *pcbReturned)
717{
718 size_t cbDst = cb;
719 uint8_t *pbDst = (uint8_t *)pv;
720 const unsigned char *pszSrc = (const unsigned char *)pszHex;
721 unsigned char uchDigit;
722
723 if (pcbReturned)
724 *pcbReturned = 0;
725 if (ppszNext)
726 *ppszNext = NULL;
727 AssertPtrReturn(pszHex, VERR_INVALID_POINTER);
728 AssertReturn(!(fFlags & ~RTSTRCONVERTHEXBYTES_F_SEP_COLON), VERR_INVALID_FLAGS);
729
730 if (fFlags & RTSTRCONVERTHEXBYTES_F_SEP_COLON)
731 {
732 /*
733 * Optional colon separators.
734 */
735 bool fPrevColon = true; /* leading colon is taken to mean leading zero byte */
736 for (;;)
737 {
738 /* Pick the next two digit from the string. */
739 uchDigit = g_auchDigits[*pszSrc++];
740 if (uchDigit >= 16)
741 {
742 if (uchDigit == 253 /* colon */)
743 {
744 Assert(pszSrc[-1] == ':');
745 if (!fPrevColon)
746 fPrevColon = true;
747 /* Add zero byte if there is room. */
748 else if (cbDst > 0)
749 {
750 cbDst--;
751 *pbDst++ = 0;
752 }
753 else
754 {
755 if (pcbReturned)
756 *pcbReturned = pbDst - (uint8_t *)pv;
757 if (ppszNext)
758 *ppszNext = (const char *)pszSrc - 1;
759 return VERR_BUFFER_OVERFLOW;
760 }
761 continue;
762 }
763 else
764 break;
765 }
766 else
767 {
768 /* Got one digit, check what comes next: */
769 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
770 if (uchDigit2 < 16)
771 {
772 if (cbDst > 0)
773 {
774 *pbDst++ = (uchDigit << 4) | uchDigit2;
775 cbDst--;
776 fPrevColon = false;
777 }
778 else
779 {
780 if (pcbReturned)
781 *pcbReturned = pbDst - (uint8_t *)pv;
782 if (ppszNext)
783 *ppszNext = (const char *)pszSrc - 1;
784 return VERR_BUFFER_OVERFLOW;
785 }
786 }
787 /* Lone digits are only allowed if following a colon or at the very start, because
788 if there is more than one byte it ambigious whether it is the lead or tail byte
789 that only has one digit in it.
790 Note! This also ensures better compatibility with the no-separator variant
791 (except for single digit strings, which are accepted here but not below). */
792 else if (fPrevColon)
793 {
794 if (cbDst > 0)
795 {
796 *pbDst++ = uchDigit;
797 cbDst--;
798 }
799 else
800 {
801 if (pcbReturned)
802 *pcbReturned = pbDst - (uint8_t *)pv;
803 if (ppszNext)
804 *ppszNext = (const char *)pszSrc - 1;
805 return VERR_BUFFER_OVERFLOW;
806 }
807 if (uchDigit2 == 253 /* colon */)
808 {
809 Assert(pszSrc[-1] == ':');
810 fPrevColon = true;
811 }
812 else
813 {
814 fPrevColon = false;
815 uchDigit = uchDigit2;
816 break;
817 }
818 }
819 else
820 {
821 if (pcbReturned)
822 *pcbReturned = pbDst - (uint8_t *)pv;
823 if (ppszNext)
824 *ppszNext = (const char *)pszSrc - 2;
825 return VERR_UNEVEN_INPUT;
826 }
827 }
828 }
829
830 /* Trailing colon means trailing zero byte: */
831 if (fPrevColon)
832 {
833 if (cbDst > 0)
834 {
835 *pbDst++ = 0;
836 cbDst--;
837 }
838 else
839 {
840 if (pcbReturned)
841 *pcbReturned = pbDst - (uint8_t *)pv;
842 if (ppszNext)
843 *ppszNext = (const char *)pszSrc - 1;
844 return VERR_BUFFER_OVERFLOW;
845 }
846 }
847 }
848 else
849 {
850 /*
851 * No separators.
852 */
853 for (;;)
854 {
855 /* Pick the next two digit from the string. */
856 uchDigit = g_auchDigits[*pszSrc++];
857 if (uchDigit < 16)
858 {
859 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
860 if (uchDigit2 < 16)
861 {
862 /* Add the byte to the output buffer. */
863 if (cbDst)
864 {
865 cbDst--;
866 *pbDst++ = (uchDigit << 4) | uchDigit2;
867 }
868 else
869 {
870 if (pcbReturned)
871 *pcbReturned = pbDst - (uint8_t *)pv;
872 if (ppszNext)
873 *ppszNext = (const char *)pszSrc - 2;
874 return VERR_BUFFER_OVERFLOW;
875 }
876 }
877 else
878 {
879 if (pcbReturned)
880 *pcbReturned = pbDst - (uint8_t *)pv;
881 if (ppszNext)
882 *ppszNext = (const char *)pszSrc - 2;
883 return VERR_UNEVEN_INPUT;
884 }
885 }
886 else
887 break;
888 }
889 }
890
891 /*
892 * End of hex bytes, look what comes next and figure out what to return.
893 */
894 if (pcbReturned)
895 *pcbReturned = pbDst - (uint8_t *)pv;
896 if (ppszNext)
897 *ppszNext = (const char *)pszSrc - 1;
898
899 if (uchDigit == 254)
900 {
901 Assert(pszSrc[-1] == '\0');
902 if (cbDst == 0)
903 return VINF_SUCCESS;
904 return pcbReturned ? VINF_BUFFER_UNDERFLOW : VERR_BUFFER_UNDERFLOW;
905 }
906 Assert(pszSrc[-1] != '\0');
907
908 if (cbDst != 0 && !pcbReturned)
909 return VERR_BUFFER_UNDERFLOW;
910
911 while (uchDigit == 252)
912 {
913 Assert(pszSrc[-1] == ' ' || pszSrc[-1] == '\t');
914 uchDigit = g_auchDigits[*pszSrc++];
915 }
916
917 Assert(pszSrc[-1] == '\0' ? uchDigit == 254 : uchDigit != 254);
918 return uchDigit == 254 ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
919
920}
921RT_EXPORT_SYMBOL(RTStrConvertHexBytesEx);
922
923
924RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags)
925{
926 return RTStrConvertHexBytesEx(pszHex, pv, cb, fFlags, NULL /*ppszNext*/, NULL /*pcbReturned*/);
927
928}
929RT_EXPORT_SYMBOL(RTStrConvertHexBytes);
930
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette