1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Component */
16 /** */
17 /** Utility */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "tx_api.h"
28 #include "nx_api.h"
29
30 /* Define the base64 letters. */
31 static CHAR _nx_utility_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _nx_utility_string_length_check PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* Yuxin Zhou, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function traverses the string and returns the string length, */
46 /* if the string is invalid or the string length is bigger than max */
47 /* string length, returns error. */
48 /* */
49 /* INPUT */
50 /* */
51 /* input_string Pointer to input string */
52 /* string_length Pointer to string length */
53 /* max_string_length Max string length */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* status Completion status */
58 /* */
59 /* CALLS */
60 /* */
61 /* None */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* Application Code */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
72 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* */
75 /**************************************************************************/
_nx_utility_string_length_check(CHAR * input_string,UINT * string_length,UINT max_string_length)76 UINT _nx_utility_string_length_check(CHAR *input_string, UINT *string_length, UINT max_string_length)
77 {
78
79 UINT i;
80
81
82 /* Check for invalid input pointers. */
83 if (input_string == NX_NULL)
84 {
85 return(NX_PTR_ERROR);
86 }
87
88 /* Traverse the string. */
89 for (i = 0; input_string[i]; i++)
90 {
91
92 /* Check if the string length is bigger than the max string length. */
93 if (i >= max_string_length)
94 {
95 return(NX_SIZE_ERROR);
96 }
97 }
98
99 /* Return the string length if string_length is not NULL.
100 String_length being NULL indicates the caller needs to check for string
101 length within the max_string_length. */
102 if (string_length)
103 {
104 *string_length = i;
105 }
106
107 /* Return success. */
108 return(NX_SUCCESS);
109 }
110
111 /**************************************************************************/
112 /* */
113 /* FUNCTION RELEASE */
114 /* */
115 /* _nx_utility_string_to_uint PORTABLE C */
116 /* 6.1.3 */
117 /* AUTHOR */
118 /* */
119 /* Yuxin Zhou, Microsoft Corporation */
120 /* */
121 /* DESCRIPTION */
122 /* */
123 /* This function converts the string to unsigned integer. */
124 /* */
125 /* INPUT */
126 /* */
127 /* input_string Pointer to input string */
128 /* string_length Length of input string */
129 /* number Pointer to the number */
130 /* */
131 /* OUTPUT */
132 /* */
133 /* status Completion status */
134 /* */
135 /* CALLS */
136 /* */
137 /* None */
138 /* */
139 /* CALLED BY */
140 /* */
141 /* Application Code */
142 /* */
143 /* RELEASE HISTORY */
144 /* */
145 /* DATE NAME DESCRIPTION */
146 /* */
147 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
148 /* */
149 /**************************************************************************/
_nx_utility_string_to_uint(CHAR * input_string,UINT string_length,UINT * number)150 UINT _nx_utility_string_to_uint(CHAR *input_string, UINT string_length, UINT *number)
151 {
152
153 UINT i;
154
155
156 /* Check for invalid input pointers. */
157 if ((input_string == NX_NULL) || (number == NX_NULL))
158 {
159 return(NX_PTR_ERROR);
160 }
161
162 /* Check string length. */
163 if (string_length == 0)
164 {
165 return(NX_SIZE_ERROR);
166 }
167
168 /* Initialize. */
169 i = 0;
170 *number = 0;
171
172 /* Traverse the string. */
173 while (i < string_length)
174 {
175
176 /* Is a numeric character present? */
177 if ((input_string[i] >= '0') && (input_string[i] <= '9'))
178 {
179
180 /* Check overflow. Max Value: Hex:0xFFFFFFFF, Decimal: 4294967295. */
181 if (((*number == 429496729) && (input_string[i] > '5')) ||
182 (*number >= 429496730))
183 {
184 return(NX_OVERFLOW);
185 }
186
187 /* Yes, numeric character is present. Update the number. */
188 *number = (*number * 10) + (UINT) (input_string[i] - '0');
189 }
190 else
191 {
192 return(NX_INVALID_PARAMETERS);
193 }
194
195 i++;
196 }
197
198 /* Return success. */
199 return(NX_SUCCESS);
200 }
201
202 /**************************************************************************/
203 /* */
204 /* FUNCTION RELEASE */
205 /* */
206 /* _nx_utility_uint_to_string PORTABLE C */
207 /* 6.1.9 */
208 /* AUTHOR */
209 /* */
210 /* Yuxin Zhou, Microsoft Corporation */
211 /* */
212 /* DESCRIPTION */
213 /* */
214 /* This function converts the unsigned integer to string. */
215 /* */
216 /* INPUT */
217 /* */
218 /* number Input number */
219 /* base Base of the conversion */
220 /* 8 for OCT */
221 /* 10 for DEC */
222 /* 16 for HEX */
223 /* string_buffer Pointer to string buffer */
224 /* string_buffer_size Size of string buffer */
225 /* */
226 /* OUTPUT */
227 /* */
228 /* size The size of output string */
229 /* */
230 /* CALLS */
231 /* */
232 /* None */
233 /* */
234 /* CALLED BY */
235 /* */
236 /* Application Code */
237 /* */
238 /* RELEASE HISTORY */
239 /* */
240 /* DATE NAME DESCRIPTION */
241 /* */
242 /* 08-02-2021 Yuxin Zhou Initial Version 6.1.8 */
243 /* 10-15-2021 Yuxin Zhou Modified comment(s), */
244 /* checked invalid input value,*/
245 /* resulting in version 6.1.9 */
246 /* */
247 /**************************************************************************/
_nx_utility_uint_to_string(UINT number,UINT base,CHAR * string_buffer,UINT string_buffer_size)248 UINT _nx_utility_uint_to_string(UINT number, UINT base, CHAR *string_buffer, UINT string_buffer_size)
249 {
250 UINT i;
251 UINT digit;
252 UINT size;
253
254 /* Check for invalid input pointers. */
255 if ((string_buffer == NX_NULL) || (string_buffer_size == 0) || (base == 0))
256 {
257 return(0);
258 }
259
260 /* Initialize. */
261 i = 0;
262 size = 0;
263
264 /* Loop to convert the number to ASCII. Minus 1 to put NULL terminal. */
265 while (size < string_buffer_size - 1)
266 {
267
268 /* Shift the current digits over one. */
269 for (i = size; i != 0; i--)
270 {
271
272 /* Move each digit over one place. */
273 string_buffer[i] = string_buffer[i-1];
274 }
275
276 /* Compute the next decimal digit. */
277 digit = number % base;
278
279 /* Update the input number. */
280 number = number / base;
281
282 /* Store the new digit in ASCII form. */
283 if (digit < 10)
284 {
285 string_buffer[0] = (CHAR) (digit + '0');
286 }
287 else
288 {
289 string_buffer[0] = (CHAR) (digit + 'a' - 0xa);
290 }
291
292 /* Increment the size. */
293 size++;
294
295 /* Determine if the number is now zero. */
296 if (number == 0)
297 break;
298 }
299
300 /* Determine if there is an overflow error. */
301 if (number)
302 {
303
304 /* Error, return bad values to user. */
305 size = 0;
306 }
307
308 /* Make the string NULL terminated. */
309 string_buffer[size] = (CHAR) NX_NULL;
310
311 /* Return size to caller. */
312 return(size);
313 }
314
315 /**************************************************************************/
316 /* */
317 /* FUNCTION RELEASE */
318 /* */
319 /* _nx_utility_base64_encode PORTABLE C */
320 /* 6.2.0 */
321 /* AUTHOR */
322 /* */
323 /* Yuxin Zhou, Microsoft Corporation */
324 /* */
325 /* DESCRIPTION */
326 /* */
327 /* This function encodes the input string into a base64 */
328 /* representation. */
329 /* */
330 /* INPUT */
331 /* */
332 /* name Name string */
333 /* name_size Size of name */
334 /* base64name Encoded base64 name string */
335 /* base64name_size Size of encoded base64 name */
336 /* bytes_copied Number of bytes copied */
337 /* */
338 /* OUTPUT */
339 /* */
340 /* status Completion status */
341 /* */
342 /* CALLS */
343 /* */
344 /* None */
345 /* */
346 /* CALLED BY */
347 /* */
348 /* Application Code */
349 /* */
350 /* RELEASE HISTORY */
351 /* */
352 /* DATE NAME DESCRIPTION */
353 /* */
354 /* 04-02-2021 Yuxin Zhou Initial Version 6.1.6 */
355 /* 10-31-2022 Yuxin Zhou Modified comment(s), */
356 /* improved the internal logic,*/
357 /* resulting in version 6.2.0 */
358 /* */
359 /**************************************************************************/
_nx_utility_base64_encode(UCHAR * name,UINT name_size,UCHAR * base64name,UINT base64name_size,UINT * bytes_copied)360 UINT _nx_utility_base64_encode(UCHAR *name, UINT name_size, UCHAR *base64name, UINT base64name_size, UINT *bytes_copied)
361 {
362 UINT pad;
363 UINT i, j;
364 UINT step;
365 UINT input_name_size = name_size;
366
367
368 /* Check for invalid input pointers. */
369 if ((name == NX_NULL) || (base64name == NX_NULL) || (bytes_copied == NX_NULL))
370 {
371 return(NX_PTR_ERROR);
372 }
373
374 /* Check the size. */
375 if ((name_size == 0) || (base64name_size == 0))
376 {
377 return(NX_SIZE_ERROR);
378 }
379
380 /* Adjust the length to represent the base64 name. */
381 name_size = ((name_size * 8) / 6);
382
383 /* Default padding to none. */
384 pad = 0;
385
386 /* Determine if an extra conversion is needed. */
387 if ((name_size * 6) % 24)
388 {
389
390 /* Some padding is needed. */
391
392 /* Calculate the number of pad characters. */
393 pad = (name_size * 6) % 24;
394 pad = (24 - pad) / 6;
395 pad = pad - 1;
396
397 /* Adjust the length to pickup the character fraction. */
398 name_size++;
399 }
400
401 /* Check the buffer size. */
402 if (base64name_size <= (name_size + pad))
403 {
404 return(NX_SIZE_ERROR);
405 }
406
407 /* Setup index into the base64name. */
408 j = 0;
409
410 /* Compute the base64name. */
411 step = 0;
412 i = 0;
413 while (j < name_size)
414 {
415
416 /* Determine which step we are in. */
417 if (step == 0)
418 {
419
420 /* Use first 6 bits of name character for index. */
421 base64name[j++] = (UCHAR)_nx_utility_base64_array[((UCHAR)name[i]) >> 2];
422 step++;
423 }
424 else if (step == 1)
425 {
426
427 /* Use last 2 bits of name character and first 4 bits of next name character for index. */
428 if ((i + 1) < input_name_size)
429 {
430 base64name[j++] = (UCHAR)_nx_utility_base64_array[((((UCHAR)name[i]) & 0x3) << 4) | (((UCHAR)name[i + 1]) >> 4)];
431 }
432 else
433 {
434
435 /* If no more name character, pad with zero. */
436 base64name[j++] = (UCHAR)_nx_utility_base64_array[(((UCHAR)name[i]) & 0x3) << 4];
437 }
438 i++;
439 step++;
440 }
441 else if (step == 2)
442 {
443
444 /* Use last 4 bits of name character and first 2 bits of next name character for index. */
445 if ((i + 1) < input_name_size)
446 {
447 base64name[j++] = (UCHAR)_nx_utility_base64_array[((((UCHAR)name[i]) & 0xF) << 2) | (((UCHAR)name[i + 1]) >> 6)];
448 }
449 else
450 {
451
452 /* If no more name character, pad with zero. */
453 base64name[j++] = (UCHAR)_nx_utility_base64_array[(((UCHAR)name[i]) & 0xF) << 2];
454 }
455 i++;
456 step++;
457 }
458 else /* Step 3 */
459 {
460
461 /* Use last 6 bits of name character for index. */
462 base64name[j++] = (UCHAR)_nx_utility_base64_array[(((UCHAR)name[i]) & 0x3F)];
463 i++;
464 step = 0;
465 }
466 }
467
468 /* Now add the PAD characters. */
469 while (pad--)
470 {
471
472 /* Pad base64name with '=' characters. */
473 base64name[j++] = '=';
474 }
475
476 /* Put a NULL character in. */
477 base64name[j] = NX_NULL;
478 *bytes_copied = j;
479
480 return(NX_SUCCESS);
481 }
482
483 /**************************************************************************/
484 /* */
485 /* FUNCTION RELEASE */
486 /* */
487 /* _nx_utility_base64_decode PORTABLE C */
488 /* 6.1.10 */
489 /* AUTHOR */
490 /* */
491 /* Yuxin Zhou, Microsoft Corporation */
492 /* */
493 /* DESCRIPTION */
494 /* */
495 /* This function decodes the input base64 ASCII string and converts */
496 /* it into a standard ASCII representation. */
497 /* */
498 /* INPUT */
499 /* */
500 /* base64name Encoded base64 name string */
501 /* base64name_size Size of encoded base64 name */
502 /* name Name string */
503 /* name_size Size of name */
504 /* bytes_copied Number of bytes copied */
505 /* */
506 /* OUTPUT */
507 /* */
508 /* None */
509 /* */
510 /* CALLS */
511 /* */
512 /* None */
513 /* */
514 /* CALLED BY */
515 /* */
516 /* Application Code */
517 /* */
518 /* RELEASE HISTORY */
519 /* */
520 /* DATE NAME DESCRIPTION */
521 /* */
522 /* 04-02-2021 Yuxin Zhou Initial Version 6.1.6 */
523 /* 10-15-2021 Yuxin Zhou Modified comment(s), */
524 /* removed useless condition, */
525 /* resulting in version 6.1.9 */
526 /* 01-31-2022 Yuxin Zhou Modified comment(s), */
527 /* fixed the issue of reading */
528 /* overflow, */
529 /* resulting in version 6.1.10 */
530 /* */
531 /**************************************************************************/
_nx_utility_base64_decode(UCHAR * base64name,UINT base64name_size,UCHAR * name,UINT name_size,UINT * bytes_copied)532 UINT _nx_utility_base64_decode(UCHAR *base64name, UINT base64name_size, UCHAR *name, UINT name_size, UINT *bytes_copied)
533 {
534 UINT i, j;
535 UINT value1, value2;
536 UINT step;
537 UINT source_size = base64name_size;
538
539 /* Check for invalid input pointers. */
540 if ((base64name == NX_NULL) || (name == NX_NULL) || (bytes_copied == NX_NULL))
541 {
542 return(NX_PTR_ERROR);
543 }
544
545 /* Check the size. */
546 if ((base64name_size == 0) || (name_size == 0))
547 {
548 return(NX_SIZE_ERROR);
549 }
550
551 /* Adjust the length to represent the ASCII name. */
552 base64name_size = ((base64name_size * 6) / 8);
553
554 if ((base64name_size) && (base64name[source_size - 1] == '='))
555 {
556 base64name_size--;
557
558 if ((base64name_size) && (base64name[source_size - 2] == '='))
559 {
560 base64name_size--;
561 }
562 }
563
564 /* Check the buffer size. */
565 if (name_size <= base64name_size)
566 {
567 return(NX_SIZE_ERROR);
568 }
569
570 /* Setup index into the ASCII name. */
571 j = 0;
572
573 /* Compute the ASCII name. */
574 step = 0;
575 i = 0;
576 while ((j < base64name_size) && (base64name[i]) && (base64name[i] != '='))
577 {
578
579 /* Derive values of the Base64 name. */
580 if ((base64name[i] >= 'A') && (base64name[i] <= 'Z'))
581 value1 = (UINT) (base64name[i] - 'A');
582 else if ((base64name[i] >= 'a') && (base64name[i] <= 'z'))
583 value1 = (UINT) (base64name[i] - 'a') + 26;
584 else if ((base64name[i] >= '0') && (base64name[i] <= '9'))
585 value1 = (UINT) (base64name[i] - '0') + 52;
586 else if ((base64name[i] == '+') ||
587 (base64name[i] == '-')) /* Base64 URL. */
588 value1 = 62;
589 else if ((base64name[i] == '/') ||
590 (base64name[i] == '_')) /* Base64 URL. */
591 value1 = 63;
592 else
593 value1 = 0;
594
595 /* Derive value for the next character. */
596 if ((base64name[i + 1] >= 'A') && (base64name[i + 1] <= 'Z'))
597 value2 = (UINT) (base64name[i+1] - 'A');
598 else if ((base64name[i + 1] >= 'a') && (base64name[i + 1] <= 'z'))
599 value2 = (UINT) (base64name[i+1] - 'a') + 26;
600 else if ((base64name[i + 1] >= '0') && (base64name[i + 1] <= '9'))
601 value2 = (UINT) (base64name[i+1] - '0') + 52;
602 else if ((base64name[i + 1] == '+') ||
603 (base64name[i + 1] == '-')) /* Base64 URL. */
604 value2 = 62;
605 else if ((base64name[i + 1] == '/') ||
606 (base64name[i + 1] == '_')) /* Base64 URL. */
607 value2 = 63;
608 else
609 value2 = 0;
610
611 /* Determine which step we are in. */
612 if (step == 0)
613 {
614
615 /* Use first value and first 2 bits of second value. */
616 name[j++] = (UCHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3));
617 i++;
618 step++;
619 }
620 else if (step == 1)
621 {
622
623 /* Use last 4 bits of first value and first 4 bits of next value. */
624 name[j++] = (UCHAR) (((value1 & 0xF) << 4) | (value2 >> 2));
625 i++;
626 step++;
627 }
628 else
629 {
630
631 /* Use first 2 bits and following 6 bits of next value. */
632 name[j++] = (UCHAR) (((value1 & 3) << 6) | (value2 & 0x3f));
633 i++;
634 i++;
635 step = 0;
636 }
637 }
638
639 /* Put a NULL character in. */
640 name[j] = NX_NULL;
641 *bytes_copied = j;
642
643 return(NX_SUCCESS);
644 }