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: 29 окт. 2019 г.
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/XMLNode.h>
23 #include <ui/XMLHandler.h>
24 
25 namespace lsp
26 {
27     //-------------------------------------------------------------------------
28     // XML Node implementation
XMLNode()29     XMLNode::XMLNode()
30     {
31     }
32 
~XMLNode()33     XMLNode::~XMLNode()
34     {
35     }
36 
find_attribute(const LSPString * const * atts,const LSPString * name)37     const LSPString *XMLNode::find_attribute(const LSPString * const *atts, const LSPString *name)
38     {
39         for ( ; *atts != NULL; atts += 2)
40         {
41             if (atts[0]->equals(name))
42                 return atts[1];
43         }
44 
45         return NULL;
46     }
47 
find_attribute(const LSPString * const * atts,const char * name)48     const LSPString *XMLNode::find_attribute(const LSPString * const *atts, const char *name)
49     {
50         LSPString tmp;
51         if (!tmp.set_utf8(name))
52             return NULL;
53         return find_attribute(atts, &tmp);
54     }
55 
enter()56     status_t XMLNode::enter()
57     {
58         return STATUS_OK;
59     }
60 
start_element(XMLNode ** child,const LSPString * name,const LSPString * const * atts)61     status_t XMLNode::start_element(XMLNode **child, const LSPString *name, const LSPString * const *atts)
62     {
63         return STATUS_OK;
64     }
65 
end_element(const LSPString * name)66     status_t XMLNode::end_element(const LSPString *name)
67     {
68         return STATUS_OK;
69     }
70 
quit()71     status_t XMLNode::quit()
72     {
73         return STATUS_OK;
74     }
75 
completed(XMLNode * child)76     status_t XMLNode::completed(XMLNode *child)
77     {
78         return STATUS_OK;
79     }
80 
81     //-------------------------------------------------------------------------
82     // XML Playback Node implementation
xml_event_t(event_t type)83     XMLPlaybackNode::xml_event_t::xml_event_t(event_t type)
84     {
85         nEvent      = type;
86     }
87 
~xml_event_t()88     XMLPlaybackNode::xml_event_t::~xml_event_t()
89     {
90         for (size_t i=0, n=vData.size(); i<n; ++i)
91         {
92             LSPString *s = vData.at(i);
93             if (s != NULL)
94                 delete s;
95         }
96         vData.flush();
97     }
98 
add_param(const LSPString * name)99     status_t XMLPlaybackNode::xml_event_t::add_param(const LSPString *name)
100     {
101         LSPString *tmp;
102         if ((tmp = name->clone()) == NULL)
103             return STATUS_NO_MEM;
104         else if (!vData.add(tmp))
105         {
106             delete tmp;
107             return STATUS_NO_MEM;
108         }
109         return STATUS_OK;
110     }
111 
add_event(event_t ev)112     XMLPlaybackNode::xml_event_t *XMLPlaybackNode::add_event(event_t ev)
113     {
114         xml_event_t *evt        = new xml_event_t(ev);
115         if (evt == NULL)
116             return NULL;
117         else if (!vEvents.add(evt))
118         {
119             delete evt;
120             evt = NULL;
121         }
122         return evt;
123     }
124 
XMLPlaybackNode(XMLNode * handler)125     XMLPlaybackNode::XMLPlaybackNode(XMLNode *handler)
126     {
127         pHandler    = handler;
128     }
129 
~XMLPlaybackNode()130     XMLPlaybackNode::~XMLPlaybackNode()
131     {
132         for (size_t i=0, n=vEvents.size(); i<n; ++i)
133         {
134             xml_event_t *ev = vEvents.at(i);
135             if (ev != NULL)
136                 delete ev;
137         }
138         vEvents.flush();
139     }
140 
init(const LSPString * const * atts)141     status_t XMLPlaybackNode::init(const LSPString * const *atts)
142     {
143         return STATUS_OK;
144     }
145 
playback_start_element(xml::IXMLHandler * handler,const LSPString * name,const LSPString * const * atts)146     status_t XMLPlaybackNode::playback_start_element(xml::IXMLHandler *handler, const LSPString *name, const LSPString * const *atts)
147     {
148         return handler->start_element(name, atts);
149     }
150 
playback_end_element(xml::IXMLHandler * handler,const LSPString * name)151     status_t XMLPlaybackNode::playback_end_element(xml::IXMLHandler *handler, const LSPString *name)
152     {
153         return handler->end_element(name);
154     }
155 
playback()156     status_t XMLPlaybackNode::playback()
157     {
158         status_t res = STATUS_OK;
159         XMLHandler h(pHandler);
160 
161         for (size_t i=0, n=vEvents.size(); i<n; ++i)
162         {
163             // Fetch event
164             xml_event_t *ev = vEvents.at(i);
165             if (ev == NULL)
166             {
167                 res = STATUS_CORRUPTED;
168                 break;
169             }
170 
171             // Parse event
172             LSPString **atts = ev->vData.get_array();
173             switch (ev->nEvent)
174             {
175                 case EVT_START_ELEMENT:
176                     res = playback_start_element(&h, atts[0], &atts[1]);
177                     break;
178                 case EVT_END_ELEMENT:
179                     res = playback_end_element(&h, atts[0]);
180                     break;
181                 default:
182                     res = STATUS_CORRUPTED;
183                     break;
184             }
185 
186             // Check result
187             if (res != STATUS_OK)
188                 break;
189         }
190 
191         return res;
192     }
193 
execute()194     status_t XMLPlaybackNode::execute()
195     {
196         return playback();
197     }
198 
start_element(XMLNode ** child,const LSPString * name,const LSPString * const * atts)199     status_t XMLPlaybackNode::start_element(XMLNode **child, const LSPString *name, const LSPString * const *atts)
200     {
201         // Allocate event
202         status_t res;
203         xml_event_t *evt        = add_event(EVT_START_ELEMENT);
204         if (evt == NULL)
205             return STATUS_NO_MEM;
206 
207         // Clone element name
208         if ((res = evt->add_param(name)) != STATUS_OK)
209             return res;
210 
211         // Clone tag attributes
212         for ( ; *atts != NULL; ++atts)
213         {
214             // Clone attribute
215             if ((res = evt->add_param(*atts)) != STATUS_OK)
216                 return res;
217         }
218 
219         // Add terminator
220         if (!evt->vData.add(NULL))
221             return STATUS_NO_MEM;
222 
223         // Increment level, set child to this
224         *child = this;
225 
226         return STATUS_OK;
227     }
228 
end_element(const LSPString * name)229     status_t XMLPlaybackNode::end_element(const LSPString *name)
230     {
231         // Allocate event and add parameter
232         xml_event_t *evt        = add_event(EVT_END_ELEMENT);
233         return (evt != NULL) ? evt->add_param(name) : STATUS_NO_MEM;
234     }
235 
236 } /* namespace lsp */
237