/* * Copyright (c) 2009 Tomasz Moń * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; under version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "preset.h" #include "gdigi.h" #ifndef DOXYGEN_SHOULD_SKIP_THIS enum { PARSER_TYPE_NOT_SET = -1, PARSER_TYPE_PRESET_NAME = 0, PARSER_TYPE_PARAM_ID, PARSER_TYPE_PARAM_POSITION, PARSER_TYPE_PARAM_VALUE, PARSER_TYPE_PARAM_NAME, PARSER_TYPE_PARAM_TEXT, PARSER_TYPE_GENETX_VERSION, PARSER_TYPE_GENETX_TYPE, PARSER_TYPE_GENETX_CHANNEL, PARSER_TYPE_GENETX_NAME, PARSER_TYPE_GENETX_DATA }; enum { SECTION_NOT_SET = -1, SECTION_PARAMS, SECTION_GENETX }; typedef struct { int depth; int id; int section; Preset *preset; } AppData; static void XMLCALL start(void *data, const char *el, const char **attr) { AppData *ad = (AppData *) data; ad->id = PARSER_TYPE_NOT_SET; if (g_strcmp0(el, "Name") == 0) { if (ad->depth == 1) { ad->id = PARSER_TYPE_PRESET_NAME; } else if (ad->depth == 3) { if (ad->section == SECTION_PARAMS) { ad->id = PARSER_TYPE_PARAM_NAME; } else if (ad->section == SECTION_GENETX) { ad->id = PARSER_TYPE_GENETX_NAME; } } } if (g_strcmp0(el, "Params") == 0) { ad->section = SECTION_PARAMS; if (ad->preset->params != NULL) g_warning("Params aleady exists!"); } else if (g_strcmp0(el, "Param") == 0) { SettingParam *param = setting_param_new(); ad->preset->params = g_list_prepend(ad->preset->params, param); } else if (g_strcmp0(el, "ID") == 0) { ad->id = PARSER_TYPE_PARAM_ID; } else if (g_strcmp0(el, "Position") == 0) { ad->id = PARSER_TYPE_PARAM_POSITION; } else if (g_strcmp0(el, "Value") == 0) { ad->id = PARSER_TYPE_PARAM_VALUE; } else if (g_strcmp0(el, "Text") == 0) { ad->id = PARSER_TYPE_PARAM_TEXT; } else if (g_strcmp0(el, "Genetx") == 0) { ad->section = SECTION_GENETX; if (ad->preset->genetxs != NULL) g_warning("Genetx already exists!"); } else if (g_strcmp0(el, "GenetxModel") == 0) { SettingGenetx *genetx = setting_genetx_new(); ad->preset->genetxs = g_list_prepend(ad->preset->genetxs, genetx); } else if (g_strcmp0(el, "Version") == 0) { ad->id = PARSER_TYPE_GENETX_VERSION; } else if (g_strcmp0(el, "Type") == 0) { ad->id = PARSER_TYPE_GENETX_TYPE; } else if (g_strcmp0(el, "Channel") == 0) { ad->id = PARSER_TYPE_GENETX_CHANNEL; } else if (g_strcmp0(el, "Data") == 0) { ad->id = PARSER_TYPE_GENETX_DATA; } ad->depth++; } static void XMLCALL end(void *data, const char *el) { AppData *ad = (AppData *) data; ad->depth--; ad->id = PARSER_TYPE_NOT_SET; } static void XMLCALL text_cb(void *data, const char* text, int len) { AppData *ad = (AppData *) data; if ((ad == NULL) || (ad->preset == NULL)) return; if (ad->id == PARSER_TYPE_PRESET_NAME) { if (ad->preset->name != NULL) g_free(ad->preset->name); ad->preset->name = g_strndup(text, len); } if (ad->section == SECTION_PARAMS) { if (ad->preset->params == NULL) return; SettingParam *param = (SettingParam *) ad->preset->params->data; if (param == NULL) return; gchar *value = g_strndup(text, len); switch (ad->id) { case PARSER_TYPE_PARAM_ID: param->id = atoi(value); break; case PARSER_TYPE_PARAM_POSITION: param->position = atoi(value); break; case PARSER_TYPE_PARAM_VALUE: param->value = atoi(value); break; } g_free(value); } else if (ad->section == SECTION_GENETX) { if (ad->preset->genetxs == NULL) return; SettingGenetx *genetx = (SettingGenetx *) ad->preset->genetxs->data; if (genetx == NULL) return; gchar *value = g_strndup(text, len); switch (ad->id) { case PARSER_TYPE_GENETX_VERSION: if (g_strcmp0(value, "Version1") == 0) { genetx->version = GENETX_VERSION_1; } else if (g_strcmp0(value, "Version2") == 0) { genetx->version = GENETX_VERSION_2; } else { g_warning("Unknown GeNetX version: %s", value); } break; case PARSER_TYPE_GENETX_TYPE: if (g_strcmp0(value, "Amp") == 0) { genetx->type = GENETX_TYPE_AMP; } else if (g_strcmp0(value, "Cabinet") == 0) { genetx->type = GENETX_TYPE_CABINET; } else { g_warning("Unknown GeNetX type: %s", value); } break; case PARSER_TYPE_GENETX_CHANNEL: if (g_strcmp0(value, "Channel1") == 0) { genetx->channel = GENETX_CHANNEL1; } else if (g_strcmp0(value, "Channel2") == 0) { genetx->channel = GENETX_CHANNEL2; } else { g_warning("Unknown GeNetX channel: %s", value); } break; case PARSER_TYPE_GENETX_NAME: /* reassign pointer */ genetx->name = value; value = NULL; break; case PARSER_TYPE_GENETX_DATA: { guchar *data = NULL; gsize length = 0; data = g_base64_decode(value, &length); genetx->data = g_string_new_len((gchar *) data, length); g_free(data); break; } } g_free(value); } } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ /** * \param filename valid path to file * \param error return location for an error * * Tries to open file pointed by path, then parses it. * * \return Preset which must be freed using preset_free, or NULL on error. **/ Preset *create_preset_from_xml_file(gchar *filename, GError **error) { GError *err = NULL; gchar *contents; if (g_file_get_contents(filename, &contents, NULL, &err) == FALSE) { g_warning("Failed to get %s contents: %s", filename, err->message); *error = g_error_copy(err); g_error_free(err); return NULL; } AppData *ad = g_slice_new(AppData); ad->depth = 0; ad->preset = g_slice_new(Preset); ad->preset->name = NULL; ad->preset->params = NULL; ad->preset->genetxs = NULL; ad->id = PARSER_TYPE_NOT_SET; XML_Parser p; p = XML_ParserCreate(NULL); XML_SetUserData(p, (void *) ad); XML_SetElementHandler(p, start, end); XML_SetCharacterDataHandler(p, text_cb); if (XML_Parse(p, contents, strlen(contents), XML_TRUE) != XML_STATUS_OK) { g_set_error(error, 0, 0, "Parse error at line %d:\n%s", (int)XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p))); preset_free(ad->preset); g_slice_free(AppData, ad); g_free(contents); return NULL; } Preset *preset = ad->preset; preset->params = g_list_reverse(preset->params); preset->genetxs = g_list_reverse(preset->genetxs); XML_ParserFree(p); g_slice_free(AppData, ad); g_free(contents); return preset; } gint params_cmp(gconstpointer a, gconstpointer b) { const SettingParam *param_a = a; const SettingParam *param_b = b; if (param_a->position != param_b->position) { return (param_a->position > param_b->position) ? 1 : -1; } if (param_a->id != param_b->id) { return (param_a->id > param_b->id) ? 1 : -1; } return 0; } /** * \param list list containing unpacked preset SysEx messages. * * Parses message * * \return Preset which must be freed using preset_free, or NULL on error. **/ Preset *create_preset_from_data(GList *list) { GString *data; GList *iter; gint total, n, x; gint bank, number, modified; gchar *name; g_return_val_if_fail(list != NULL, NULL); Preset *preset = g_slice_new(Preset); preset->name = NULL; preset->params = NULL; preset->genetxs = NULL; iter = list; for (iter = list; iter; iter = g_list_next(iter)) { data = (GString*) iter->data; switch (get_message_id(data)) { case RECEIVE_PRESET_START: bank = (unsigned char)data->str[8]; number = (unsigned char)data->str[9]; name = g_strdup(&data->str[10]); modified = (unsigned char)data->str[11+strlen(name)]; if ((bank == PRESETS_EDIT_BUFFER) && (number == 0)) { debug_msg(DEBUG_MSG2HOST, "RECEIVE_PRESET_START: current edit buffer"); } else { debug_msg(DEBUG_MSG2HOST, "RECEIVE_PRESET_START: preset %d from bank %d", number, bank); } debug_msg(DEBUG_MSG2HOST, "Name: %s, %sodified", name, modified ? "M" : "Not m"); preset->name = name; break; case RECEIVE_PRESET_PARAMETERS: x = 0x09; n = 0; total = (unsigned char)data->str[x]; x++; do { SettingParam *param = setting_param_new_from_data(&data->str[x], &x); n++; preset->params = g_list_prepend(preset->params, param); if (debug_flag_is_set(DEBUG_MSG2HOST)) { GString *ipv = format_ipv(param->id, param->position, param->value); debug_msg(DEBUG_MSG2HOST, "%3d %s", n, ipv->str); g_string_free(ipv, TRUE); } } while ((x < data->len) && nparams = g_list_sort(preset->params, params_cmp); break; case RECEIVE_PRESET_END: break; default: g_warning("Unhandled message 0x%x in preset messages list", get_message_id(data)); } } return preset; } /** * \param preset preset to be freed * * Frees all memory used by preset. **/ void preset_free(Preset *preset) { g_return_if_fail(preset != NULL); if (preset->params != NULL) { GList *iter; for (iter = preset->params; iter; iter = iter->next) { setting_param_free((SettingParam*)iter->data); } g_list_free(preset->params); } if (preset->genetxs != NULL) { GList *iter; for (iter = preset->genetxs; iter; iter = iter->next) { setting_genetx_free((SettingGenetx*)iter->data); } g_list_free(preset->genetxs); } g_free(preset->name); g_slice_free(Preset, preset); }