]> git.proxmox.com Git - efi-boot-shim.git/blame - csv.c
New upstream version 15.4
[efi-boot-shim.git] / csv.c
CommitLineData
031e5cce
SM
1// SPDX-License-Identifier: BSD-2-Clause-Patent
2/*
3 * csv.c - CSV parser
4 */
5
6#include "shim.h"
7
8void NONNULL(1, 3, 4)
9parse_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
36void
37free_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
49EFI_STATUS
50parse_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
8119f718
SM
58 if (!data || !end || end <= data || !n_columns || !list) {
59 dprint(L"data:0x%lx end:0x%lx n_columns:%lu list:0x%lx\n",
60 data, end, n_columns, list);
031e5cce 61 return EFI_INVALID_PARAMETER;
8119f718 62 }
031e5cce
SM
63
64 max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
65
66 if (line && is_utf8_bom(line, max))
67 line += UTF8_BOM_SIZE;
68
69 while (line && line <= data_end) {
70 size_t entrysz = sizeof(char *) * n_columns + sizeof(struct csv_row);
71 struct csv_row *entry;
72 size_t m_columns = n_columns;
73 char *delim;
74 bool found = true;
75
76 end = data_end;
77 max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
78 while (max && found) {
79 found = false;
80 for (delim = &delims[0]; max && *delim; delim++) {
81 if (line[0] == *delim) {
82 line++;
83 max--;
84 found = true;
85 }
86 }
87 }
88 for (delim = &delims[0]; *delim; delim++) {
89 char *tmp = strnchrnul(line, max, *delim);
90 if (tmp < end)
91 end = tmp;
92 }
93 max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
94 *end = '\0';
95
96 if (line == data_end || max == 0) {
97 line = end + 1;
98 continue;
99 }
100
101 entry = AllocateZeroPool(entrysz);
102 if (!entry) {
103 efi_status = EFI_OUT_OF_RESOURCES;
104 goto err_oom;
105 }
106
107 INIT_LIST_HEAD(&entry->list);
108 list_add_tail(&entry->list, list);
109
110 for (delim = &delims[0]; *delim; delim++) {
111 char *tmp = strnchrnul((const char *)line, max, *delim);
112 if (tmp < end)
113 end = tmp;
114 }
115
116 parse_csv_line(line, max, &m_columns, (const char **)entry->columns);
117 entry->n_columns = m_columns;
118 line = end + 1;
119 }
120
121 return EFI_SUCCESS;
122err_oom:
123 free_csv_list(list);
124 return efi_status;
125}
126
127// vim:fenc=utf-8:tw=75:noet