2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.ihc.internal.ws.projectfile;
15 import java.io.ByteArrayInputStream;
17 import java.io.IOException;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
27 import org.apache.commons.io.FileUtils;
28 import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
29 import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Element;
34 import org.w3c.dom.NodeList;
35 import org.xml.sax.SAXException;
38 * Generic methods related to IHC / ELKO project file handling.
40 * @author Pauli Anttila - Initial contribution
42 public class ProjectFileUtils {
43 private static final Logger LOGGER = LoggerFactory.getLogger(ProjectFileUtils.class);
46 * Read IHC project file from local file.
48 * @param filePath File to read.
49 * @return XML document.
50 * @throws IhcExecption when file read fails.
52 public static Document readFromFile(String filePath) throws IhcExecption {
53 File fXmlFile = new File(filePath);
54 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
56 // see https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
57 dbFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
58 dbFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
59 dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
60 dbFactory.setXIncludeAware(false);
61 dbFactory.setExpandEntityReferences(false);
62 DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
63 Document doc = dBuilder.parse(fXmlFile);
65 } catch (IOException | ParserConfigurationException | SAXException e) {
66 throw new IhcExecption(e);
71 * Save IHC project file to local file.
73 * @param filePath File path.
74 * @param data Data to write
75 * @throws IhcExecption when file write fails.
77 public static void saveToFile(String filePath, byte[] data) throws IhcExecption {
79 FileUtils.writeByteArrayToFile(new File(filePath), data);
80 } catch (IOException e) {
81 throw new IhcExecption(e);
86 * Convert bytes to XML document.
88 * @return XML document or null if conversion fails.
90 public static Document converteBytesToDocument(byte[] data) {
91 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
92 factory.setNamespaceAware(true);
94 DocumentBuilder builder = factory.newDocumentBuilder();
95 return builder.parse(new ByteArrayInputStream(data));
96 } catch (ParserConfigurationException | SAXException | IOException e) {
97 LOGGER.warn("Error occured when trying to convert data to XML, reason {}", e.getMessage());
103 * Compare XML document header information to project info.
105 * @return true if information is equal and false if not.
107 public static boolean projectEqualsToControllerProject(Document projectfile, WSProjectInfo projectInfo) {
108 if (projectInfo != null) {
110 NodeList nodes = projectfile.getElementsByTagName("modified");
111 if (nodes.getLength() == 1) {
112 Element node = (Element) nodes.item(0);
113 int year = Integer.parseInt(node.getAttribute("year"));
114 int month = Integer.parseInt(node.getAttribute("month"));
115 int day = Integer.parseInt(node.getAttribute("day"));
116 int hour = Integer.parseInt(node.getAttribute("hour"));
117 int minute = Integer.parseInt(node.getAttribute("minute"));
119 LOGGER.debug("Project file from file, date: {}.{}.{} {}:{}", year, month, day, hour, minute);
120 LOGGER.debug("Project file in controller, date: {}.{}.{} {}:{}",
121 projectInfo.getLastmodified().getYear(),
122 projectInfo.getLastmodified().getMonthWithJanuaryAsOne(),
123 projectInfo.getLastmodified().getDay(), projectInfo.getLastmodified().getHours(),
124 projectInfo.getLastmodified().getMinutes());
126 if (projectInfo.getLastmodified().getYear() == year
127 && projectInfo.getLastmodified().getMonthWithJanuaryAsOne() == month
128 && projectInfo.getLastmodified().getDay() == day
129 && projectInfo.getLastmodified().getHours() == hour
130 && projectInfo.getLastmodified().getMinutes() == minute) {
134 } catch (RuntimeException e) {
135 LOGGER.debug("Error occured during project file date comparasion, reason {}.", e.getMessage(), e);
136 // There is no documentation available for XML content. This is part of inessential feature, so do
137 // nothing, but return false
144 * Parse all enum values from IHC project file.
146 * @param doc IHC project file in XML format.
147 * @return enum dictionary.
149 public static Map<Integer, List<IhcEnumValue>> parseEnums(Document doc) {
150 Map<Integer, List<IhcEnumValue>> enumDictionary = new HashMap<>();
152 NodeList nodes = doc.getElementsByTagName("enum_definition");
154 // iterate enum definitions from project
155 for (int i = 0; i < nodes.getLength(); i++) {
156 Element element = (Element) nodes.item(i);
158 int typedefId = Integer.parseInt(element.getAttribute("id").replace("_0x", ""), 16);
159 String enumName = element.getAttribute("name");
161 List<IhcEnumValue> enumValues = new ArrayList<>();
163 NodeList name = element.getElementsByTagName("enum_value");
165 for (int j = 0; j < name.getLength(); j++) {
166 Element val = (Element) name.item(j);
167 int id = Integer.parseInt(val.getAttribute("id").replace("_0x", ""), 16);
168 String n = val.getAttribute("name");
169 IhcEnumValue enumVal = new IhcEnumValue(id, n);
170 enumValues.add(enumVal);
173 LOGGER.debug("Enum values found: typedefId={}, name={}: {}", typedefId, enumName, enumValues);
174 enumDictionary.put(typedefId, enumValues);
177 return enumDictionary;