data.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 3 #include "data.h" 4 5 #include <ctype.h> 6 #include <limits.h> 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include "utils.h" 13 14 void print_data(const uint8_t data[], size_t data_size, enum data_type type) 15 { 16 if (data_size == 0) 17 return; 18 19 switch (type) { 20 case DATA_TYPE_BOOL: 21 bool value = false; 22 for (size_t i = 0; i < data_size; ++i) { 23 if (data[i] != 0) { 24 value = true; 25 break; 26 } 27 } 28 printf("%s\n", value ? "true" : "false"); 29 break; 30 case DATA_TYPE_UINT8: 31 if (data_size != 1) { 32 fprintf(stderr, 33 "warning: expected size of 1, got %zu\n", 34 data_size); 35 } 36 37 if (data_size >= 1) 38 printf("%u\n", *(uint8_t *)data); 39 break; 40 case DATA_TYPE_UINT16: 41 if (data_size != 2) { 42 fprintf(stderr, 43 "warning: expected size of 2, got %zu\n", 44 data_size); 45 } 46 47 if (data_size >= 2) 48 printf("%u\n", *(uint16_t *)data); 49 break; 50 case DATA_TYPE_UINT32: 51 if (data_size != 4) { 52 fprintf(stderr, 53 "warning: expected size of 4, got %zu\n", 54 data_size); 55 } 56 57 if (data_size >= 4) 58 printf("%u\n", *(uint32_t *)data); 59 break; 60 case DATA_TYPE_UINT64: 61 if (data_size != 8) { 62 fprintf(stderr, 63 "warning: expected size of 8, got %zu\n", 64 data_size); 65 } 66 67 if (data_size >= 8) 68 printf("%llu\n", (unsigned long long)*(uint64_t *)data); 69 break; 70 case DATA_TYPE_ASCII: 71 for (size_t i = 0; i < data_size; ++i) { 72 char c = data[i]; 73 if (isprint(c)) 74 printf("%c", c); 75 } 76 printf("\n"); 77 break; 78 case DATA_TYPE_UNICODE: 79 char *chars = to_chars((const CHAR16 *)data, data_size); 80 printf("%s\n", chars); 81 free(chars); 82 break; 83 case DATA_TYPE_RAW: 84 fwrite(data, 1, data_size, stdout); 85 break; 86 } 87 } 88 89 static uint64_t parse_uint(const char source[], 90 const char type[], 91 unsigned long long max, 92 bool *failed) 93 { 94 char *end; 95 unsigned long long uint = strtoull(source, &end, /*base=*/0); 96 if (*end != '\0') { 97 fprintf(stderr, "Trailing characters in \"%s\": %s\n", 98 source, end); 99 *failed = true; 100 return 0; 101 } 102 if (uint > max) { 103 fprintf(stderr, "Invalid %s value: %llu\n", type, uint); 104 *failed = true; 105 return 0; 106 } 107 108 *failed = false; 109 return uint; 110 } 111 112 void *make_data(const char source[], size_t *data_size, enum data_type type) 113 { 114 switch (type) { 115 void *data; 116 bool boolean; 117 uint64_t uint; 118 bool failed; 119 120 case DATA_TYPE_BOOL: 121 if (str_eq(source, "true")) { 122 boolean = true; 123 } else if (str_eq(source, "false")) { 124 boolean = false; 125 } else { 126 fprintf(stderr, "Invalid boolean value: \"%s\"\n", 127 source); 128 return NULL; 129 } 130 131 *data_size = 1; 132 data = xmalloc(*data_size); 133 *(uint8_t *)data = boolean; 134 return data; 135 case DATA_TYPE_UINT8: 136 uint = parse_uint(source, "uint8", UINT8_MAX, &failed); 137 if (failed) 138 return NULL; 139 140 *data_size = 1; 141 data = xmalloc(*data_size); 142 *(uint8_t *)data = uint; 143 return data; 144 case DATA_TYPE_UINT16: 145 uint = parse_uint(source, "uint16", UINT16_MAX, &failed); 146 if (failed) 147 return NULL; 148 149 *data_size = 2; 150 data = xmalloc(*data_size); 151 *(uint16_t *)data = uint; 152 return data; 153 case DATA_TYPE_UINT32: 154 uint = parse_uint(source, "uint32", UINT32_MAX, &failed); 155 if (failed) 156 return NULL; 157 158 *data_size = 4; 159 data = xmalloc(*data_size); 160 *(uint32_t *)data = uint; 161 return data; 162 case DATA_TYPE_UINT64: 163 uint = parse_uint(source, "uint64", UINT64_MAX, &failed); 164 if (failed) 165 return NULL; 166 167 *data_size = 8; 168 data = xmalloc(*data_size); 169 *(uint64_t *)data = uint; 170 return data; 171 case DATA_TYPE_ASCII: 172 *data_size = strlen(source) + 1; 173 return strdup(source); 174 case DATA_TYPE_UNICODE: 175 return to_uchars(source, data_size); 176 case DATA_TYPE_RAW: 177 fprintf(stderr, "Raw data type is output only\n"); 178 return NULL; 179 } 180 181 return NULL; 182 } 183 184 bool parse_data_type(const char str[], enum data_type *type) 185 { 186 if (str_eq(str, "bool")) 187 *type = DATA_TYPE_BOOL; 188 else if (str_eq(str, "uint8")) 189 *type = DATA_TYPE_UINT8; 190 else if (str_eq(str, "uint16")) 191 *type = DATA_TYPE_UINT16; 192 else if (str_eq(str, "uint32")) 193 *type = DATA_TYPE_UINT32; 194 else if (str_eq(str, "uint64")) 195 *type = DATA_TYPE_UINT64; 196 else if (str_eq(str, "ascii")) 197 *type = DATA_TYPE_ASCII; 198 else if (str_eq(str, "unicode")) 199 *type = DATA_TYPE_UNICODE; 200 else if (str_eq(str, "raw")) 201 *type = DATA_TYPE_RAW; 202 else 203 return false; 204 205 return true; 206 }