]> git.basschouten.com Git - openhab-addons.git/blob
c44bf7b83b2e5e7452352d3f0831c2e71b87e719
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ihc.internal.ws.projectfile;
14
15 import java.io.ByteArrayInputStream;
16 import java.io.File;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import javax.xml.parsers.DocumentBuilder;
25 import javax.xml.parsers.DocumentBuilderFactory;
26 import javax.xml.parsers.ParserConfigurationException;
27
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;
36
37 /**
38  * Generic methods related to IHC / ELKO project file handling.
39  *
40  * @author Pauli Anttila - Initial contribution
41  */
42 public class ProjectFileUtils {
43     private static final Logger LOGGER = LoggerFactory.getLogger(ProjectFileUtils.class);
44
45     /**
46      * Read IHC project file from local file.
47      *
48      * @param filePath File to read.
49      * @return XML document.
50      * @throws IhcExecption when file read fails.
51      */
52     public static Document readFromFile(String filePath) throws IhcExecption {
53         File fXmlFile = new File(filePath);
54         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
55         try {
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);
64             return doc;
65         } catch (IOException | ParserConfigurationException | SAXException e) {
66             throw new IhcExecption(e);
67         }
68     }
69
70     /**
71      * Save IHC project file to local file.
72      *
73      * @param filePath File path.
74      * @param data Data to write
75      * @throws IhcExecption when file write fails.
76      */
77     public static void saveToFile(String filePath, byte[] data) throws IhcExecption {
78         try {
79             try (FileOutputStream stream = new FileOutputStream(filePath)) {
80                 stream.write(data);
81                 stream.flush();
82             }
83         } catch (IOException e) {
84             throw new IhcExecption(e);
85         }
86     }
87
88     /**
89      * Convert bytes to XML document.
90      *
91      * @return XML document or null if conversion fails.
92      */
93     public static Document converteBytesToDocument(byte[] data) {
94         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
95         factory.setNamespaceAware(true);
96         try {
97             DocumentBuilder builder = factory.newDocumentBuilder();
98             return builder.parse(new ByteArrayInputStream(data));
99         } catch (ParserConfigurationException | SAXException | IOException e) {
100             LOGGER.warn("Error occured when trying to convert data to XML, reason {}", e.getMessage());
101         }
102         return null;
103     }
104
105     /**
106      * Compare XML document header information to project info.
107      *
108      * @return true if information is equal and false if not.
109      */
110     public static boolean projectEqualsToControllerProject(Document projectfile, WSProjectInfo projectInfo) {
111         if (projectInfo != null) {
112             try {
113                 NodeList nodes = projectfile.getElementsByTagName("modified");
114                 if (nodes.getLength() == 1) {
115                     Element node = (Element) nodes.item(0);
116                     int year = Integer.parseInt(node.getAttribute("year"));
117                     int month = Integer.parseInt(node.getAttribute("month"));
118                     int day = Integer.parseInt(node.getAttribute("day"));
119                     int hour = Integer.parseInt(node.getAttribute("hour"));
120                     int minute = Integer.parseInt(node.getAttribute("minute"));
121
122                     LOGGER.debug("Project file from file, date: {}.{}.{} {}:{}", year, month, day, hour, minute);
123                     LOGGER.debug("Project file in controller, date: {}.{}.{} {}:{}",
124                             projectInfo.getLastmodified().getYear(),
125                             projectInfo.getLastmodified().getMonthWithJanuaryAsOne(),
126                             projectInfo.getLastmodified().getDay(), projectInfo.getLastmodified().getHours(),
127                             projectInfo.getLastmodified().getMinutes());
128
129                     if (projectInfo.getLastmodified().getYear() == year
130                             && projectInfo.getLastmodified().getMonthWithJanuaryAsOne() == month
131                             && projectInfo.getLastmodified().getDay() == day
132                             && projectInfo.getLastmodified().getHours() == hour
133                             && projectInfo.getLastmodified().getMinutes() == minute) {
134                         return true;
135                     }
136                 }
137             } catch (RuntimeException e) {
138                 LOGGER.debug("Error occured during project file date comparasion, reason {}.", e.getMessage(), e);
139                 // There is no documentation available for XML content. This is part of inessential feature, so do
140                 // nothing, but return false
141             }
142         }
143         return false;
144     }
145
146     /**
147      * Parse all enum values from IHC project file.
148      *
149      * @param doc IHC project file in XML format.
150      * @return enum dictionary.
151      */
152     public static Map<Integer, List<IhcEnumValue>> parseEnums(Document doc) {
153         Map<Integer, List<IhcEnumValue>> enumDictionary = new HashMap<>();
154         if (doc != null) {
155             NodeList nodes = doc.getElementsByTagName("enum_definition");
156
157             // iterate enum definitions from project
158             for (int i = 0; i < nodes.getLength(); i++) {
159                 Element element = (Element) nodes.item(i);
160
161                 int typedefId = Integer.parseInt(element.getAttribute("id").replace("_0x", ""), 16);
162                 String enumName = element.getAttribute("name");
163
164                 List<IhcEnumValue> enumValues = new ArrayList<>();
165
166                 NodeList name = element.getElementsByTagName("enum_value");
167
168                 for (int j = 0; j < name.getLength(); j++) {
169                     Element val = (Element) name.item(j);
170                     int id = Integer.parseInt(val.getAttribute("id").replace("_0x", ""), 16);
171                     String n = val.getAttribute("name");
172                     IhcEnumValue enumVal = new IhcEnumValue(id, n);
173                     enumValues.add(enumVal);
174                 }
175
176                 LOGGER.debug("Enum values found: typedefId={}, name={}: {}", typedefId, enumName, enumValues);
177                 enumDictionary.put(typedefId, enumValues);
178             }
179         }
180         return enumDictionary;
181     }
182 }