#include #include #include #include #include namespace rack { namespace plugin { Plugin::~Plugin() { for (Model* model : models) { delete model; } } void Plugin::addModel(Model* model) { // Check that the model is not added to a plugin already assert(!model->plugin); model->plugin = this; models.push_back(model); } Model* Plugin::getModel(std::string slug) { slug = normalizeSlug(slug); for (Model* model : models) { if (model->slug == slug) { return model; } } return NULL; } void Plugin::fromJson(json_t* rootJ) { // Slug json_t* slugJ = json_object_get(rootJ, "slug"); if (slugJ) slug = json_string_value(slugJ); if (slug == "") throw UserException("No plugin slug"); if (!isSlugValid(slug)) throw UserException(string::f("Plugin slug \"%s\" is invalid", slug.c_str())); // Version json_t* versionJ = json_object_get(rootJ, "version"); if (versionJ) version = json_string_value(versionJ); if (!string::startsWith(version, app::ABI_VERSION + ".")) throw UserException(string::f("Plugin version %s does not match Rack ABI version %s", version.c_str(), app::ABI_VERSION.c_str())); if (version == "") throw UserException("No plugin version"); // Name json_t* nameJ = json_object_get(rootJ, "name"); if (nameJ) name = json_string_value(nameJ); if (name == "") throw UserException("No plugin name"); // Brand json_t* brandJ = json_object_get(rootJ, "brand"); if (brandJ) brand = json_string_value(brandJ); // Use name for brand name by default if (brand == "") brand = name; json_t* authorJ = json_object_get(rootJ, "author"); if (authorJ) author = json_string_value(authorJ); json_t* licenseJ = json_object_get(rootJ, "license"); if (licenseJ) license = json_string_value(licenseJ); json_t* authorEmailJ = json_object_get(rootJ, "authorEmail"); if (authorEmailJ) authorEmail = json_string_value(authorEmailJ); json_t* pluginUrlJ = json_object_get(rootJ, "pluginUrl"); if (pluginUrlJ) pluginUrl = json_string_value(pluginUrlJ); json_t* authorUrlJ = json_object_get(rootJ, "authorUrl"); if (authorUrlJ) authorUrl = json_string_value(authorUrlJ); json_t* manualUrlJ = json_object_get(rootJ, "manualUrl"); if (manualUrlJ) manualUrl = json_string_value(manualUrlJ); json_t* sourceUrlJ = json_object_get(rootJ, "sourceUrl"); if (sourceUrlJ) sourceUrl = json_string_value(sourceUrlJ); json_t* donateUrlJ = json_object_get(rootJ, "donateUrl"); if (donateUrlJ) donateUrl = json_string_value(donateUrlJ); json_t* modulesJ = json_object_get(rootJ, "modules"); if (modulesJ) { size_t moduleId; json_t* moduleJ; json_array_foreach(modulesJ, moduleId, moduleJ) { // Check if module is disabled json_t* disabledJ = json_object_get(moduleJ, "disabled"); if (disabledJ) { if (json_boolean_value(disabledJ)) continue; } // Get model slug json_t* modelSlugJ = json_object_get(moduleJ, "slug"); if (!modelSlugJ) { throw UserException(string::f("No slug found for module entry %d", moduleId)); } std::string modelSlug = json_string_value(modelSlugJ); // Check model slug if (!isSlugValid(modelSlug)) { throw UserException(string::f("Module slug \"%s\" is invalid", modelSlug.c_str())); } // Get model Model* model = getModel(modelSlug); if (!model) { throw UserException(string::f("Manifest contains module %s but it is not defined in the plugin", modelSlug.c_str())); } model->fromJson(moduleJ); } } // Remove models without names // This is a hacky way of matching JSON models with C++ models. for (auto it = models.begin(); it != models.end();) { Model* model = *it; if (model->name == "") { it = models.erase(it); delete model; continue; } it++; } } } // namespace plugin } // namespace rack