diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml
index 732ac5e4c2..706b88899a 100644
--- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/pom.xml
@@ -92,6 +92,7 @@
${basedir}/src/test/resources/simple_types.asn
${basedir}/src/test/resources/complex_types.asn
${basedir}/src/test/resources/example.asn
+ ${basedir}/src/test/resources/tbcd_string.asn
-o
${basedir}/target/generated-test-sources
@@ -128,8 +129,10 @@
src/test/resources/example.asn
src/test/resources/simple_types.asn
src/test/resources/complex_types.asn
+ src/test/resources/tbcd_string.asn
src/test/resources/examples/basic-types.dat
src/test/resources/examples/composite.dat
+ src/test/resources/examples/tbcd-string.dat
diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java
index 4c52b79ac7..fc684d0f98 100644
--- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/JASN1ConverterImpl.java
@@ -29,6 +29,7 @@ import org.apache.nifi.jasn1.convert.converters.BerOctetStringConverter;
import org.apache.nifi.jasn1.convert.converters.BerRealConverter;
import org.apache.nifi.jasn1.convert.converters.BerRecordConverter;
import org.apache.nifi.jasn1.convert.converters.BerStringConverter;
+import org.apache.nifi.jasn1.convert.converters.TbcdStringConverter;
import org.apache.nifi.jasn1.convert.converters.BerTimeOfDayConverter;
import org.apache.nifi.serialization.record.DataType;
import org.apache.nifi.serialization.record.RecordSchema;
@@ -50,6 +51,7 @@ public class JASN1ConverterImpl implements JASN1Converter {
new BerDateTimeConverter(),
new BerRealConverter(),
new BerStringConverter(),
+ new TbcdStringConverter(),
new BerOctetStringConverter(),
new BerArrayConverter(),
new BerRecordConverter(schemaProvider)
diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/TbcdStringConverter.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/TbcdStringConverter.java
new file mode 100644
index 0000000000..5596ff2179
--- /dev/null
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/TbcdStringConverter.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+package org.apache.nifi.jasn1.convert.converters;
+
+import com.beanit.asn1bean.ber.types.BerOctetString;
+import com.beanit.asn1bean.ber.types.BerType;
+import org.apache.nifi.jasn1.convert.JASN1Converter;
+import org.apache.nifi.jasn1.convert.JASN1TypeAndValueConverter;
+import org.apache.nifi.serialization.record.DataType;
+import org.apache.nifi.serialization.record.RecordFieldType;
+
+public class TbcdStringConverter implements JASN1TypeAndValueConverter {
+
+ private static final String TBCD_STRING_TYPE = "TBCDSTRING";
+ private static final char[] TBCD_SYMBOLS = "0123456789*#abc".toCharArray();
+ private static final int FILLER_DECIMAL_CODE = 15;
+
+ @Override
+ public boolean supportsType(Class> berType) {
+ boolean supportsType = BerOctetString.class.isAssignableFrom(berType) && isTbcdString(berType);
+
+ return supportsType;
+ }
+
+ @Override
+ public DataType convertType(Class> berType, JASN1Converter converter) {
+ DataType dataType = RecordFieldType.STRING.getDataType();
+
+ return dataType;
+ }
+
+ @Override
+ public boolean supportsValue(BerType value, DataType dataType) {
+ boolean supportsValue = value instanceof BerOctetString && isTbcdString(value.getClass());
+
+ return supportsValue;
+ }
+
+ @Override
+ public Object convertValue(BerType value, DataType dataType, JASN1Converter converter) {
+ final BerOctetString berValue = ((BerOctetString) value);
+
+ byte[] bytes = berValue.value;
+
+ int size = (bytes == null ? 0 : bytes.length);
+ StringBuilder resultBuilder = new StringBuilder(2 * size);
+
+ for (int octetIndex = 0; octetIndex < size; ++octetIndex) {
+ int octet = bytes[octetIndex];
+
+ int digit2 = (octet >> 4) & 0xF;
+ int digit1 = octet & 0xF;
+
+ if (digit1 == FILLER_DECIMAL_CODE) {
+ invalidFiller(octetIndex, octet);
+ } else if (digit1 > 15) {
+ invalidInteger(digit1);
+ } else {
+ resultBuilder.append(TBCD_SYMBOLS[digit1]);
+ }
+
+ if (digit2 == FILLER_DECIMAL_CODE) {
+ if (octetIndex != size - 1) {
+ invalidFiller(octetIndex, octet);
+ }
+ } else if (digit2 > 15) {
+ invalidInteger(digit2);
+ } else {
+ resultBuilder.append(TBCD_SYMBOLS[digit2]);
+ }
+ }
+
+ return resultBuilder.toString();
+ }
+
+ private boolean isTbcdString(Class> berType) {
+ Class> currentType = berType;
+ while (currentType != null) {
+ if (currentType.getSimpleName().equals(TBCD_STRING_TYPE)) {
+ return true;
+ }
+
+ currentType = currentType.getSuperclass();
+ }
+
+ return false;
+ }
+
+ private void invalidFiller(int octetIndex, int octet) {
+ throw new NumberFormatException("Illegal filler in octet " + octetIndex + ": " + octet);
+ }
+
+ private void invalidInteger(int digit) {
+ throw new IllegalArgumentException(
+ "Integer should be between 0 - 15 for Telephony Binary Coded Decimal String. Received " + digit);
+ }
+}
diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java
index f73ad45ab4..5296d5bfa6 100644
--- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/ExampleDataGenerator.java
@@ -25,6 +25,8 @@ import com.beanit.asn1bean.ber.types.string.BerUTF8String;
import org.apache.nifi.jasn1.example.BasicTypeSet;
import org.apache.nifi.jasn1.example.BasicTypes;
import org.apache.nifi.jasn1.example.Composite;
+import org.apache.nifi.jasn1.tbcd.TBCDSTRING;
+import org.apache.nifi.jasn1.tbcd.TbcdStringWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,6 +54,8 @@ public class ExampleDataGenerator {
generateComposite(dir);
generateMultiRecord(dir);
+
+ generateTbcdString(dir);
}
private static void generateBasicTypes(File dir) throws IOException {
@@ -143,4 +147,17 @@ public class ExampleDataGenerator {
return encoded;
}
+
+ private static void generateTbcdString(File dir) throws IOException {
+ final File file = new File(dir, "tbcd-string.dat");
+ try (final ReverseByteArrayOutputStream rev = new ReverseByteArrayOutputStream(1024);
+ final OutputStream out = new FileOutputStream(file)) {
+ final TbcdStringWrapper tbcdStringWrapper = new TbcdStringWrapper();
+ tbcdStringWrapper.setTbcdString(new TBCDSTRING(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}));
+ tbcdStringWrapper.setOctetString(new BerOctetString(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}));
+ final int encoded = tbcdStringWrapper.encode(rev);
+ out.write(rev.getArray(), 0, encoded);
+ LOG.info("Generated {} bytes to {}", encoded, file);
+ }
+ }
}
diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java
index c1fb12c24d..129d5bac39 100644
--- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/java/org/apache/nifi/jasn1/TestJASN1RecordReader.java
@@ -153,4 +153,23 @@ public class TestJASN1RecordReader implements JASN1ReadRecordTester {
assertNull(record3);
}
}
+
+ @Test
+ public void testTbcdString() throws Exception {
+ try (final InputStream input = TestJASN1RecordReader.class.getResourceAsStream("/examples/tbcd-string.dat")) {
+
+ final JASN1RecordReader reader = new JASN1RecordReader("org.apache.nifi.jasn1.tbcd.TbcdStringWrapper", null,
+ new RecordSchemaProvider(), Thread.currentThread().getContextClassLoader(), null,
+ input, new MockComponentLog("id", new JASN1Reader()));
+
+ final RecordSchema schema = reader.getSchema();
+ assertEquals("TbcdStringWrapper", schema.getSchemaName().orElse(null));
+
+ Record record = reader.nextRecord(true, false);
+ assertNotNull(record);
+
+ record = reader.nextRecord(true, false);
+ assertNull(record);
+ }
+ }
}
diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/examples/tbcd-string.dat b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/examples/tbcd-string.dat
new file mode 100644
index 0000000000..18097ce68d
--- /dev/null
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/examples/tbcd-string.dat
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/tbcd_string.asn b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/tbcd_string.asn
new file mode 100644
index 0000000000..d5802a531c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/test/resources/tbcd_string.asn
@@ -0,0 +1,22 @@
+ORG-APACHE-NIFI-JASN1-TBCD
+
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+TbcdStringWrapper ::= SEQUENCE
+{
+ tbcdString [0] TBCD-STRING,
+ octetString [1] OCTET STRING (SIZE (4..255))
+}
+
+TBCD-STRING ::= OCTET STRING
+-- This type (Telephony Binary Coded Decimal String) is used to
+-- represent several digits from 0 through 9, *, #, a, b , c, two
+-- digits per octet, each digit encoded 0000 to 1001 (0 to 9),
+-- 1010 (*), 1011 (#), 1100 (a), 1101 (b) or 1110 (c); 1111 used
+-- as filler when there is an odd number of digits.
+-- bits 8765 of octet n encoding digit 2n
+-- bits 4321 of octet n encoding digit 2(n-1) 1
+
+END
\ No newline at end of file