]> git.basschouten.com Git - openhab-addons.git/blob
3ccb76a832006a11cafb8f3dc71357e993574021
[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 bit) {
165                 for (final byte b : bit.getArray()) {
166                     jsonArray.add(new JsonPrimitive(b));
167                 }
168             } else if (field instanceof JBBPFieldArrayBoolean boolean1) {
169                 for (final boolean b : boolean1.getArray()) {
170                     jsonArray.add(new JsonPrimitive(b));
171                 }
172             } else if (field instanceof JBBPFieldArrayByte byte1) {
173                 for (final byte b : byte1.getArray()) {
174                     jsonArray.add(new JsonPrimitive(b));
175                 }
176             } else if (field instanceof JBBPFieldArrayInt int1) {
177                 for (final int b : int1.getArray()) {
178                     jsonArray.add(new JsonPrimitive(b));
179                 }
180             } else if (field instanceof JBBPFieldArrayLong long1) {
181                 for (final long b : long1.getArray()) {
182                     jsonArray.add(new JsonPrimitive(b));
183                 }
184             } else if (field instanceof JBBPFieldArrayShort short1) {
185                 for (final short b : short1.getArray()) {
186                     jsonArray.add(new JsonPrimitive(b));
187                 }
188             } else if (field instanceof JBBPFieldArrayStruct array) {
189                 for (int i = 0; i < array.size(); i++) {
190                     jsonArray.add(convertToJSon(new JsonObject(), array.getElementAt(i)));
191                 }
192             } else if (field instanceof JBBPFieldArrayUByte byte1) {
193                 for (final byte b : byte1.getArray()) {
194                     jsonArray.add(new JsonPrimitive(b & 0xFF));
195                 }
196             } else if (field instanceof JBBPFieldArrayUShort short1) {
197                 for (final short b : short1.getArray()) {
198                     jsonArray.add(new JsonPrimitive(b & 0xFFFF));
199                 }
200             } else {
201                 throw new ConversionException(String.format("Unexpected field type '%s'", field));
202             }
203             jsn.add(fieldName, jsonArray);
204         } else {
205             if (field instanceof JBBPFieldBit bit) {
206                 jsn.addProperty(fieldName, bit.getAsInt());
207             } else if (field instanceof JBBPFieldBoolean boolean1) {
208                 jsn.addProperty(fieldName, boolean1.getAsBool());
209             } else if (field instanceof JBBPFieldByte byte1) {
210                 jsn.addProperty(fieldName, byte1.getAsInt());
211             } else if (field instanceof JBBPFieldInt int1) {
212                 jsn.addProperty(fieldName, int1.getAsInt());
213             } else if (field instanceof JBBPFieldLong long1) {
214                 jsn.addProperty(fieldName, long1.getAsLong());
215             } else if (field instanceof JBBPFieldShort short1) {
216                 jsn.addProperty(fieldName, short1.getAsInt());
217             } else if (field instanceof JBBPFieldStruct struct) {
218                 final JsonObject obj = new JsonObject();
219                 for (final JBBPAbstractField f : struct.getArray()) {
220                     convertToJSon(obj, f);
221                 }
222                 if (json == null) {
223                     return obj;
224                 } else {
225                     jsn.add(fieldName, obj);
226                 }
227             } else if (field instanceof JBBPFieldUByte byte1) {
228                 jsn.addProperty(fieldName, byte1.getAsInt());
229             } else if (field instanceof JBBPFieldUShort short1) {
230                 jsn.addProperty(fieldName, short1.getAsInt());
231             } else {
232                 throw new ConversionException(String.format("Unexpected field '%s'", field));
233             }
234         }
235         return jsn;
236     }
237 }