| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| |
| #include "data.h" |
| |
| #include <ctype.h> |
| #include <limits.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "utils.h" |
| |
| void print_data(const uint8_t data[], size_t data_size, enum data_type type) |
| { |
| if (data_size == 0) |
| return; |
| |
| switch (type) { |
| case DATA_TYPE_BOOL: |
| bool value = false; |
| for (size_t i = 0; i < data_size; ++i) { |
| if (data[i] != 0) { |
| value = true; |
| break; |
| } |
| } |
| printf("%s\n", value ? "true" : "false"); |
| break; |
| case DATA_TYPE_UINT8: |
| if (data_size != 1) { |
| fprintf(stderr, |
| "warning: expected size of 1, got %zu\n", |
| data_size); |
| } |
| |
| if (data_size >= 1) |
| printf("%u\n", *(uint8_t *)data); |
| break; |
| case DATA_TYPE_UINT16: |
| if (data_size != 2) { |
| fprintf(stderr, |
| "warning: expected size of 2, got %zu\n", |
| data_size); |
| } |
| |
| if (data_size >= 2) |
| printf("%u\n", *(uint16_t *)data); |
| break; |
| case DATA_TYPE_UINT32: |
| if (data_size != 4) { |
| fprintf(stderr, |
| "warning: expected size of 4, got %zu\n", |
| data_size); |
| } |
| |
| if (data_size >= 4) |
| printf("%u\n", *(uint32_t *)data); |
| break; |
| case DATA_TYPE_UINT64: |
| if (data_size != 8) { |
| fprintf(stderr, |
| "warning: expected size of 8, got %zu\n", |
| data_size); |
| } |
| |
| if (data_size >= 8) |
| printf("%llu\n", (unsigned long long)*(uint64_t *)data); |
| break; |
| case DATA_TYPE_ASCII: |
| for (size_t i = 0; i < data_size; ++i) { |
| char c = data[i]; |
| if (isprint(c)) |
| printf("%c", c); |
| } |
| printf("\n"); |
| break; |
| case DATA_TYPE_UNICODE: |
| char *chars = to_chars((const CHAR16 *)data, data_size); |
| printf("%s\n", chars); |
| free(chars); |
| break; |
| case DATA_TYPE_RAW: |
| fwrite(data, 1, data_size, stdout); |
| break; |
| } |
| } |
| |
| static uint64_t parse_uint(const char source[], |
| const char type[], |
| unsigned long long max, |
| bool *failed) |
| { |
| char *end; |
| unsigned long long uint = strtoull(source, &end, /*base=*/0); |
| if (*end != '\0') { |
| fprintf(stderr, "Trailing characters in \"%s\": %s\n", |
| source, end); |
| *failed = true; |
| return 0; |
| } |
| if (uint > max) { |
| fprintf(stderr, "Invalid %s value: %llu\n", type, uint); |
| *failed = true; |
| return 0; |
| } |
| |
| *failed = false; |
| return uint; |
| } |
| |
| void *make_data(const char source[], size_t *data_size, enum data_type type) |
| { |
| switch (type) { |
| void *data; |
| bool boolean; |
| uint64_t uint; |
| bool failed; |
| |
| case DATA_TYPE_BOOL: |
| if (str_eq(source, "true")) { |
| boolean = true; |
| } else if (str_eq(source, "false")) { |
| boolean = false; |
| } else { |
| fprintf(stderr, "Invalid boolean value: \"%s\"\n", |
| source); |
| return NULL; |
| } |
| |
| *data_size = 1; |
| data = xmalloc(*data_size); |
| *(uint8_t *)data = boolean; |
| return data; |
| case DATA_TYPE_UINT8: |
| uint = parse_uint(source, "uint8", UINT8_MAX, &failed); |
| if (failed) |
| return NULL; |
| |
| *data_size = 1; |
| data = xmalloc(*data_size); |
| *(uint8_t *)data = uint; |
| return data; |
| case DATA_TYPE_UINT16: |
| uint = parse_uint(source, "uint16", UINT16_MAX, &failed); |
| if (failed) |
| return NULL; |
| |
| *data_size = 2; |
| data = xmalloc(*data_size); |
| *(uint16_t *)data = uint; |
| return data; |
| case DATA_TYPE_UINT32: |
| uint = parse_uint(source, "uint32", UINT32_MAX, &failed); |
| if (failed) |
| return NULL; |
| |
| *data_size = 4; |
| data = xmalloc(*data_size); |
| *(uint32_t *)data = uint; |
| return data; |
| case DATA_TYPE_UINT64: |
| uint = parse_uint(source, "uint64", UINT64_MAX, &failed); |
| if (failed) |
| return NULL; |
| |
| *data_size = 8; |
| data = xmalloc(*data_size); |
| *(uint64_t *)data = uint; |
| return data; |
| case DATA_TYPE_ASCII: |
| *data_size = strlen(source) + 1; |
| return strdup(source); |
| case DATA_TYPE_UNICODE: |
| return to_uchars(source, data_size); |
| case DATA_TYPE_RAW: |
| fprintf(stderr, "Raw data type is output only\n"); |
| return NULL; |
| } |
| |
| return NULL; |
| } |
| |
| bool parse_data_type(const char str[], enum data_type *type) |
| { |
| if (str_eq(str, "bool")) |
| *type = DATA_TYPE_BOOL; |
| else if (str_eq(str, "uint8")) |
| *type = DATA_TYPE_UINT8; |
| else if (str_eq(str, "uint16")) |
| *type = DATA_TYPE_UINT16; |
| else if (str_eq(str, "uint32")) |
| *type = DATA_TYPE_UINT32; |
| else if (str_eq(str, "uint64")) |
| *type = DATA_TYPE_UINT64; |
| else if (str_eq(str, "ascii")) |
| *type = DATA_TYPE_ASCII; |
| else if (str_eq(str, "unicode")) |
| *type = DATA_TYPE_UNICODE; |
| else if (str_eq(str, "raw")) |
| *type = DATA_TYPE_RAW; |
| else |
| return false; |
| |
| return true; |
| } |