mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-05-29 17:38:35 +00:00
138 lines
2.8 KiB
C
138 lines
2.8 KiB
C
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
/*
|
|
* csv.c - CSV parser
|
|
*/
|
|
|
|
#include "shim.h"
|
|
|
|
void NONNULL(1, 3, 4)
|
|
parse_csv_line(char * line, size_t max, size_t *n_columns, const char *columns[])
|
|
{
|
|
char *next = line;
|
|
size_t n = 0, new_n = n;
|
|
const char * const delims = ",";
|
|
char state = 0;
|
|
char *token = NULL;
|
|
|
|
bool valid = true;
|
|
|
|
for (n = 0; n < *n_columns; n++) {
|
|
|
|
if (valid) {
|
|
valid = strntoken(next, max, delims, &token, &state);
|
|
}
|
|
if (valid) {
|
|
next += strlen(token) + 1;
|
|
max -= strlen(token) + 1;
|
|
columns[n] = token;
|
|
new_n = n + 1;
|
|
} else {
|
|
columns[n] = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
*n_columns = new_n;
|
|
}
|
|
|
|
void
|
|
free_csv_list(list_t *list)
|
|
{
|
|
list_t *pos = NULL, *tmp = NULL;
|
|
list_for_each_safe(pos, tmp, list) {
|
|
struct csv_row *row;
|
|
|
|
row = list_entry(pos, struct csv_row, list);
|
|
list_del(&row->list);
|
|
FreePool(row);
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
parse_csv_data(char *data, char *data_end, size_t n_columns, list_t *list)
|
|
{
|
|
EFI_STATUS efi_status = EFI_OUT_OF_RESOURCES;
|
|
char delims[] = "\r\n";
|
|
char *line = data;
|
|
size_t max = 0;
|
|
char *end = data_end;
|
|
|
|
if (!data || !end || end <= data || !n_columns || !list) {
|
|
dprint(L"data:0x%lx end:0x%lx n_columns:%lu list:0x%lx\n",
|
|
data, end, n_columns, list);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
|
|
if (is_utf8_bom(line, max))
|
|
|
|
line += UTF8_BOM_SIZE;
|
|
|
|
while (line <= data_end && *line) {
|
|
size_t entrysz = sizeof(char *) * n_columns + sizeof(struct csv_row);
|
|
struct csv_row *entry;
|
|
size_t m_columns = n_columns;
|
|
char *delim;
|
|
bool found = true;
|
|
bool eof = false;
|
|
|
|
end = data_end;
|
|
max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
|
|
/* Skip the delimiter(s) of the previous line */
|
|
while (max && found) {
|
|
found = false;
|
|
for (delim = &delims[0]; max && *delim; delim++) {
|
|
if (line[0] == *delim) {
|
|
line++;
|
|
max--;
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
/* Find the first delimiter of the current line */
|
|
for (delim = &delims[0]; *delim; delim++) {
|
|
char *tmp = strnchrnul(line, max, *delim);
|
|
if (tmp < end)
|
|
end = tmp;
|
|
}
|
|
max = (uintptr_t)end - (uintptr_t)line + (end > line ? 1 : 0);
|
|
|
|
if (!*end)
|
|
eof = true;
|
|
*end = '\0';
|
|
|
|
if (line == data_end || max == 0) {
|
|
line = end + 1;
|
|
continue;
|
|
}
|
|
|
|
entry = AllocateZeroPool(entrysz);
|
|
if (!entry) {
|
|
efi_status = EFI_OUT_OF_RESOURCES;
|
|
goto err_oom;
|
|
}
|
|
|
|
INIT_LIST_HEAD(&entry->list);
|
|
list_add_tail(&entry->list, list);
|
|
|
|
for (delim = &delims[0]; *delim; delim++) {
|
|
char *tmp = strnchrnul((const char *)line, max, *delim);
|
|
if (tmp < end)
|
|
end = tmp;
|
|
}
|
|
|
|
parse_csv_line(line, max, &m_columns, (const char **)entry->columns);
|
|
entry->n_columns = m_columns;
|
|
if (eof)
|
|
break;
|
|
|
|
line = end + 1;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
err_oom:
|
|
free_csv_list(list);
|
|
return efi_status;
|
|
}
|
|
|
|
// vim:fenc=utf-8:tw=75:noet
|