Merge branch 'stable' into 'main'
[ladish.git] / daemon / room_load.c
blobde00a3abd99dc0d01962707312921eb235b33e36
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2010,2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains the parts of room object implementation
9 * that are related to project load functionality
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <expat.h>
34 #include "room_internal.h"
35 #include "../common/catdup.h"
36 #include "load.h"
37 #include "../proxies/notify_proxy.h"
38 #include "escape.h"
39 #include "studio.h"
40 #include "recent_projects.h"
42 #define context_ptr ((struct ladish_parse_context *)data)
43 #define room_ptr ((struct ladish_room *)context_ptr->room)
45 static void callback_chrdata(void * data, const XML_Char * s, int len)
47 if (context_ptr->error)
49 return;
52 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER ||
53 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY ||
54 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION ||
55 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_DESCRIPTION ||
56 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_NOTES)
58 if ((size_t)(context_ptr->data_used + len) >= sizeof(context_ptr->data))
60 log_error("xml parse max char data length reached");
61 context_ptr->error = XML_TRUE;
62 return;
65 memcpy(context_ptr->data + context_ptr->data_used, s, len);
66 context_ptr->data_used += len;
70 static void callback_elstart(void * data, const char * el, const char ** attr)
72 const char * name;
73 const char * level;
74 char * name_dup;
75 const char * uuid_str;
76 uuid_t uuid;
77 const char * uuid2_str;
78 uuid_t uuid2;
79 ladish_port_handle port1;
80 ladish_port_handle port2;
81 uint32_t port_type;
82 uint32_t port_flags;
83 size_t len;
85 name_dup = NULL;
87 if (context_ptr->error)
89 goto free;
92 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
94 log_error("xml parse max stack depth reached");
95 context_ptr->error = XML_TRUE;
96 goto free;
99 if (strcmp(el, "project") == 0)
101 //log_info("<project>");
102 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PROJECT;
104 if (!ladish_get_name_and_uuid_attributes("/project", attr, &name, &uuid_str, uuid))
106 context_ptr->error = XML_TRUE;
107 goto free;
110 len = strlen(name) + 1;
111 room_ptr->project_name = malloc(len);
112 if (room_ptr->project_name == NULL)
114 log_error("malloc() failed for project name with length %zu", len);
115 context_ptr->error = XML_TRUE;
116 goto free;
119 unescape(name, len, room_ptr->project_name);
121 log_info("Project '%s' with uuid %s", room_ptr->project_name, uuid_str);
123 uuid_copy(room_ptr->project_uuid, uuid);
125 goto free;
128 if (strcmp(el, "description") == 0)
130 //log_info("<description>");
132 if (room_ptr->project_description != NULL)
134 log_error("project description is already set");
135 context_ptr->error = XML_TRUE;
136 goto free;
139 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DESCRIPTION;
140 context_ptr->data_used = 0;
141 goto free;
144 if (strcmp(el, "notes") == 0)
146 //log_info("<notes>");
148 if (room_ptr->project_notes != NULL)
150 log_error("project notes are already set");
151 context_ptr->error = XML_TRUE;
152 goto free;
155 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_NOTES;
156 context_ptr->data_used = 0;
157 goto free;
160 if (strcmp(el, "jack") == 0)
162 //log_info("<jack>");
163 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
164 goto free;
167 if (strcmp(el, "clients") == 0)
169 //log_info("<clients>");
170 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENTS;
171 goto free;
174 if (strcmp(el, "room") == 0)
176 //log_info("<room>");
177 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ROOM;
178 goto free;
181 if (strcmp(el, "client") == 0)
183 //log_info("<client>");
184 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENT;
185 if (context_ptr->client != NULL)
187 log_error("nested clients");
188 context_ptr->error = XML_TRUE;
189 goto free;
192 if (context_ptr->depth == 3 &&
193 context_ptr->element[0] == PARSE_CONTEXT_PROJECT &&
194 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
195 context_ptr->element[2] == PARSE_CONTEXT_CLIENTS)
197 if (!ladish_get_name_and_uuid_attributes("/project/jack/clients/client", attr, &name, &uuid_str, uuid))
199 context_ptr->error = XML_TRUE;
200 goto free;
203 name_dup = unescape_dup(name);
204 if (name_dup == NULL)
206 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
207 context_ptr->error = XML_TRUE;
208 goto free;
211 log_info("jack client \"%s\" with uuid %s", name_dup, uuid_str);
213 context_ptr->client = ladish_graph_find_client_by_uuid(ladish_studio_get_jack_graph(), uuid);
214 if (context_ptr->client != NULL)
216 log_info("Found existing client");
217 goto free;
220 if (!ladish_client_create(uuid, &context_ptr->client))
222 log_error("ladish_client_create() failed.");
223 context_ptr->error = XML_TRUE;
224 ASSERT(context_ptr->client == NULL);
225 goto free;
228 if (ladish_get_uuid_attribute(attr, "app", context_ptr->uuid, true))
230 ladish_client_set_app(context_ptr->client, context_ptr->uuid);
233 if (!ladish_graph_add_client(ladish_studio_get_jack_graph(), context_ptr->client, name_dup, true))
235 log_error("ladish_graph_add_client() failed to add client '%s' to JACK graph", name_dup);
236 context_ptr->error = XML_TRUE;
237 ladish_client_destroy(context_ptr->client);
238 context_ptr->client = NULL;
241 goto free;
244 if (context_ptr->depth == 2 &&
245 context_ptr->element[0] == PARSE_CONTEXT_PROJECT &&
246 context_ptr->element[1] == PARSE_CONTEXT_CLIENTS)
248 if (!ladish_get_name_and_uuid_attributes("/room/clients/client", attr, &name, &uuid_str, uuid))
250 context_ptr->error = XML_TRUE;
251 goto free;
254 name_dup = unescape_dup(name);
255 if (name_dup == NULL)
257 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
258 context_ptr->error = XML_TRUE;
259 goto free;
262 log_info("room client \"%s\" with uuid %s", name_dup, uuid_str);
264 context_ptr->client = ladish_graph_find_client_by_uuid(room_ptr->graph, uuid);
265 if (context_ptr->client != NULL)
267 log_info("Found existing client");
268 goto free;
271 if (!ladish_client_create(uuid, &context_ptr->client))
273 log_error("ladish_client_create() failed.");
274 context_ptr->error = XML_TRUE;
275 ASSERT(context_ptr->client == NULL);
276 goto free;
279 if (!ladish_graph_add_client(room_ptr->graph, context_ptr->client, name_dup, true))
281 log_error("ladish_graph_add_client() failed to add client '%s' to room graph", name_dup);
282 context_ptr->error = XML_TRUE;
283 ladish_client_destroy(context_ptr->client);
284 context_ptr->client = NULL;
287 goto free;
290 log_error("client element in wrong place");
291 ladish_dump_element_stack(context_ptr);
292 context_ptr->error = XML_TRUE;
293 goto free;
296 if (strcmp(el, "ports") == 0)
298 //log_info("<ports>");
299 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORTS;
300 goto free;
303 if (strcmp(el, "port") == 0)
305 //log_info("<port>");
306 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORT;
308 if (context_ptr->port != NULL)
310 log_error("nested ports");
311 context_ptr->error = XML_TRUE;
312 goto free;
315 if (context_ptr->depth >= 3 &&
316 context_ptr->element[context_ptr->depth - 3] == PARSE_CONTEXT_CLIENTS &&
317 context_ptr->element[context_ptr->depth - 2] == PARSE_CONTEXT_CLIENT &&
318 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORTS)
320 //log_info("client port");
321 if (context_ptr->client == NULL)
323 log_error("client-less port");
324 context_ptr->error = XML_TRUE;
325 goto free;
328 if (context_ptr->depth == 5 && context_ptr->element[0] == PARSE_CONTEXT_PROJECT && context_ptr->element[1] == PARSE_CONTEXT_JACK)
330 if (!ladish_get_name_and_uuid_attributes("/project/jack/clients/client/ports/port", attr, &name, &uuid_str, uuid))
332 context_ptr->error = XML_TRUE;
333 goto free;
336 name_dup = unescape_dup(name);
337 if (name_dup == NULL)
339 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
340 context_ptr->error = XML_TRUE;
341 goto free;
344 log_info("jack port \"%s\" with uuid %s", name_dup, uuid_str);
346 if (!ladish_port_create(uuid, false, &context_ptr->port))
348 log_error("ladish_port_create() failed.");
349 goto free;
352 ladish_port_set_vgraph(context_ptr->port, room_ptr->graph);
354 if (!ladish_graph_add_port(ladish_studio_get_jack_graph(), context_ptr->client, context_ptr->port, name_dup, 0, 0, true))
356 log_error("ladish_graph_add_port() failed.");
357 ladish_port_destroy(context_ptr->port);
358 context_ptr->port = NULL;
361 goto free;
363 else if (context_ptr->depth == 4 && context_ptr->element[0] == PARSE_CONTEXT_PROJECT)
365 if (!ladish_get_name_and_uuid_attributes("/project/clients/client/ports/port", attr, &name, &uuid_str, uuid))
367 context_ptr->error = XML_TRUE;
368 goto free;
371 name_dup = unescape_dup(name);
372 if (name_dup == NULL)
374 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
375 context_ptr->error = XML_TRUE;
376 goto free;
379 context_ptr->port = ladish_graph_find_port_by_uuid(room_ptr->graph, uuid, false, NULL);
380 if (context_ptr->port != NULL)
382 if (!ladish_port_is_link(context_ptr->port))
384 log_info("port \"%s\" with uuid %s already exists in room graph and is not a room-studio link", name_dup, uuid_str);
385 context_ptr->error = XML_TRUE;
387 goto free;
390 /* there can be two ports with same uuid in the jack graph so we search for a port
391 with vgraph for the room where porject is being loaded to */
392 context_ptr->port = ladish_graph_find_port_by_uuid(ladish_studio_get_jack_graph(), uuid, false, room_ptr->graph);
393 if (context_ptr->port == NULL)
395 log_error("app port \"%s\" with uuid %s not found in the jack graph", name_dup, uuid_str);
396 context_ptr->error = XML_TRUE;
397 ladish_graph_dump(ladish_studio_get_jack_graph());
398 goto free;
401 log_info("app port \"%s\" with uuid %s", name_dup, uuid_str);
403 if (!ladish_graph_add_port(room_ptr->graph, context_ptr->client, context_ptr->port, name_dup, 0, 0, true))
405 log_error("ladish_graph_add_port() failed.");
406 ladish_port_destroy(context_ptr->port);
407 context_ptr->port = NULL;
408 goto free;
411 goto free;
414 else if (context_ptr->depth == 2 &&
415 context_ptr->element[0] == PARSE_CONTEXT_PROJECT &&
416 context_ptr->element[1] == PARSE_CONTEXT_ROOM)
418 ASSERT(context_ptr->room != NULL);
419 //log_info("room port");
421 if (!ladish_get_name_and_uuid_attributes("/project/room/port", attr, &name, &uuid_str, uuid))
423 context_ptr->error = XML_TRUE;
424 goto free;
427 name_dup = unescape_dup(name);
428 if (name_dup == NULL)
430 log_error("allocation of memory for unescaped name buffer failed. name = '%s'", name);
431 context_ptr->error = XML_TRUE;
432 goto free;
435 log_info("room port \"%s\" with uuid %s", name_dup, uuid_str);
437 if (!ladish_parse_port_type_and_direction_attributes("/project/room/port", attr, &port_type, &port_flags))
439 context_ptr->error = XML_TRUE;
440 goto free;
443 context_ptr->port = ladish_graph_find_port_by_uuid(room_ptr->graph, uuid, false, NULL);
444 if (context_ptr->port == NULL)
446 log_error("Cannot find room link port.");
447 context_ptr->error = XML_TRUE;
450 goto free;
453 log_error("port element in wrong place");
454 ladish_dump_element_stack(context_ptr);
455 context_ptr->error = XML_TRUE;
457 goto free;
460 if (strcmp(el, "connections") == 0)
462 //log_info("<connections>");
463 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTIONS;
464 goto free;
467 if (strcmp(el, "connection") == 0)
469 //log_info("<connection>");
470 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTION;
472 uuid_str = ladish_get_uuid_attribute(attr, "port1", uuid, false);
473 if (uuid_str == NULL)
475 log_error("/room/connections/connection \"port1\" attribute is not available.");
476 context_ptr->error = XML_TRUE;
477 goto free;
480 uuid2_str = ladish_get_uuid_attribute(attr, "port2", uuid2, false);
481 if (uuid2_str == NULL)
483 log_error("/room/connections/connection \"port2\" attribute is not available.");
484 context_ptr->error = XML_TRUE;
485 goto free;
488 log_info("room connection between port %s and port %s", uuid_str, uuid2_str);
490 port1 = ladish_graph_find_port_by_uuid(room_ptr->graph, uuid, true, NULL);
491 if (port1 == NULL)
493 log_error("room client with unknown port %s", uuid_str);
494 context_ptr->error = XML_TRUE;
495 goto free;
498 port2 = ladish_graph_find_port_by_uuid(room_ptr->graph, uuid2, true, NULL);
499 if (port2 == NULL)
501 log_error("room client with unknown port %s", uuid2_str);
502 context_ptr->error = XML_TRUE;
503 goto free;
506 context_ptr->connection_id = ladish_graph_add_connection(room_ptr->graph, port1, port2, true);
507 if (context_ptr->connection_id == 0)
509 log_error("ladish_graph_add_connection() failed.");
510 goto free;
513 goto free;
516 if (strcmp(el, "applications") == 0)
518 //log_info("<applications>");
519 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATIONS;
520 goto free;
523 if (strcmp(el, "application") == 0)
525 //log_info("<application>");
526 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATION;
528 name = ladish_get_string_attribute(attr, "name");
529 if (name == NULL)
531 log_error("application \"name\" attribute is not available.");
532 context_ptr->error = XML_TRUE;
533 goto free;
536 if (!ladish_get_uuid_attribute(attr, "uuid", context_ptr->uuid, true))
538 uuid_clear(context_ptr->uuid);
541 if (ladish_get_bool_attribute(attr, "terminal", &context_ptr->terminal) == NULL)
543 log_error("application \"terminal\" attribute is not available. name=\"%s\"", name);
544 context_ptr->error = XML_TRUE;
545 goto free;
548 if (ladish_get_bool_attribute(attr, "autorun", &context_ptr->autorun) == NULL)
550 log_error("application \"autorun\" attribute is not available. name=\"%s\"", name);
551 context_ptr->error = XML_TRUE;
552 goto free;
555 level = ladish_get_string_attribute(attr, "level");
556 if (level == NULL)
558 log_error("application \"level\" attribute is not available. name=\"%s\"", name);
559 context_ptr->error = XML_TRUE;
560 goto free;
563 if (!ladish_check_app_level_validity(level, &len))
565 log_error("application \"level\" attribute has invalid value \"%s\", name=\"%s\"", level, name);
566 context_ptr->error = XML_TRUE;
567 goto free;
570 memcpy(context_ptr->level, level, len + 1);
572 context_ptr->str = strdup(name);
573 if (context_ptr->str == NULL)
575 log_error("strdup() failed");
576 context_ptr->error = XML_TRUE;
577 goto free;
580 context_ptr->data_used = 0;
581 goto free;
584 if (strcmp(el, "dict") == 0)
586 //log_info("<dict>");
587 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DICT;
589 if (context_ptr->dict != NULL)
591 log_error("nested dicts");
592 context_ptr->error = XML_TRUE;
593 goto free;
596 if (context_ptr->depth == 1 &&
597 context_ptr->element[0] == PARSE_CONTEXT_PROJECT)
599 context_ptr->dict = ladish_graph_get_dict(room_ptr->graph);
600 ASSERT(context_ptr->dict != NULL);
602 else if (context_ptr->depth > 0 &&
603 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CLIENT)
605 ASSERT(context_ptr->client != NULL);
606 context_ptr->dict = ladish_client_get_dict(context_ptr->client);
607 ASSERT(context_ptr->dict != NULL);
609 else if (context_ptr->depth > 0 &&
610 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORT)
612 ASSERT(context_ptr->port != NULL);
613 context_ptr->dict = ladish_port_get_dict(context_ptr->port);
614 ASSERT(context_ptr->dict != NULL);
616 else if (context_ptr->depth > 0 &&
617 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CONNECTION)
619 ASSERT(context_ptr->port != NULL);
620 context_ptr->dict = ladish_graph_get_connection_dict(room_ptr->graph, context_ptr->connection_id);
621 ASSERT(context_ptr->dict != NULL);
623 else
625 log_error("unexpected dict XML element");
626 context_ptr->error = XML_TRUE;
627 goto free;
630 goto free;
633 if (strcmp(el, "key") == 0)
635 //log_info("<key>");
636 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_KEY;
638 if (context_ptr->dict == NULL)
640 log_error("dict-less key");
641 context_ptr->error = XML_TRUE;
642 goto free;
645 name = ladish_get_string_attribute(attr, "name");
646 if (name == NULL)
648 log_error("dict/key \"name\" attribute is not available.");
649 context_ptr->error = XML_TRUE;
650 goto free;
653 context_ptr->str = strdup(name);
654 if (context_ptr->str == NULL)
656 log_error("strdup() failed");
657 context_ptr->error = XML_TRUE;
658 goto free;
661 context_ptr->data_used = 0;
663 goto free;
666 log_error("unknown element \"%s\"", el);
667 context_ptr->error = XML_TRUE;
669 free:
670 free(name_dup);
673 static void callback_elend(void * data, const char * UNUSED(el))
675 if (context_ptr->error)
677 return;
680 //log_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
682 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY &&
683 context_ptr->depth > 0 &&
684 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_DICT)
686 ASSERT(context_ptr->dict != NULL);
687 context_ptr->data[context_ptr->data_used] = 0;
688 log_info("dict key '%s' with value '%s'", context_ptr->str, context_ptr->data);
689 if (!ladish_dict_set(context_ptr->dict, context_ptr->str, context_ptr->data))
691 log_error("ladish_dict_set() failed");
692 context_ptr->error = XML_TRUE;
693 return;
696 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_ROOM)
698 //log_info("</room>");
700 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_JACK)
702 //log_info("</jack>");
704 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_DICT)
706 //log_info("</dict>");
707 ASSERT(context_ptr->dict != NULL);
708 context_ptr->dict = NULL;
710 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_CLIENT)
712 //log_info("</client>");
713 ASSERT(context_ptr->client != NULL);
714 context_ptr->client = NULL;
716 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PORT)
718 //log_info("</port>");
719 ASSERT(context_ptr->port != NULL);
720 context_ptr->port = NULL;
722 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
724 context_ptr->data[unescape(context_ptr->data, context_ptr->data_used, context_ptr->data)] = 0;
725 unescape_simple(context_ptr->str);
727 log_info("application '%s' (%s, %s, level '%s') with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", context_ptr->level, context_ptr->data);
729 if (ladish_app_supervisor_add(
730 room_ptr->app_supervisor,
731 context_ptr->str,
732 context_ptr->uuid,
733 context_ptr->autorun,
734 context_ptr->data,
735 context_ptr->terminal,
736 context_ptr->level) == NULL)
738 log_error("ladish_app_supervisor_add() failed.");
739 context_ptr->error = XML_TRUE;
742 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_DESCRIPTION)
744 context_ptr->data[unescape(context_ptr->data, context_ptr->data_used, context_ptr->data)] = 0;
745 //log_info("</description>");
746 //log_info("[%s]", context_ptr->data);
748 ASSERT(room_ptr->project_description == NULL);
749 room_ptr->project_description = strdup(context_ptr->data);
750 if (room_ptr->project_description == NULL)
752 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Project description failed to load", LADISH_CHECK_LOG_TEXT);
755 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_NOTES)
757 context_ptr->data[unescape(context_ptr->data, context_ptr->data_used, context_ptr->data)] = 0;
758 //log_info("</notes>");
759 //log_info("[%s]", context_ptr->data);
761 ASSERT(room_ptr->project_notes == NULL);
762 room_ptr->project_notes = strdup(context_ptr->data);
763 if (room_ptr->project_notes == NULL)
765 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Project notes failed to load", LADISH_CHECK_LOG_TEXT);
769 context_ptr->depth--;
771 if (context_ptr->str != NULL)
773 free(context_ptr->str);
774 context_ptr->str = NULL;
777 return;
780 #undef room_ptr
781 #undef context_ptr
783 #define room_ptr ((struct ladish_room *)room_handle)
785 bool ladish_room_load_project(ladish_room_handle room_handle, const char * project_dir)
787 char * path;
788 struct stat st;
789 XML_Parser parser;
790 int bytes_read;
791 void * buffer;
792 int fd;
793 enum XML_Status xmls;
794 struct ladish_parse_context parse_context;
795 bool ret;
797 log_info("Loading project '%s' into room '%s'", project_dir, room_ptr->name);
799 ASSERT(room_ptr->project_state == ROOM_PROJECT_STATE_UNLOADED);
800 ASSERT(room_ptr->project_dir == NULL);
801 ASSERT(room_ptr->project_name == NULL);
802 ASSERT(!ladish_app_supervisor_has_apps(room_ptr->app_supervisor));
803 ASSERT(!ladish_graph_has_visible_connections(room_ptr->graph));
805 ret = false;
807 room_ptr->project_dir = strdup(project_dir);
808 if (room_ptr->project_dir == NULL)
810 log_error("strdup() failed to for project dir");
811 goto exit;
814 path = catdup(project_dir, LADISH_PROJECT_FILENAME);
815 if (path == NULL)
817 log_error("catdup() failed to compose xml file path");
818 goto exit;
821 if (stat(path, &st) != 0)
823 log_error("failed to stat '%s': %d (%s)", path, errno, strerror(errno));
824 goto free_path;
827 fd = open(path, O_RDONLY);
828 if (fd == -1)
830 log_error("failed to open '%s': %d (%s)", path, errno, strerror(errno));
831 goto free_path;
834 parser = XML_ParserCreate(NULL);
835 if (parser == NULL)
837 log_error("XML_ParserCreate() failed to create parser object.");
838 goto close;
841 //log_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
843 /* we are expecting that conf file has small enough size to fit in memory */
845 buffer = XML_GetBuffer(parser, st.st_size);
846 if (buffer == NULL)
848 log_error("XML_GetBuffer() failed.");
849 goto free_parser;
852 bytes_read = read(fd, buffer, st.st_size);
853 if (bytes_read != st.st_size)
855 log_error("read() returned unexpected result.");
856 goto free_parser;
859 //log_info("\n----------\n%s\n-----------\n", buffer);
860 //goto free_parser;
862 parse_context.error = XML_FALSE;
863 parse_context.depth = -1;
864 parse_context.str = NULL;
865 parse_context.client = NULL;
866 parse_context.port = NULL;
867 parse_context.dict = NULL;
868 parse_context.room = room_handle;
870 XML_SetElementHandler(parser, callback_elstart, callback_elend);
871 XML_SetCharacterDataHandler(parser, callback_chrdata);
872 XML_SetUserData(parser, &parse_context);
874 ladish_app_supervisor_set_directory(room_ptr->app_supervisor, project_dir);
875 if (!ladish_app_supervisor_set_project_name(room_ptr->app_supervisor, room_ptr->project_name))
877 ladish_app_supervisor_set_project_name(room_ptr->app_supervisor, NULL);
880 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
881 if (xmls == XML_STATUS_ERROR && !parse_context.error)
883 log_error("XML_ParseBuffer() failed.");
885 if (xmls == XML_STATUS_ERROR || parse_context.error)
887 goto free_parser;
890 ladish_interlink(room_ptr->graph, room_ptr->app_supervisor);
891 ladish_graph_dump(ladish_studio_get_jack_graph());
892 ladish_graph_dump(room_ptr->graph);
893 ladish_app_supervisor_dump(room_ptr->app_supervisor);
895 ladish_graph_trick_dicts(room_ptr->graph);
896 ladish_try_connect_hidden_connections(room_ptr->graph);
897 ladish_app_supervisor_autorun(room_ptr->app_supervisor);
899 ladish_recent_project_use(room_ptr->project_dir);
900 ladish_room_emit_project_properties_changed(room_ptr);
902 ret = true;
904 free_parser:
905 XML_ParserFree(parser);
906 close:
907 close(fd);
908 free_path:
909 free(path);
910 exit:
911 if (!ret)
913 ladish_room_clear_project(room_ptr);
914 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Project load failed", LADISH_CHECK_LOG_TEXT);
916 else
918 room_ptr->project_state = ROOM_PROJECT_STATE_LOADED;
921 return ret;
924 #undef room_ptr
926 #define context_ptr ((struct ladish_parse_context *)data)
928 static void project_name_elstart_callback(void * data, const char * el, const char ** attr)
930 const char * name;
931 const char * uuid_str;
932 uuid_t uuid;
933 size_t len;
935 if (strcmp(el, "project") == 0)
937 if (ladish_get_name_and_uuid_attributes("/project", attr, &name, &uuid_str, uuid))
939 len = strlen(name) + 1;
940 context_ptr->str = malloc(len);
941 if (context_ptr->str == NULL)
943 log_error("malloc() failed for project name with length %zu", len);
946 unescape(name, len, context_ptr->str);
949 XML_StopParser(context_ptr->parser, XML_TRUE);
950 return;
954 #undef context_ptr
956 char * ladish_get_project_name(const char * project_dir)
958 char * path;
959 struct stat st;
960 XML_Parser parser;
961 int bytes_read;
962 void * buffer;
963 int fd;
964 enum XML_Status xmls;
965 struct ladish_parse_context parse_context;
967 parse_context.str = NULL;
969 path = catdup(project_dir, LADISH_PROJECT_FILENAME);
970 if (path == NULL)
972 log_error("catdup() failed to compose xml file path");
973 goto exit;
976 if (stat(path, &st) != 0)
978 log_error("failed to stat '%s': %d (%s)", path, errno, strerror(errno));
979 goto free_path;
982 fd = open(path, O_RDONLY);
983 if (fd == -1)
985 log_error("failed to open '%s': %d (%s)", path, errno, strerror(errno));
986 goto free_path;
989 parser = XML_ParserCreate(NULL);
990 if (parser == NULL)
992 log_error("XML_ParserCreate() failed to create parser object.");
993 goto close;
996 /* we are expecting that conf file has small enough size to fit in memory */
998 buffer = XML_GetBuffer(parser, st.st_size);
999 if (buffer == NULL)
1001 log_error("XML_GetBuffer() failed.");
1002 goto free_parser;
1005 bytes_read = read(fd, buffer, st.st_size);
1006 if (bytes_read != st.st_size)
1008 log_error("read() returned unexpected result.");
1009 goto free_parser;
1012 XML_SetElementHandler(parser, project_name_elstart_callback, NULL);
1013 XML_SetUserData(parser, &parse_context);
1015 parse_context.parser = parser;
1017 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
1018 if (xmls == XML_STATUS_ERROR)
1020 log_error("XML_ParseBuffer() failed.");
1023 free_parser:
1024 XML_ParserFree(parser);
1025 close:
1026 close(fd);
1027 free_path:
1028 free(path);
1029 exit:
1030 return parse_context.str;