summaryrefslogtreecommitdiff
path: root/voice-app/src/Model/ManifestParser.cpp
blob: 8b40092313be77b4438ec9ccc808f66091435c6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
 * Copyright 2017 Samsung Electronics Co., Ltd
 *
 * Licensed under the Flora License, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://floralicense.org/license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Model/ManifestParser.h"
#include "Model/VoiceCommand.h"
#include "Utils/Callback.h"
#include "Utils/String.h"

using namespace Model;
using namespace Utils;
using namespace std::placeholders;

namespace
{
	const char *nodeUiApp         = "ui-application";
	const char *nodeAppControl    = "app-control";
	const char *nodeVoiceCommand  = "voice-command";
	const char *nodeOperation     = "operation";
	const char *nodeMime          = "mime";
	const char *nodeUri           = "uri";
	const char *propType          = "type";
	const char *propName          = "name";
	const char *nodeCommandName   = "name";
	const char *propTypeWithParam = "with-param";
}

ManifestParser::ManifestParser(std::string path, std::string appId)
	: m_AppId(std::move(appId)), m_Doc(nullptr)
{
	m_Doc = xmlReadFile(path.c_str(), nullptr, 0);
}

ManifestParser::~ManifestParser()
{
	if (m_Doc) {
		xmlFreeDoc(m_Doc);
		xmlCleanupParser();
	}
}

void ManifestParser::parse(CommandFoundCallback callback)
{
	m_OnCommandFound = std::move(callback);

	if (!m_Doc) {
		return;
	}

	xmlNode *manifest = xmlDocGetRootElement(m_Doc);
	findChildNodes(manifest, nodeUiApp, std::bind(&ManifestParser::parseUiAppNode, this, _1));
}

void ManifestParser::findChildNodes(xmlNodePtr parentNode, const char *childNodeName, NodeFoundCallback onNodeFound)
{
	for (auto node = parentNode->children; node; node = xmlNextElementSibling(node)) {
		if (node->type == XML_ELEMENT_NODE && safeCmp((const char *)node->name, childNodeName)) {
			onNodeFound(node);
		}
	}
}

void ManifestParser::parseUiAppNode(xmlNodePtr uiAppNode)
{
	findChildNodes(uiAppNode, nodeAppControl, std::bind(&ManifestParser::parseAppControlNode, this, _1));
}

void ManifestParser::parseAppControlNode(xmlNodePtr appControlNode)
{
	VoiceCommand command;
	command.setAppId(m_AppId);

	for (auto node = appControlNode->children; node; node = xmlNextElementSibling(node)) {
		if (node->type == XML_ELEMENT_NODE) {
			auto nodeName = (const char *)node->name;
			auto properties = node->properties;

			if (safeCmp(nodeName, nodeVoiceCommand)) {
				parseVoiceCommandNode(node, command);
			} else if (safeCmp((const char *)properties->name, propName)) {
				auto value = (const char *)properties->children->content;
				if (safeCmp(nodeName, nodeOperation)) {
					command.setOperation(value);
				} else if (safeCmp(nodeName, nodeMime)) {
					command.setMime(value);
				} else if (safeCmp(nodeName, nodeUri)) {
					command.setUri(value);
				}
			}
		}
	}

	if (m_OnCommandFound && !command.getNames().empty()) {
		m_OnCommandFound(std::move(command));
	}
}

void ManifestParser::parseVoiceCommandNode(xmlNodePtr voiceCommandNode, VoiceCommand &command)
{
	auto properties = voiceCommandNode->properties;

	if (safeCmp((const char *)properties->name, propType) &&
		safeCmp((const char *)properties->children->content, propTypeWithParam)) {
		command.setType(VoiceCommand::CommandWithParam);
	} else {
		command.setType(VoiceCommand::CommandWithAction);
	}

	for (auto node = voiceCommandNode->children; node; node = xmlNextElementSibling(node)) {
		if (node->type == XML_ELEMENT_NODE && safeCmp((const char *)node->name, nodeCommandName)) {
			command.addName((const char *)node->children->content);
		}
	}
}