]> git.proxmox.com Git - efi-boot-shim.git/blob - csv.c
d141f03543e5b2e0310aaf1fcbe17ccb60679f7e
[efi-boot-shim.git] / csv.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 /*
3 * csv.c - CSV parser
4 */
5
6 #include "shim.h"
7
8 void NONNULL(1, 3, 4)
9 parse_csv_line(char * line, size_t max, size_t *n_columns, const char *columns[])
10 {
11 char *next = line;
12 size_t n = 0, new_n = n;
13 const char * const delims = ",";
14 char state = 0;
15 char *token = NULL;
16
17 bool valid = true;
18 for (n = 0; n < *n_columns; n++) {
19
20 if (valid) {
21 valid = strntoken(next, max, delims, &token, &state);
22 }
23 if (valid) {
24 next += strlen(token) + 1;
25 max -= strlen(token) + 1;
26 columns[n] = token;
27 new_n = n + 1;
28 } else {
29 columns[n] = NULL;
30 continue;
31 }
32 }
33 *n_columns = new_n;
34 }
35
36 void
37 free_csv_list(list_t *list)
38 {
39 list_t *pos = NULL, *tmp = NULL;
40 list_for_each_safe(pos, tmp, list) {
41 struct csv_row *row;
42
43 row = list_entry(pos, struct csv_row, list);
44 list_del(&row->list);
45 FreePool(row);
46 }
47 }
48
49 EFI_STATUS
50 parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
51 {
52 EFI_STATUS efi_status = EFI_OUT_OF_RESOURCES;
53 char delims[] = "\r\n";
54 char *line = data;
55 size_t max = 0;
56 char *end = data_end;
57
58 if (!data || !end || end <= data || !n_columns || !list)
59 return EFI_INVALID_PARAMETER;
60
61 max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
62
63 if (line && is_utf8_bom(line, max))
64 line += UTF8_BOM_SIZE;
65
66 while (line && line <= data_end) {
67 size_t entrysz = sizeof(char *) * n_columns + sizeof(struct csv_row);
68 struct csv_row *entry;
69 size_t m_columns = n_columns;
70 char *delim;
71 bool found = true;
72
73 end = data_end;
74 max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
75 while (max && found) {
76 found = false;
77 for (delim = &delims[0]; max && *delim; delim++) {
78 if (line[0] == *delim) {
79 line++;
80 max--;
81 found = true;
82 }
83 }
84 }
85 for (delim = &delims[0]; *delim; delim++) {
86 char *tmp = strnchrnul(line, max, *delim);
87 if (tmp < end)
88 end = tmp;
89 }
90 max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
91 *end = '\0';
92
93 if (line == data_end || max == 0) {
94 line = end + 1;
95 continue;
96 }
97
98 entry = AllocateZeroPool(entrysz);
99 if (!entry) {
100 efi_status = EFI_OUT_OF_RESOURCES;
101 goto err_oom;
102 }
103
104 INIT_LIST_HEAD(&entry->list);
105 list_add_tail(&entry->list, list);
106
107 for (delim = &delims[0]; *delim; delim++) {
108 char *tmp = strnchrnul((const char *)line, max, *delim);
109 if (tmp < end)
110 end = tmp;
111 }
112
113 parse_csv_line(line, max, &m_columns, (const char **)entry->columns);
114 entry->n_columns = m_columns;
115 line = end + 1;
116 }
117
118 return EFI_SUCCESS;
119 err_oom:
120 free_csv_list(list);
121 return efi_status;
122 }
123
124 // vim:fenc=utf-8:tw=75:noet