/** * SPDX-FileCopyrightText: Copyright (C) 2024 ZeldaRET * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include "xml.h" #include "samplebank.h" #include "util.h" const char * samplebank_path_forname(samplebank *sb, const char *name) { assert(name != NULL); for (size_t i = 0; i < sb->num_samples; i++) { if (strequ(sb->sample_names[i], name)) return sb->sample_paths[i]; } return NULL; } typedef struct { const char *name; const char *path; } samplebank_xml_entry; void read_samplebank_xml(samplebank *sb, xmlDocPtr doc) { // XML Example: // // // // static const xml_attr_spec header_spec = { {"Name", false, xml_parse_c_identifier, offsetof(samplebank, name) }, { "Index", false, xml_parse_int, offsetof(samplebank, index) }, { "Medium", false, xml_parse_c_identifier, offsetof(samplebank, medium) }, { "CachePolicy", false, xml_parse_c_identifier, offsetof(samplebank, cache_policy)}, { "BufferBug", true, xml_parse_bool, offsetof(samplebank, buffer_bug) }, }; static const xml_attr_spec entry_spec = { {"Name", false, xml_parse_c_identifier, offsetof(samplebank_xml_entry, name)}, { "Path", false, xml_parse_string, offsetof(samplebank_xml_entry, path)}, }; xmlNodePtr root = xmlDocGetRootElement(doc); if (!strequ(XMLSTR_TO_STR(root->name), "SampleBank")) error("Root node must be "); sb->buffer_bug = false; xml_parse_node_by_spec(sb, root, header_spec, ARRAY_COUNT(header_spec)); if (root->children == NULL) error("Missing samples list"); size_t entries_cap = 8; size_t entries_len = 0; sb->sample_names = malloc(entries_cap * sizeof(const char *)); sb->sample_paths = malloc(entries_cap * sizeof(const char *)); sb->is_sample = malloc(entries_cap * sizeof(bool)); size_t pointers_cap = 4; size_t pointers_len = 0; sb->pointer_indices = malloc(pointers_cap * sizeof(int)); LL_FOREACH(xmlNodePtr, node, root->children) { if (node->type != XML_ELEMENT_NODE) continue; if (node->children != NULL) { xmlNodePtr first_child = node->children; const char *child_name = XMLSTR_TO_STR(first_child->name); error("Unexpected child node(s) (first is %s) in samples list (line %d)", child_name, first_child->line); } const char *node_name = XMLSTR_TO_STR(node->name); bool is_sample; if (strequ(node_name, "Sample")) { is_sample = true; } else if (strequ(node_name, "Blob")) { is_sample = false; } else if (strequ(node_name, "Pointer")) { // pointer entry int ptr_index; xml_get_single_property(&ptr_index, node, "Index", xml_parse_int); if (pointers_len == pointers_cap) { pointers_cap *= 2; sb->pointer_indices = realloc(sb->pointer_indices, pointers_cap * sizeof(int)); } sb->pointer_indices[pointers_len++] = ptr_index; continue; } else { error("Unexpected element node %s in samples list (line %d)", node_name, node->line); } samplebank_xml_entry ent; xml_parse_node_by_spec(&ent, node, entry_spec, ARRAY_COUNT(entry_spec)); if (entries_len == entries_cap) { entries_cap *= 2; sb->sample_names = realloc(sb->sample_names, entries_cap * sizeof(const char *)); sb->sample_paths = realloc(sb->sample_paths, entries_cap * sizeof(const char *)); sb->is_sample = realloc(sb->is_sample, entries_cap * sizeof(bool)); } sb->sample_names[entries_len] = ent.name; sb->sample_paths[entries_len] = ent.path; sb->is_sample[entries_len] = is_sample; entries_len++; } sb->num_samples = entries_len; sb->num_pointers = pointers_len; }