/ util / smmstoretool / data.c
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  }