uuid.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. void uuid_unparse_lower_compact(const uuid_t uuid, char *out) {
  4. static const char *hex_chars = "0123456789abcdef";
  5. for (int i = 0; i < 16; i++) {
  6. out[i * 2] = hex_chars[(uuid[i] >> 4) & 0x0F];
  7. out[i * 2 + 1] = hex_chars[uuid[i] & 0x0F];
  8. }
  9. out[32] = '\0'; // Null-terminate the string
  10. }
  11. inline int uuid_parse_compact(const char *in, uuid_t uuid) {
  12. if (strlen(in) != 32)
  13. return -1; // Invalid input length
  14. for (int i = 0; i < 16; i++) {
  15. int high = hex_char_to_int(in[i * 2]);
  16. int low = hex_char_to_int(in[i * 2 + 1]);
  17. if (high < 0 || low < 0)
  18. return -1; // Invalid hexadecimal character
  19. uuid[i] = (high << 4) | low;
  20. }
  21. return 0; // Success
  22. }
  23. int uuid_parse_flexi(const char *in, uuid_t uu) {
  24. if(!in || !*in)
  25. return -1;
  26. size_t hexCharCount = 0;
  27. size_t hyphenCount = 0;
  28. const char *s = in;
  29. int byteIndex = 0;
  30. uuid_t uuid; // work on a temporary place, to not corrupt the previous value of uu if we fail
  31. while (*s && byteIndex < 16) {
  32. if (*s == '-') {
  33. s++;
  34. hyphenCount++;
  35. if (unlikely(hyphenCount > 4))
  36. // Too many hyphens
  37. return -2;
  38. }
  39. if (likely(isxdigit(*s))) {
  40. int high = hex_char_to_int(*s++);
  41. hexCharCount++;
  42. if (likely(isxdigit(*s))) {
  43. int low = hex_char_to_int(*s++);
  44. hexCharCount++;
  45. uuid[byteIndex++] = (high << 4) | low;
  46. }
  47. else
  48. // Not a valid UUID (expected a pair of hex digits)
  49. return -3;
  50. }
  51. else
  52. // Not a valid UUID
  53. return -4;
  54. }
  55. if (unlikely(byteIndex < 16))
  56. // Not enough data to form a UUID
  57. return -5;
  58. if (unlikely(hexCharCount != 32))
  59. // wrong number of hex digits
  60. return -6;
  61. if(unlikely(hyphenCount != 0 && hyphenCount != 4))
  62. // wrong number of hyphens
  63. return -7;
  64. // copy the final value
  65. memcpy(uu, uuid, sizeof(uuid_t));
  66. return 0;
  67. }
  68. // ----------------------------------------------------------------------------
  69. // unit test
  70. static inline void remove_hyphens(const char *uuid_with_hyphens, char *uuid_without_hyphens) {
  71. while (*uuid_with_hyphens) {
  72. if (*uuid_with_hyphens != '-') {
  73. *uuid_without_hyphens++ = *uuid_with_hyphens;
  74. }
  75. uuid_with_hyphens++;
  76. }
  77. *uuid_without_hyphens = '\0';
  78. }
  79. int uuid_unittest(void) {
  80. const int num_tests = 100000;
  81. int failed_tests = 0;
  82. int i;
  83. for (i = 0; i < num_tests; i++) {
  84. uuid_t original_uuid, parsed_uuid;
  85. char uuid_str_with_hyphens[UUID_STR_LEN], uuid_str_without_hyphens[UUID_COMPACT_STR_LEN];
  86. // Generate a random UUID
  87. switch(i % 2) {
  88. case 0:
  89. uuid_generate(original_uuid);
  90. break;
  91. case 1:
  92. uuid_generate_random(original_uuid);
  93. break;
  94. }
  95. // Unparse it with hyphens
  96. bool lower = false;
  97. switch(i % 3) {
  98. case 0:
  99. uuid_unparse_lower(original_uuid, uuid_str_with_hyphens);
  100. lower = true;
  101. break;
  102. case 1:
  103. uuid_unparse(original_uuid, uuid_str_with_hyphens);
  104. break;
  105. case 2:
  106. uuid_unparse_upper(original_uuid, uuid_str_with_hyphens);
  107. break;
  108. }
  109. // Remove the hyphens
  110. remove_hyphens(uuid_str_with_hyphens, uuid_str_without_hyphens);
  111. if(lower) {
  112. char test[UUID_COMPACT_STR_LEN];
  113. uuid_unparse_lower_compact(original_uuid, test);
  114. if(strcmp(test, uuid_str_without_hyphens) != 0) {
  115. printf("uuid_unparse_lower_compact() failed, expected '%s', got '%s'\n",
  116. uuid_str_without_hyphens, test);
  117. failed_tests++;
  118. }
  119. }
  120. // Parse the UUID string with hyphens
  121. int parse_result = uuid_parse_flexi(uuid_str_with_hyphens, parsed_uuid);
  122. if (parse_result != 0) {
  123. printf("uuid_parse_flexi() returned -1 (parsing error) for UUID with hyphens: %s\n", uuid_str_with_hyphens);
  124. failed_tests++;
  125. } else if (uuid_compare(original_uuid, parsed_uuid) != 0) {
  126. printf("uuid_parse_flexi() parsed value mismatch for UUID with hyphens: %s\n", uuid_str_with_hyphens);
  127. failed_tests++;
  128. }
  129. // Parse the UUID string without hyphens
  130. parse_result = uuid_parse_flexi(uuid_str_without_hyphens, parsed_uuid);
  131. if (parse_result != 0) {
  132. printf("uuid_parse_flexi() returned -1 (parsing error) for UUID without hyphens: %s\n", uuid_str_without_hyphens);
  133. failed_tests++;
  134. }
  135. else if(uuid_compare(original_uuid, parsed_uuid) != 0) {
  136. printf("uuid_parse_flexi() parsed value mismatch for UUID without hyphens: %s\n", uuid_str_without_hyphens);
  137. failed_tests++;
  138. }
  139. if(failed_tests)
  140. break;
  141. }
  142. printf("UUID: failed %d out of %d tests.\n", failed_tests, i);
  143. return failed_tests;
  144. }