1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 23 дек. 2017 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <ui/ctl/ctl.h> 23 24 namespace lsp 25 { 26 namespace ctl 27 { 28 typedef struct file_format_t 29 { 30 const char *id; 31 const char *filter; 32 const char *text; 33 const char *ext; 34 size_t flags; 35 } file_format_t; 36 37 static const file_format_t file_formats[] = 38 { 39 { "wav", "*.wav", "files.audio.wave", ".wav", LSPFileMask::NONE }, 40 { "lspc", "*.lspc", "files.config.lspc", ".lspc", LSPFileMask::NONE }, 41 { "cfg", "*.cfg", "files.config.lsp", ".cfg", LSPFileMask::NONE }, 42 { "audio", "*.wav", "files.audio.supported", ".wav", LSPFileMask::NONE }, 43 { "audio_lspc", "*.wav|*.lspc", "files.audio.audio_lspc", ".wav", LSPFileMask::NONE }, 44 { "obj3d", "*.obj", "files.3d.wavefont", ".obj", LSPFileMask::NONE }, 45 { "all", "*", "files.all", "", LSPFileMask::NONE }, 46 { NULL, NULL, NULL, 0 } 47 }; 48 add_format(LSPFileFilter * flt,const char * variable,size_t n)49 void add_format(LSPFileFilter *flt, const char *variable, size_t n) 50 { 51 for (const file_format_t *f = file_formats; f->id != NULL; ++f) 52 { 53 if (!strncasecmp(f->id, variable, n)) 54 { 55 LSPFileFilterItem ffi; 56 ffi.pattern()->set(f->filter, f->flags); 57 ffi.title()->set(f->text); 58 ffi.set_extension(f->ext); 59 60 flt->add(&ffi); 61 return; 62 } 63 } 64 } 65 parse_file_formats(const char * variable,LSPFileFilter * flt)66 bool parse_file_formats(const char *variable, LSPFileFilter *flt) 67 { 68 status_t res = flt->clear(); 69 if (res != STATUS_OK) 70 return res; 71 72 while (true) 73 { 74 while (*variable == ' ') 75 variable ++; 76 if (*variable == '\0') 77 break; 78 79 const char *s = strchr(variable, ','); 80 const char *end = (s == NULL) ? strchr(variable, '\0') : s; 81 while ((end > variable) && (end[-1] == ' ')) 82 --end; 83 84 if (end > variable) 85 add_format(flt, variable, end - variable); 86 87 if (s == NULL) 88 break; 89 variable = s + 1; 90 } 91 92 return true; 93 } 94 parse_relative_path(io::Path * path,const io::Path * base,const char * value,size_t len)95 bool parse_relative_path(io::Path *path, const io::Path *base, const char *value, size_t len) 96 { 97 if ((base == NULL) || (len <= 0)) 98 return false; 99 100 LSPString svalue; 101 if (!svalue.set_utf8(value, len)) 102 return false; 103 104 if (svalue.starts_with_ascii("builtin://")) 105 return path->set(&svalue) == STATUS_OK; 106 107 // This method won't accept absolute path stored in svalue 108 if (path->set(base, &svalue) != STATUS_OK) 109 return false; 110 111 return (path->canonicalize() == STATUS_OK); 112 } 113 set_port_value(CtlPort * up,const char * value,size_t flags,const io::Path * base)114 bool set_port_value(CtlPort *up, const char *value, size_t flags, const io::Path *base) 115 { 116 if (up == NULL) 117 return false; 118 119 // Get metadata 120 const port_t *p = up->metadata(); 121 if (p == NULL) 122 return false; 123 124 // Check that it's a control port 125 if (!IS_IN_PORT(p)) 126 return false; 127 128 // Apply changes 129 switch (p->role) 130 { 131 case R_PORT_SET: 132 case R_CONTROL: 133 { 134 if (is_discrete_unit(p->unit)) 135 { 136 if (p->unit == U_BOOL) 137 { 138 PARSE_BOOL(value, up->set_value(__, flags); ); 139 } 140 else 141 { 142 PARSE_INT(value, up->set_value(__, flags); ); 143 } 144 } 145 else 146 { 147 PARSE_FLOAT(value, up->set_value(__, flags); ); 148 } 149 break; 150 } 151 case R_PATH: 152 { 153 size_t len = ::strlen(value); 154 io::Path path; 155 156 if (parse_relative_path(&path, base, value, len)) 157 { 158 // Update value and it's length 159 value = path.as_utf8(); 160 len = strlen(value); 161 } 162 163 up->write(value, len, flags); 164 break; 165 } 166 default: 167 return false; 168 } 169 return true; 170 } 171 format_relative_path(LSPString * value,const char * path,const io::Path * base)172 bool format_relative_path(LSPString *value, const char *path, const io::Path *base) 173 { 174 if (base == NULL) 175 return false; 176 177 io::Path xpath; 178 if (xpath.set(path) != STATUS_OK) 179 return false; 180 if (xpath.as_relative(base) != STATUS_OK) 181 return false; 182 183 return value->append(xpath.as_string()); 184 } 185 format_port_value(CtlPort * up,LSPString * name,LSPString * value,LSPString * comment,int * flags,const io::Path * base)186 status_t format_port_value(CtlPort *up, LSPString *name, LSPString *value, LSPString *comment, int *flags, const io::Path *base) 187 { 188 // Get metadata 189 const port_t *p = up->metadata(); 190 if (p == NULL) 191 return STATUS_OK; 192 193 switch (p->role) 194 { 195 case R_PORT_SET: 196 case R_CONTROL: 197 { 198 // Serialize meta information 199 const char *unit = encode_unit(p->unit); 200 if (unit != NULL) 201 LSP_BOOL_ASSERT(comment->fmt_append_utf8("%s [%s]", p->name, unit), STATUS_NO_MEM) 202 else if (p->unit == U_BOOL) 203 LSP_BOOL_ASSERT(comment->fmt_append_utf8("%s [boolean]", p->name), STATUS_NO_MEM) 204 else 205 LSP_BOOL_ASSERT(comment->append_utf8(p->name), STATUS_NO_MEM); 206 207 if ((p->flags & (F_LOWER | F_UPPER)) || (p->unit == U_ENUM) || (p->unit == U_BOOL)) 208 { 209 if (is_discrete_unit(p->unit) || (p->flags & F_INT)) 210 { 211 if (p->unit != U_BOOL) 212 { 213 if (p->unit == U_ENUM) 214 { 215 int value = p->min + list_size(p->items) - 1; 216 LSP_BOOL_ASSERT(comment->fmt_append_utf8(": %d..%d", int(p->min), int(value)), STATUS_NO_MEM); 217 } 218 else 219 LSP_BOOL_ASSERT(comment->fmt_append_utf8(": %d..%d", int(p->min), int(p->max)), STATUS_NO_MEM); 220 } 221 else 222 LSP_BOOL_ASSERT(comment->append_utf8(": true/false"), STATUS_NO_MEM); 223 } 224 else if (!(p->flags & F_EXT)) 225 { 226 LSP_BOOL_ASSERT(comment->fmt_append_utf8(": %.8f..%.8f", p->min, p->max), STATUS_NO_MEM); 227 } 228 else 229 { 230 LSP_BOOL_ASSERT(comment->fmt_append_utf8(": %.12f..%.12f", p->min, p->max), STATUS_NO_MEM); 231 } 232 } 233 234 // Describe enum 235 if ((p->unit == U_ENUM) && (p->items != NULL)) 236 { 237 int value = p->min; 238 for (const port_item_t *item = p->items; item->text != NULL; ++item) 239 LSP_BOOL_ASSERT(comment->fmt_append_utf8("\n %d: %s", value++, item->text), STATUS_NO_MEM); 240 } 241 242 // Serialize name 243 LSP_BOOL_ASSERT(name->append_utf8(p->id), STATUS_NO_MEM); 244 245 // Serialize value 246 float v = up->get_value(); 247 if (is_discrete_unit(p->unit) || (p->flags & F_INT)) 248 { 249 if (p->unit == U_BOOL) 250 LSP_BOOL_ASSERT(value->append_utf8((v >= 0.5f) ? "true" : "false"), STATUS_NO_MEM) 251 else 252 LSP_BOOL_ASSERT(value->fmt_utf8("%d", int(v)), STATUS_NO_MEM); 253 } 254 else if (!(p->flags & F_EXT)) 255 { 256 LSP_BOOL_ASSERT(value->fmt_utf8("%.8f", v), STATUS_NO_MEM); 257 } 258 else 259 { 260 LSP_BOOL_ASSERT(value->fmt_utf8("%.12f", v), STATUS_NO_MEM); 261 } 262 263 // No flags 264 *flags = 0; 265 break; 266 } 267 case R_PATH: 268 { 269 LSP_BOOL_ASSERT(comment->fmt_append_utf8("%s [pathname]", p->name), STATUS_NO_MEM); 270 LSP_BOOL_ASSERT(name->append_utf8(p->id), STATUS_NO_MEM); 271 272 const char *path = up->get_buffer<const char>(); 273 if ((path != NULL) && (strlen(path) > 0)) 274 { 275 if (!format_relative_path(value, path, base)) 276 { 277 LSP_BOOL_ASSERT(value->append_utf8(path), STATUS_NO_MEM) 278 } 279 } 280 else 281 LSP_BOOL_ASSERT(value->append_utf8(""), STATUS_NO_MEM); 282 283 // No flags 284 *flags = config::SF_QUOTED; 285 break; 286 } 287 default: 288 return STATUS_BAD_TYPE; 289 } 290 return STATUS_OK; 291 } 292 } 293 } 294 295