]> git.basschouten.com Git - openhab-addons.git/blob
a884f8367dd46c345109e03916f06723c9038ed3
[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.transform.bin2json.internal;
14
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.time.Duration;
18 import java.time.LocalDateTime;
19
20 import org.openhab.core.util.HexUtils;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import com.google.gson.JsonArray;
25 import com.google.gson.JsonObject;
26 import com.google.gson.JsonPrimitive;
27 import com.igormaznitsa.jbbp.JBBPParser;
28 import com.igormaznitsa.jbbp.exceptions.JBBPException;
29 import com.igormaznitsa.jbbp.model.JBBPAbstractArrayField;
30 import com.igormaznitsa.jbbp.model.JBBPAbstractField;
31 import com.igormaznitsa.jbbp.model.JBBPFieldArrayBit;
32 import com.igormaznitsa.jbbp.model.JBBPFieldArrayBoolean;
33 import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte;
34 import com.igormaznitsa.jbbp.model.JBBPFieldArrayInt;
35 import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong;
36 import com.igormaznitsa.jbbp.model.JBBPFieldArrayShort;
37 import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct;
38 import com.igormaznitsa.jbbp.model.JBBPFieldArrayUByte;
39 import com.igormaznitsa.jbbp.model.JBBPFieldArrayUShort;
40 import com.igormaznitsa.jbbp.model.JBBPFieldBit;
41 import com.igormaznitsa.jbbp.model.JBBPFieldBoolean;
42 import com.igormaznitsa.jbbp.model.JBBPFieldByte;
43 import com.igormaznitsa.jbbp.model.JBBPFieldInt;
44 import com.igormaznitsa.jbbp.model.JBBPFieldLong;
45 import com.igormaznitsa.jbbp.model.JBBPFieldShort;
46 import com.igormaznitsa.jbbp.model.JBBPFieldStruct;
47 import com.igormaznitsa.jbbp.model.JBBPFieldUByte;
48 import com.igormaznitsa.jbbp.model.JBBPFieldUShort;
49
50 /**
51  * This class converts binary data to JSON format.
52  *
53  * Parser rules follows Java Binary Block Parser syntax.
54  *
55  * <p>
56  *
57  * See details from <a href=
58  * "https://github.com/raydac/java-binary-block-parser">https://github.com/raydac/java-binary-block-parser</a>
59  *
60  * <p>
61  * Usage example:
62  *
63  * <pre>
64  * {@code
65  * JsonObject json = new Bin2Json("byte a; byte b; ubyte c;").convert("03FAFF");
66  * json.toString() = {"a":3,"b":-6,"c":255}}
67  * </pre>
68  *
69  * @author Pauli Anttila - Initial contribution
70  *
71  */
72 public class Bin2Json {
73
74     private final Logger logger = LoggerFactory.getLogger(Bin2Json.class);
75
76     private JBBPParser parser;
77
78     /**
79      *
80      * @param parserRule Binary data parser rule
81      * @throws ConversionException
82      */
83     public Bin2Json(String parserRule) throws ConversionException {
84         try {
85             parser = JBBPParser.prepare(parserRule);
86         } catch (JBBPException e) {
87             throw new ConversionException(String.format("Illegal parser rule, reason: %s", e.getMessage(), e));
88         }
89     }
90
91     /**
92      * Convert {@link String} in hexadecimal string format to JSON object.
93      *
94      * @param hexString Data in hexadecimal string format. Example data: 03FAFF
95      * @return Gson {@link JsonObject}
96      * @throws ConversionException
97      */
98     public JsonObject convert(String hexString) throws ConversionException {
99         try {
100             return convert(HexUtils.hexToBytes(hexString));
101         } catch (IllegalArgumentException e) {
102             throw new ConversionException(String.format("Illegal hexstring , reason: %s", e.getMessage(), e));
103         }
104     }
105
106     /**
107      * Convert byte array to JSON object.
108      *
109      * @param data Data in byte array format.
110      * @return Gson {@link JsonObject}
111      * @throws ConversionException
112      */
113     public JsonObject convert(byte[] data) throws ConversionException {
114         try {
115             return convert(parser.parse(data));
116         } catch (IOException e) {
117             throw new ConversionException(String.format("Unexpected error, reason: %s", e.getMessage(), e));
118         } catch (JBBPException e) {
119             throw new ConversionException(String.format("Unexpected error, reason: %s", e.getMessage(), e));
120         }
121     }
122
123     /**
124      * Convert data from {@link InputStream} to JSON object.
125      *
126      * @param inputStream
127      * @return Gson {@link JsonObject}
128      * @throws ConversionException
129      */
130     public JsonObject convert(InputStream inputStream) throws ConversionException {
131         try {
132             return convert(parser.parse(inputStream));
133         } catch (IOException e) {
134             throw new ConversionException(String.format("Unexpected error, reason: %s", e.getMessage(), e));
135         } catch (JBBPException e) {
136             throw new ConversionException(String.format("Unexpected error, reason: %s", e.getMessage(), e));
137         }
138     }
139
140     private JsonObject convert(JBBPFieldStruct data) throws ConversionException {
141         try {
142             LocalDateTime start = LocalDateTime.now();
143             final JsonObject json = convertToJSon(data);
144             if (logger.isTraceEnabled()) {
145                 Duration duration = Duration.between(start, LocalDateTime.now());
146                 logger.trace("Conversion time={}, json={}", duration, json.toString());
147             }
148             return json;
149         } catch (JBBPException e) {
150             throw new ConversionException(String.format("Unexpected error, reason: %s", e.getMessage(), e));
151         }
152     }
153
154     private JsonObject convertToJSon(final JBBPAbstractField field) throws ConversionException {
155         return convertToJSon(null, field);
156     }
157
158     private JsonObject convertToJSon(final JsonObject json, final JBBPAbstractField field) throws ConversionException {
159         JsonObject jsn = json == null ? new JsonObject() : json;
160
161         final String fieldName = field.getFieldName() == null ? "nonamed" : field.getFieldName();
162         if (field instanceof JBBPAbstractArrayField) {
163             final JsonArray jsonArray = new JsonArray();
164             if (field instanceof JBBPFieldArrayBit) {
165                 for (final byte b : ((JBBPFieldArrayBit) field).getArray()) {
166                     jsonArray.add(new JsonPrimitive(b));
167                 }
168             } else if (field instanceof JBBPFieldArrayBoolean) {
169                 for (final boolean b : ((JBBPFieldArrayBoolean) field).getArray()) {
170                     jsonArray.add(new JsonPrimitive(b));
171                 }
172             } else if (field instanceof JBBPFieldArrayByte) {
173                 for (final byte b : ((JBBPFieldArrayByte) field).getArray()) {
174                     jsonArray.add(new JsonPrimitive(b));
175                 }
176             } else if (field instanceof JBBPFieldArrayInt) {
177                 for (final int b : ((JBBPFieldArrayInt) field).getArray()) {
178                     jsonArray.add(new JsonPrimitive(b));
179                 }
180             } else if (field instanceof JBBPFieldArrayLong) {
181                 for (final long b : ((JBBPFieldArrayLong) field).getArray()) {
182                     jsonArray.add(new JsonPrimitive(b));
183                 }
184             } else if (field instanceof JBBPFieldArrayShort) {
185                 for (final short b : ((JBBPFieldArrayShort) field).getArray()) {
186                     jsonArray.add(new JsonPrimitive(b));
187                 }
188             } else if (field instanceof JBBPFieldArrayStruct) {
189                 final JBBPFieldArrayStruct array = (JBBPFieldArrayStruct) field;
190                 for (int i = 0; i < array.size(); i++) {
191                     jsonArray.add(convertToJSon(new JsonObject(), array.getElementAt(i)));
192                 }
193             } else if (field instanceof JBBPFieldArrayUByte) {
194                 for (final byte b : ((JBBPFieldArrayUByte) field).getArray()) {
195                     jsonArray.add(new JsonPrimitive(b & 0xFF));
196                 }
197             } else if (field instanceof JBBPFieldArrayUShort) {
198                 for (final short b : ((JBBPFieldArrayUShort) field).getArray()) {
199                     jsonArray.add(new JsonPrimitive(b & 0xFFFF));
200                 }
201             } else {
202                 throw new ConversionException(String.format("Unexpected field type '%s'", field));
203             }
204             jsn.add(fieldName, jsonArray);
205         } else {
206             if (field instanceof JBBPFieldBit) {
207                 jsn.addProperty(fieldName, ((JBBPFieldBit) field).getAsInt());
208             } else if (field instanceof JBBPFieldBoolean) {
209                 jsn.addProperty(fieldName, ((JBBPFieldBoolean) field).getAsBool());
210             } else if (field instanceof JBBPFieldByte) {
211                 jsn.addProperty(fieldName, ((JBBPFieldByte) field).getAsInt());
212             } else if (field instanceof JBBPFieldInt) {
213                 jsn.addProperty(fieldName, ((JBBPFieldInt) field).getAsInt());
214             } else if (field instanceof JBBPFieldLong) {
215                 jsn.addProperty(fieldName, ((JBBPFieldLong) field).getAsLong());
216             } else if (field instanceof JBBPFieldShort) {
217                 jsn.addProperty(fieldName, ((JBBPFieldShort) field).getAsInt());
218             } else if (field instanceof JBBPFieldStruct) {
219                 final JBBPFieldStruct struct = (JBBPFieldStruct) field;
220                 final JsonObject obj = new JsonObject();
221                 for (final JBBPAbstractField f : struct.getArray()) {
222                     convertToJSon(obj, f);
223                 }
224                 if (json == null) {
225                     return obj;
226                 } else {
227                     jsn.add(fieldName, obj);
228                 }
229             } else if (field instanceof JBBPFieldUByte) {
230                 jsn.addProperty(fieldName, ((JBBPFieldUByte) field).getAsInt());
231             } else if (field instanceof JBBPFieldUShort) {
232                 jsn.addProperty(fieldName, ((JBBPFieldUShort) field).getAsInt());
233             } else {
234                 throw new ConversionException(String.format("Unexpected field '%s'", field));
235             }
236         }
237         return jsn;
238     }
239 }