VirtualBox

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

Last change on this file since 107649 was 107429, checked in by vboxsync, 2 weeks ago

Runtime/common/string/strtonum.cpp: Fixed a warning found by Parfait. ​jiraref:VBP-1424

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 26.2 KB
Line 
1/* $Id: strtonum.cpp 107429 2025-01-06 17:08:14Z 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 ( 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 ( cchMax > 1
456 && (psz[1] == 'x' || psz[1] == 'X')
457 && g_auchDigits[(unsigned char)psz[2]] < 16)
458 {
459 uBase = 16;
460 psz += 2;
461 cchMax -= 2;
462 }
463 else if ( psz[0] == '0'
464 && g_auchDigits[(unsigned char)psz[1]] < 8)
465 uBase = 8; /* don't skip the zero, in case it's alone. */
466 }
467 }
468 else if ( uBase == 16
469 && psz[0] == '0'
470 && cchMax > 1
471 && (psz[1] == 'x' || psz[1] == 'X')
472 && g_auchDigits[(unsigned char)psz[2]] < 16)
473 {
474 cchMax -= 2;
475 psz += 2;
476 }
477
478 /*
479 * Interpret the value.
480 * Note: We only support ascii digits at this time... :-)
481 */
482 pszValue = psz; /* (Prefix and sign doesn't count in the digit counting.) */
483 iShift = g_auchShift[uBase];
484 rc = VINF_SUCCESS;
485 u64 = 0;
486 while (cchMax > 0 && (uch = (unsigned char)*psz) != 0)
487 {
488 unsigned char chDigit = g_auchDigits[uch];
489 uint64_t u64Prev;
490
491 if (chDigit >= uBase)
492 break;
493
494 u64Prev = u64;
495 u64 *= uBase;
496 u64 += chDigit;
497 if (u64Prev > u64 || (u64Prev >> iShift))
498 rc = VWRN_NUMBER_TOO_BIG;
499 psz++;
500 cchMax--;
501 }
502
503 /* Mixing pi64 assigning and overflow checks is to pacify a tstRTCRest-1
504 asan overflow warning. */
505 if (!(u64 & RT_BIT_64(63)))
506 {
507 if (psz == pszValue)
508 rc = VERR_NO_DIGITS;
509 if (pi64)
510 *pi64 = fPositive ? u64 : -(int64_t)u64;
511 }
512 else if (!fPositive && u64 == RT_BIT_64(63))
513 {
514 if (pi64)
515 *pi64 = INT64_MIN;
516 }
517 else
518 {
519 rc = VWRN_NUMBER_TOO_BIG;
520 if (pi64)
521 *pi64 = fPositive ? u64 : -(int64_t)u64;
522 }
523
524 if (ppszNext)
525 *ppszNext = (char *)psz;
526
527 /*
528 * Warn about trailing chars/spaces.
529 */
530 if ( rc == VINF_SUCCESS
531 && cchMax > 0
532 && *psz)
533 {
534 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
535 psz++, cchMax--;
536 rc = cchMax > 0 && *psz ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
537 }
538
539 return rc;
540}
541RT_EXPORT_SYMBOL(RTStrToInt64Ex);
542
543
544RTDECL(int) RTStrToInt64Full(const char *pszValue, unsigned uBaseAndMaxLen, int64_t *pi64)
545{
546 char *psz;
547 int rc = RTStrToInt64Ex(pszValue, &psz, uBaseAndMaxLen, pi64);
548 if (RT_SUCCESS(rc) && *psz)
549 {
550 if (rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES)
551 rc = -rc;
552 else if (rc != VINF_SUCCESS)
553 {
554 unsigned cchMax = uBaseAndMaxLen >> 8;
555 if (!cchMax)
556 cchMax = ~0U;
557 else
558 cchMax -= (unsigned)(psz - pszValue);
559 if (cchMax > 0)
560 {
561 while (cchMax > 0 && (*psz == ' ' || *psz == '\t'))
562 psz++, cchMax--;
563 rc = cchMax > 0 && *psz ? VERR_TRAILING_CHARS : VERR_TRAILING_SPACES;
564 }
565 }
566 }
567 return rc;
568}
569RT_EXPORT_SYMBOL(RTStrToInt64Full);
570
571
572RTDECL(int64_t) RTStrToInt64(const char *pszValue)
573{
574 int64_t i64;
575 int rc = RTStrToInt64Ex(pszValue, NULL, 0, &i64);
576 if (RT_SUCCESS(rc))
577 return i64;
578 return 0;
579}
580RT_EXPORT_SYMBOL(RTStrToInt64);
581
582
583RTDECL(int) RTStrToInt32Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int32_t *pi32)
584{
585 int64_t i64;
586 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
587 if (RT_SUCCESS(rc))
588 {
589 int32_t i32 = (int32_t)i64;
590 if (i64 != (int64_t)i32)
591 rc = VWRN_NUMBER_TOO_BIG;
592 }
593 if (pi32)
594 *pi32 = (int32_t)i64;
595 return rc;
596}
597RT_EXPORT_SYMBOL(RTStrToInt32Ex);
598
599
600RTDECL(int) RTStrToInt32Full(const char *pszValue, unsigned uBaseAndMaxLen, int32_t *pi32)
601{
602 int64_t i64;
603 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
604 if (RT_SUCCESS(rc))
605 {
606 int32_t i32 = (int32_t)i64;
607 if (i64 != (int64_t)i32)
608 rc = VWRN_NUMBER_TOO_BIG;
609 }
610 if (pi32)
611 *pi32 = (int32_t)i64;
612 return rc;
613}
614RT_EXPORT_SYMBOL(RTStrToInt32Full);
615
616
617RTDECL(int32_t) RTStrToInt32(const char *pszValue)
618{
619 int32_t i32;
620 int rc = RTStrToInt32Ex(pszValue, NULL, 0, &i32);
621 if (RT_SUCCESS(rc))
622 return i32;
623 return 0;
624}
625RT_EXPORT_SYMBOL(RTStrToInt32);
626
627
628RTDECL(int) RTStrToInt16Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int16_t *pi16)
629{
630 int64_t i64;
631 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
632 if (RT_SUCCESS(rc))
633 {
634 int16_t i16 = (int16_t)i64;
635 if (i64 != (int64_t)i16)
636 rc = VWRN_NUMBER_TOO_BIG;
637 }
638 if (pi16)
639 *pi16 = (int16_t)i64;
640 return rc;
641}
642RT_EXPORT_SYMBOL(RTStrToInt16Ex);
643
644
645RTDECL(int) RTStrToInt16Full(const char *pszValue, unsigned uBaseAndMaxLen, int16_t *pi16)
646{
647 int64_t i64;
648 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
649 if (RT_SUCCESS(rc))
650 {
651 int16_t i16 = (int16_t)i64;
652 if (i64 != (int64_t)i16)
653 rc = VWRN_NUMBER_TOO_BIG;
654 }
655 if (pi16)
656 *pi16 = (int16_t)i64;
657 return rc;
658}
659RT_EXPORT_SYMBOL(RTStrToInt16Full);
660
661
662RTDECL(int16_t) RTStrToInt16(const char *pszValue)
663{
664 int16_t i16;
665 int rc = RTStrToInt16Ex(pszValue, NULL, 0, &i16);
666 if (RT_SUCCESS(rc))
667 return i16;
668 return 0;
669}
670RT_EXPORT_SYMBOL(RTStrToInt16);
671
672
673RTDECL(int) RTStrToInt8Ex(const char *pszValue, char **ppszNext, unsigned uBaseAndMaxLen, int8_t *pi8)
674{
675 int64_t i64;
676 int rc = RTStrToInt64Ex(pszValue, ppszNext, uBaseAndMaxLen, &i64);
677 if (RT_SUCCESS(rc))
678 {
679 int8_t i8 = (int8_t)i64;
680 if (i64 != (int64_t)i8)
681 rc = VWRN_NUMBER_TOO_BIG;
682 }
683 if (pi8)
684 *pi8 = (int8_t)i64;
685 return rc;
686}
687RT_EXPORT_SYMBOL(RTStrToInt8Ex);
688
689
690RTDECL(int) RTStrToInt8Full(const char *pszValue, unsigned uBaseAndMaxLen, int8_t *pi8)
691{
692 int64_t i64;
693 int rc = RTStrToInt64Full(pszValue, uBaseAndMaxLen, &i64);
694 if (RT_SUCCESS(rc))
695 {
696 int8_t i8 = (int8_t)i64;
697 if (i64 != (int64_t)i8)
698 rc = VWRN_NUMBER_TOO_BIG;
699 }
700 if (pi8)
701 *pi8 = (int8_t)i64;
702 return rc;
703}
704RT_EXPORT_SYMBOL(RTStrToInt8Full);
705
706
707RTDECL(int8_t) RTStrToInt8(const char *pszValue)
708{
709 int8_t i8;
710 int rc = RTStrToInt8Ex(pszValue, NULL, 0, &i8);
711 if (RT_SUCCESS(rc))
712 return i8;
713 return 0;
714}
715RT_EXPORT_SYMBOL(RTStrToInt8);
716
717
718RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags,
719 const char **ppszNext, size_t *pcbReturned)
720{
721 size_t cbDst = cb;
722 uint8_t *pbDst = (uint8_t *)pv;
723 const unsigned char *pszSrc = (const unsigned char *)pszHex;
724 unsigned char uchDigit;
725
726 if (pcbReturned)
727 *pcbReturned = 0;
728 if (ppszNext)
729 *ppszNext = NULL;
730 AssertPtrReturn(pszHex, VERR_INVALID_POINTER);
731 AssertReturn(!(fFlags & ~RTSTRCONVERTHEXBYTES_F_SEP_COLON), VERR_INVALID_FLAGS);
732
733 if (fFlags & RTSTRCONVERTHEXBYTES_F_SEP_COLON)
734 {
735 /*
736 * Optional colon separators.
737 */
738 bool fPrevColon = true; /* leading colon is taken to mean leading zero byte */
739 for (;;)
740 {
741 /* Pick the next two digit from the string. */
742 uchDigit = g_auchDigits[*pszSrc++];
743 if (uchDigit >= 16)
744 {
745 if (uchDigit == 253 /* colon */)
746 {
747 Assert(pszSrc[-1] == ':');
748 if (!fPrevColon)
749 fPrevColon = true;
750 /* Add zero byte if there is room. */
751 else if (cbDst > 0)
752 {
753 cbDst--;
754 *pbDst++ = 0;
755 }
756 else
757 {
758 if (pcbReturned)
759 *pcbReturned = pbDst - (uint8_t *)pv;
760 if (ppszNext)
761 *ppszNext = (const char *)pszSrc - 1;
762 return VERR_BUFFER_OVERFLOW;
763 }
764 continue;
765 }
766 else
767 break;
768 }
769 else
770 {
771 /* Got one digit, check what comes next: */
772 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
773 if (uchDigit2 < 16)
774 {
775 if (cbDst > 0)
776 {
777 *pbDst++ = (uchDigit << 4) | uchDigit2;
778 cbDst--;
779 fPrevColon = false;
780 }
781 else
782 {
783 if (pcbReturned)
784 *pcbReturned = pbDst - (uint8_t *)pv;
785 if (ppszNext)
786 *ppszNext = (const char *)pszSrc - 1;
787 return VERR_BUFFER_OVERFLOW;
788 }
789 }
790 /* Lone digits are only allowed if following a colon or at the very start, because
791 if there is more than one byte it ambigious whether it is the lead or tail byte
792 that only has one digit in it.
793 Note! This also ensures better compatibility with the no-separator variant
794 (except for single digit strings, which are accepted here but not below). */
795 else if (fPrevColon)
796 {
797 if (cbDst > 0)
798 {
799 *pbDst++ = uchDigit;
800 cbDst--;
801 }
802 else
803 {
804 if (pcbReturned)
805 *pcbReturned = pbDst - (uint8_t *)pv;
806 if (ppszNext)
807 *ppszNext = (const char *)pszSrc - 1;
808 return VERR_BUFFER_OVERFLOW;
809 }
810 if (uchDigit2 == 253 /* colon */)
811 {
812 Assert(pszSrc[-1] == ':');
813 fPrevColon = true;
814 }
815 else
816 {
817 fPrevColon = false;
818 uchDigit = uchDigit2;
819 break;
820 }
821 }
822 else
823 {
824 if (pcbReturned)
825 *pcbReturned = pbDst - (uint8_t *)pv;
826 if (ppszNext)
827 *ppszNext = (const char *)pszSrc - 2;
828 return VERR_UNEVEN_INPUT;
829 }
830 }
831 }
832
833 /* Trailing colon means trailing zero byte: */
834 if (fPrevColon)
835 {
836 if (cbDst > 0)
837 {
838 *pbDst++ = 0;
839 cbDst--;
840 }
841 else
842 {
843 if (pcbReturned)
844 *pcbReturned = pbDst - (uint8_t *)pv;
845 if (ppszNext)
846 *ppszNext = (const char *)pszSrc - 1;
847 return VERR_BUFFER_OVERFLOW;
848 }
849 }
850 }
851 else
852 {
853 /*
854 * No separators.
855 */
856 for (;;)
857 {
858 /* Pick the next two digit from the string. */
859 uchDigit = g_auchDigits[*pszSrc++];
860 if (uchDigit < 16)
861 {
862 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
863 if (uchDigit2 < 16)
864 {
865 /* Add the byte to the output buffer. */
866 if (cbDst)
867 {
868 cbDst--;
869 *pbDst++ = (uchDigit << 4) | uchDigit2;
870 }
871 else
872 {
873 if (pcbReturned)
874 *pcbReturned = pbDst - (uint8_t *)pv;
875 if (ppszNext)
876 *ppszNext = (const char *)pszSrc - 2;
877 return VERR_BUFFER_OVERFLOW;
878 }
879 }
880 else
881 {
882 if (pcbReturned)
883 *pcbReturned = pbDst - (uint8_t *)pv;
884 if (ppszNext)
885 *ppszNext = (const char *)pszSrc - 2;
886 return VERR_UNEVEN_INPUT;
887 }
888 }
889 else
890 break;
891 }
892 }
893
894 /*
895 * End of hex bytes, look what comes next and figure out what to return.
896 */
897 if (pcbReturned)
898 *pcbReturned = pbDst - (uint8_t *)pv;
899 if (ppszNext)
900 *ppszNext = (const char *)pszSrc - 1;
901
902 if (uchDigit == 254)
903 {
904 Assert(pszSrc[-1] == '\0');
905 if (cbDst == 0)
906 return VINF_SUCCESS;
907 return pcbReturned ? VINF_BUFFER_UNDERFLOW : VERR_BUFFER_UNDERFLOW;
908 }
909 Assert(pszSrc[-1] != '\0');
910
911 if (cbDst != 0 && !pcbReturned)
912 return VERR_BUFFER_UNDERFLOW;
913
914 while (uchDigit == 252)
915 {
916 Assert(pszSrc[-1] == ' ' || pszSrc[-1] == '\t');
917 uchDigit = g_auchDigits[*pszSrc++];
918 }
919
920 Assert(pszSrc[-1] == '\0' ? uchDigit == 254 : uchDigit != 254);
921 return uchDigit == 254 ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
922
923}
924RT_EXPORT_SYMBOL(RTStrConvertHexBytesEx);
925
926
927RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags)
928{
929 return RTStrConvertHexBytesEx(pszHex, pv, cb, fFlags, NULL /*ppszNext*/, NULL /*pcbReturned*/);
930
931}
932RT_EXPORT_SYMBOL(RTStrConvertHexBytes);
933
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