summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/main/java/org/uic/barcode/Decoder.java9
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/AsnExtractor.java80
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/AsnUtils.java59
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/BitBuffer.java1
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/BitStringCoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/BooleanCoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/ByteBitBuffer.java30
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/ByteCoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/ChoiceCoder.java6
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/Decoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/EnumCoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/IntCoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/SeqOfCoder.java4
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/SequenceCoder.java29
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/StringCoder.java2
-rw-r--r--src/main/java/org/uic/barcode/asn1/uper/UperEncoder.java46
-rw-r--r--src/main/java/org/uic/barcode/dynamicFrame/api/IDynamicFrame.java26
-rw-r--r--src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java109
-rw-r--r--src/main/java/org/uic/barcode/dynamicFrame/v1/DynamicFrameCoderV1.java15
-rw-r--r--src/main/java/org/uic/barcode/dynamicFrame/v2/DynamicFrameCoderV2.java11
-rw-r--r--src/main/java/org/uic/barcode/utils/AlgorithmNameResolver.java37
-rw-r--r--src/test/java/org/uic/barcode/test/BinaryStringTest.java61
-rw-r--r--src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java2
23 files changed, 443 insertions, 96 deletions
diff --git a/src/main/java/org/uic/barcode/Decoder.java b/src/main/java/org/uic/barcode/Decoder.java
index b980f19..5cb0546 100644
--- a/src/main/java/org/uic/barcode/Decoder.java
+++ b/src/main/java/org/uic/barcode/Decoder.java
@@ -81,7 +81,7 @@ public class Decoder {
*/
public int validateLevel1(PublicKey key, String signingAlg) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IllegalArgumentException, UnsupportedOperationException, IOException, EncodingFormatException {
if (!isStaticHeader(data)) {
- return dynamicFrame.validateLevel1(key) ;
+ return dynamicFrame.validateLevel1(key, data) ;
} else {
if (staticFrame.verifyByAlgorithmOid(key,signingAlg)) {
return Constants.LEVEL1_VALIDATION_OK;
@@ -91,7 +91,6 @@ public class Decoder {
}
}
-
/**
* Validate level 1.
*
@@ -109,7 +108,7 @@ public class Decoder {
*/
public int validateLevel1(PublicKey key, String signingAlg, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IllegalArgumentException, UnsupportedOperationException, IOException, EncodingFormatException {
if (!isStaticHeader(data)) {
- return dynamicFrame.validateLevel1(key, provider) ;
+ return dynamicFrame.validateLevel1(key, provider, data) ;
} else {
if (staticFrame.verifyByAlgorithmOid(key,signingAlg, provider)) {
return Constants.LEVEL1_VALIDATION_OK;
@@ -127,7 +126,7 @@ public class Decoder {
*/
public int validateLevel2() throws EncodingFormatException {
if (!isStaticHeader(data)) {
- return dynamicFrame.validateLevel2() ;
+ return dynamicFrame.validateLevel2(null, data) ;
} else {
return Constants.LEVEL2_VALIDATION_NO_SIGNATURE;
}
@@ -140,7 +139,7 @@ public class Decoder {
*/
public int validateLevel2(Provider prov) throws EncodingFormatException {
if (!isStaticHeader(data)) {
- return dynamicFrame.validateLevel2(prov) ;
+ return dynamicFrame.validateLevel2(prov,data) ;
} else {
return Constants.LEVEL2_VALIDATION_NO_SIGNATURE;
}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/AsnExtractor.java b/src/main/java/org/uic/barcode/asn1/uper/AsnExtractor.java
new file mode 100644
index 0000000..0d5d1da
--- /dev/null
+++ b/src/main/java/org/uic/barcode/asn1/uper/AsnExtractor.java
@@ -0,0 +1,80 @@
+package org.uic.barcode.asn1.uper;
+
+public class AsnExtractor {
+
+ private String path = null;
+
+ private boolean extractionStarted = false;
+ private boolean extractionCompleted = false;
+
+ private BitBuffer bitBuffer = null;
+ private int startBit = 0;
+ private int endBit = 0;
+
+ AsnExtractor(String path, BitBuffer bitBuffer) {
+ this.path = path;
+ this.bitBuffer = bitBuffer;
+ }
+
+ public byte[] getResult() {
+
+ if (!extractionCompleted) {
+ return null;
+ }
+
+ if (!(endBit > startBit)) {
+ return null;
+ }
+
+ String bitString = bitBuffer.toBooleanString(startBit, endBit - startBit);
+
+ while (bitString.length() % 8 != 0) {
+ bitString = bitString + "0";
+ }
+
+ return AsnUtils.fromBooleanString(bitString);
+
+ }
+
+
+
+ public boolean found(String className) {
+
+ if (extractionStarted || extractionCompleted) return false;
+
+ if (path != null && path.length() > 0 && className != null & className.length() > 0) {
+ if (className.endsWith(path)){
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void startExtraction(int position) {
+
+ if (path == null || path.length() == 0 || bitBuffer == null) {
+ return;
+ }
+
+ if (!extractionCompleted && !extractionStarted) {
+ extractionStarted = true;
+ startBit = position;
+ }
+ }
+
+ public void endExtraction(int position) {
+ if (extractionStarted) {
+ extractionCompleted = true;
+ endBit = position;
+ }
+
+ }
+
+ public boolean isStarted() {
+ return extractionStarted;
+ }
+
+
+
+}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/AsnUtils.java b/src/main/java/org/uic/barcode/asn1/uper/AsnUtils.java
new file mode 100644
index 0000000..dbb95c9
--- /dev/null
+++ b/src/main/java/org/uic/barcode/asn1/uper/AsnUtils.java
@@ -0,0 +1,59 @@
+package org.uic.barcode.asn1.uper;
+
+public class AsnUtils {
+
+
+ private static byte[] mask = new byte[] {
+ (byte) 0b1000_0000,
+ 0b0100_0000,
+ 0b0010_0000,
+ 0b0001_0000,
+ 0b0000_1000,
+ 0b0000_0100,
+ 0b0000_0010,
+ 0b0000_0001,
+ };
+
+
+ public static byte[] fromBooleanString(final String s) {
+
+ char[] ascii = s.toCharArray();
+ if (ascii == null || ascii.length == 0) {
+ return null;
+ }
+ // get length/8 times bytes with 3 bit shifts to the right of the length
+ final byte[] l_raw = new byte[ascii.length >> 3];
+ /*
+ * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
+ * loop.
+ */
+ for (int ii = 0, jj = 0; ii < l_raw.length; ii++, jj += 8) {
+ for (int bits = 0; bits < mask.length; ++bits) {
+ if (ascii[jj + bits] == '1') {
+ l_raw[ii] |= mask[bits];
+ }
+ }
+ }
+ return l_raw;
+ }
+
+ public static String toBooleanString(byte[] bytes) {
+ StringBuilder sb = new StringBuilder(bytes.length);
+ for (int i = 0; i < bytes.length*8;i++) {
+ sb.append(AsnUtils.get(bytes,i) ? "1" : "0");
+ }
+ return sb.toString();
+ }
+
+ public static boolean get(byte[] bytes, int index) {
+
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Index " + index + " is less than 0");
+ } else if (index >= bytes.length * 8) {
+ throw new IndexOutOfBoundsException("Index " + index + " violates the limit " + bytes.length*8);
+ }
+ boolean result = (bytes[index / 8] & mask[index % 8]) != 0;
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/BitBuffer.java b/src/main/java/org/uic/barcode/asn1/uper/BitBuffer.java
index bba0de7..21d0e03 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/BitBuffer.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/BitBuffer.java
@@ -19,6 +19,7 @@ public interface BitBuffer {
BitBuffer flip();
String toBooleanString(int startIndex, int length);
String toBooleanStringFromPosition(int startIndex);
+ byte[] fromBooleanString(String s);
byte[] array();
BitBuffer putByte(byte element);
byte getByte();
diff --git a/src/main/java/org/uic/barcode/asn1/uper/BitStringCoder.java b/src/main/java/org/uic/barcode/asn1/uper/BitStringCoder.java
index 19aac9b..6f435c4 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/BitStringCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/BitStringCoder.java
@@ -97,7 +97,7 @@ class BitStringCoder implements Decoder, Encoder {
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),
extraAnnotations);
if (!Asn1VarSizeBitstring.class.isAssignableFrom(classOfT)) {
diff --git a/src/main/java/org/uic/barcode/asn1/uper/BooleanCoder.java b/src/main/java/org/uic/barcode/asn1/uper/BooleanCoder.java
index 3bd7a38..892f851 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/BooleanCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/BooleanCoder.java
@@ -22,7 +22,7 @@ class BooleanCoder implements Decoder, Encoder {
@SuppressWarnings("unchecked")
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
Boolean result = new Boolean(bitbuffer.get());
UperEncoder.logger.debug(String.format("BOOL: decoded as %s",result));
return (T) result;
diff --git a/src/main/java/org/uic/barcode/asn1/uper/ByteBitBuffer.java b/src/main/java/org/uic/barcode/asn1/uper/ByteBitBuffer.java
index 3ed3eed..e409005 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/ByteBitBuffer.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/ByteBitBuffer.java
@@ -3,7 +3,7 @@ package org.uic.barcode.asn1.uper;
public class ByteBitBuffer implements BitBuffer {
-
+
byte[] bytes;
byte[] mask = new byte[] {
(byte) 0b1000_0000,
@@ -45,7 +45,8 @@ public class ByteBitBuffer implements BitBuffer {
bytes = newbytes;
}
- @Override public BitBuffer put(int index, boolean element) {
+ @Override
+ public BitBuffer put(int index, boolean element) {
if (bytes.length <= index / 8) {
if (isFinite) { throw new IndexOutOfBoundsException(); }
else { grow(); }
@@ -58,21 +59,24 @@ public class ByteBitBuffer implements BitBuffer {
return this;
}
- @Override public BitBuffer put(boolean element) {
+ @Override
+ public BitBuffer put(boolean element) {
put(position, element);
position++;
limit = limit < position ? position : limit; // TODO: should it be here?
return this;
}
- @Override public BitBuffer putByte(byte element) {
+ @Override
+ public BitBuffer putByte(byte element) {
for (int i = 0; i < 8; i++) {
put((element & mask[i]) != 0);
}
return this;
}
- @Override public BitBuffer putByteArray(int index, byte[] data) {
+ @Override
+ public BitBuffer putByteArray(int index, byte[] data) {
for (int l = 0; l < data.length;l++) {
for (int i = 0; i < 8; i++) {
@@ -83,7 +87,8 @@ public class ByteBitBuffer implements BitBuffer {
}
- @Override public byte getByte() {
+ @Override
+ public byte getByte() {
byte result = 0;
for (int i = 0; i < 8; i++) {
result |= (get() ? 1 : 0) << (7 - i);
@@ -91,11 +96,13 @@ public class ByteBitBuffer implements BitBuffer {
return result;
}
- @Override public int limit() {
+ @Override
+ public int limit() {
return limit;
}
- @Override public String toBooleanString(int startIndex, int length) {
+ @Override
+ public String toBooleanString(int startIndex, int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = startIndex; i < startIndex + length; i++) {
sb.append(get(i) ? "1" : "0");
@@ -267,5 +274,12 @@ public class ByteBitBuffer implements BitBuffer {
return stringBuilder.toString().trim();
}
+
+ public byte[] fromBooleanString(final String s) {
+
+ return AsnUtils.fromBooleanString(s);
+
+ }
+
}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/ByteCoder.java b/src/main/java/org/uic/barcode/asn1/uper/ByteCoder.java
index f26a598..5ecb925 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/ByteCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/ByteCoder.java
@@ -21,7 +21,7 @@ class ByteCoder implements Decoder, Encoder {
@SuppressWarnings("unchecked")
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
UperEncoder.logger.debug("BYTE");
return (T) new Byte((byte) UperEncoder.decodeConstrainedInt(bitbuffer, UperEncoder.newRange(0, 255, false)));
}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/ChoiceCoder.java b/src/main/java/org/uic/barcode/asn1/uper/ChoiceCoder.java
index d17a813..0bbce73 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/ChoiceCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/ChoiceCoder.java
@@ -95,7 +95,7 @@ class ChoiceCoder implements Decoder, Encoder {
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field1,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),extraAnnotations);
UperEncoder.logger.debug(String.format("CHOICE: %s", classOfT.getName()));
T result = UperEncoder.instantiate(classOfT);
@@ -120,7 +120,7 @@ class ChoiceCoder implements Decoder, Encoder {
Class<?> classOfElement = field != null ? field.getType() : null;
if (field != null) {
try {
- Object decodedValue = UperEncoder.decodeAsOpenType(bitbuffer, classOfElement,field, field.getAnnotations());
+ Object decodedValue = UperEncoder.decodeAsOpenType(bitbuffer, classOfElement,field, field.getAnnotations(),extractor);
if (field != null) {
field.set(result, decodedValue);
}
@@ -144,7 +144,7 @@ class ChoiceCoder implements Decoder, Encoder {
UperEncoder.newRange(0, sorter.ordinaryFields.size() - 1, false));
Field f = sorter.ordinaryFields.get(index);
UperEncoder.logger.debug(String.format("CHOICE: selected %s", f.getName()));
- Object fieldValue = UperEncoder.decodeAny(bitbuffer, f.getType(),f, f.getAnnotations());
+ Object fieldValue = UperEncoder.decodeAny(bitbuffer, f.getType(),f, f.getAnnotations(),extractor);
try {
f.set(result, fieldValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
diff --git a/src/main/java/org/uic/barcode/asn1/uper/Decoder.java b/src/main/java/org/uic/barcode/asn1/uper/Decoder.java
index 947a752..3140443 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/Decoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/Decoder.java
@@ -5,6 +5,6 @@ import java.lang.reflect.Field;
public interface Decoder {
<T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations);
- <T> T decode(BitBuffer bitbuffer, Class<T> classOfT,Field f, Annotation[] extraAnnotations);
+ <T> T decode(BitBuffer bitbuffer, Class<T> classOfT,Field f, Annotation[] extraAnnotations,AsnExtractor extractor);
<T> T getDefault(Class<T> classOfT, Annotation[] extraAnnotations);
}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/EnumCoder.java b/src/main/java/org/uic/barcode/asn1/uper/EnumCoder.java
index 5d78bc7..3bfdec9 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/EnumCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/EnumCoder.java
@@ -82,7 +82,7 @@ class EnumCoder implements Decoder, Encoder {
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), extraAnnotations);
UperEncoder.logger.debug("ENUM");
boolean extensionPresent = false;
diff --git a/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java b/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java
index 5964a64..e5e48c1 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/IntCoder.java
@@ -27,7 +27,7 @@ class IntCoder implements Encoder, Decoder {
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),extraAnnotations);
String pos = String.format("Position: %d.%d", bitbuffer.position()/8 , bitbuffer.position() % 8);
UperEncoder.logger.debug(String.format("%s: INTEGER",pos));
diff --git a/src/main/java/org/uic/barcode/asn1/uper/SeqOfCoder.java b/src/main/java/org/uic/barcode/asn1/uper/SeqOfCoder.java
index a7ae7ba..d0ce782 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/SeqOfCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/SeqOfCoder.java
@@ -96,7 +96,7 @@ class SeqOfCoder implements Decoder, Encoder {
@SuppressWarnings("unchecked")
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT,Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),
extraAnnotations);
UperEncoder.logger.debug(String.format("SEQUENCE OF for %s", classOfT));
@@ -135,7 +135,7 @@ class SeqOfCoder implements Decoder, Encoder {
}
}
for (int i = 0; i < size; i++) {
- coll.add(UperEncoder.decodeAny(bitbuffer, classOfElements,field, annotationArray));
+ coll.add(UperEncoder.decodeAny(bitbuffer, classOfElements,field, annotationArray, extractor));
}
T result = null;
diff --git a/src/main/java/org/uic/barcode/asn1/uper/SequenceCoder.java b/src/main/java/org/uic/barcode/asn1/uper/SequenceCoder.java
index ce89a3e..3af7217 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/SequenceCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/SequenceCoder.java
@@ -150,13 +150,24 @@ class SequenceCoder implements Decoder, Encoder {
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT,Field f1,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations,
+ AsnExtractor extractor) {
UperEncoder.logger.debug(String.format("decode SEQUENCE %s",classOfT.getSimpleName()));
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),extraAnnotations);
T result = UperEncoder.instantiate(classOfT);
- Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(classOfT);
+ Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(classOfT);
boolean hasExtensionMarker = UperEncoder.hasExtensionMarker(annotations);
boolean extensionPresent = false;
+
+ //check Extraction
+ boolean extract = false;
+ if (extractor != null && !extractor.isStarted() && extractor.found(classOfT.getCanonicalName())) {
+ extractor.startExtraction(bitbuffer.position());
+ extract = true;
+ }
+
+
+ //start decodong
if (hasExtensionMarker) {
extensionPresent = bitbuffer.get();
UperEncoder.logger.debug(String.format("with extension marker, extension %s", extensionPresent ? "present!" : "absent"));
@@ -175,7 +186,7 @@ class SequenceCoder implements Decoder, Encoder {
(UperEncoder.isOptional(f) && optionalFieldsMask.pop()))) {
UperEncoder.logger.debug(String.format("Field : %s", f.getName()));
try {
- f.set(result, UperEncoder.decodeAny(bitbuffer,f.getType(),f, f.getAnnotations()));
+ f.set(result, UperEncoder.decodeAny(bitbuffer,f.getType(),f, f.getAnnotations(),extractor));
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("can't access 'set method' for field " + f + " of class " + classOfT + " " + e, e);
}
@@ -196,6 +207,11 @@ class SequenceCoder implements Decoder, Encoder {
if (!hasExtensionMarker) {
//done
sorter.revertAccess();
+
+ if (extract) {
+ extractor.endExtraction(bitbuffer.position());
+ }
+
return result;
}
@@ -222,7 +238,7 @@ class SequenceCoder implements Decoder, Encoder {
Class<?> classOfElement = field != null ? field.getType() : null;
if (field != null) {
try {
- Object decodedValue = UperEncoder.decodeAsOpenType(bitbuffer, classOfElement,field, field.getAnnotations());
+ Object decodedValue = UperEncoder.decodeAsOpenType(bitbuffer, classOfElement,field, field.getAnnotations(),extractor);
if (field != null) {
field.set(result, decodedValue);
}
@@ -269,6 +285,11 @@ class SequenceCoder implements Decoder, Encoder {
} // end of extension handling
}
sorter.revertAccess();
+
+ if (extract) {
+ extractor.endExtraction(bitbuffer.position());
+ }
+
return result;
}
diff --git a/src/main/java/org/uic/barcode/asn1/uper/StringCoder.java b/src/main/java/org/uic/barcode/asn1/uper/StringCoder.java
index 349e988..a504096 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/StringCoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/StringCoder.java
@@ -150,7 +150,7 @@ class StringCoder implements Decoder, Encoder {
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT, Field field,
- Annotation[] extraAnnotations) {
+ Annotation[] extraAnnotations, AsnExtractor extractor) {
UperEncoder.logger.debug("decode String");
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(), extraAnnotations);
RestrictedString restrictionAnnotation = annotations.getAnnotation(RestrictedString.class);
diff --git a/src/main/java/org/uic/barcode/asn1/uper/UperEncoder.java b/src/main/java/org/uic/barcode/asn1/uper/UperEncoder.java
index d5c5d1e..c256b4f 100644
--- a/src/main/java/org/uic/barcode/asn1/uper/UperEncoder.java
+++ b/src/main/java/org/uic/barcode/asn1/uper/UperEncoder.java
@@ -66,7 +66,7 @@ public final class UperEncoder {
public static <T> T decode(byte[] bytes, Class<T> classOfT) throws IllegalArgumentException,
UnsupportedOperationException {
BitBuffer bitQueue = bitBufferFromBinaryString(binaryStringFromBytes(bytes));
- T result = decodeAny(bitQueue, classOfT,null, new Annotation[] {});
+ T result = decodeAny(bitQueue, classOfT,null, new Annotation[] {}, null);
if (bitQueue.remaining() > 7) {
throw new IllegalArgumentException("Can't fully decode "
+ classOfT.getName() + ", got (" + result.getClass().getName() + "): " + result
@@ -74,11 +74,43 @@ public final class UperEncoder {
}
return result;
}
+
+ public static <T> T decode(byte[] bytes, Class<T> classOfT,AsnExtractor extractor) throws IllegalArgumentException,
+ UnsupportedOperationException {
+ BitBuffer bitQueue = bitBufferFromBinaryString(binaryStringFromBytes(bytes));
+ T result = decodeAny(bitQueue, classOfT,null, new Annotation[] {}, extractor);
+ if (bitQueue.remaining() > 7) {
+ throw new IllegalArgumentException("Can't fully decode "
+ + classOfT.getName() + ", got (" + result.getClass().getName() + "): " + result
+ + "; remaining " + bitQueue.remaining() + " bits: " + bitQueue);
+ }
+ return result;
+ }
+
+
+ public static <T> byte[] extract(byte[] bytes,String path,Class<T> classOfT) throws IllegalArgumentException, UnsupportedOperationException {
+
+ BitBuffer bitQueue = bitBufferFromBinaryString(binaryStringFromBytes(bytes));
+
+ AsnExtractor extractor = new AsnExtractor(path,bitQueue);
+
+ T result = decodeAny(bitQueue, classOfT,null, new Annotation[] {}, extractor);
+ if (bitQueue.remaining() > 7) {
+ throw new IllegalArgumentException("Can't fully decode "
+ + classOfT.getName() + ", got (" + result.getClass().getName() + "): " + result
+ + "; remaining " + bitQueue.remaining() + " bits: " + bitQueue);
+ }
+ return extractor.getResult();
+ }
+
+
+
+
- public static <T> T decode(byte[] bytes, Class<T> classOfT, Field f) throws IllegalArgumentException,
+ public static <T> T decode(byte[] bytes, Class<T> classOfT, Field f,AsnExtractor extractor) throws IllegalArgumentException,
UnsupportedOperationException {
BitBuffer bitQueue = bitBufferFromBinaryString(binaryStringFromBytes(bytes));
- T result = decodeAny(bitQueue, classOfT, f, new Annotation[] {});
+ T result = decodeAny(bitQueue, classOfT, f, new Annotation[] {}, extractor);
if (bitQueue.remaining() > 7) {
throw new IllegalArgumentException("Can't fully decode "
+ classOfT.getName() + ", got (" + result.getClass().getName() + "): " + result
@@ -108,13 +140,13 @@ public final class UperEncoder {
+ " with extra annotations " + Arrays.asList(extraAnnotations));
}
- static <T> T decodeAny(BitBuffer bitbuffer,Class<T> classOfT, Field f, Annotation[] extraAnnotations) {
+ static <T> T decodeAny(BitBuffer bitbuffer,Class<T> classOfT, Field f, Annotation[] extraAnnotations, AsnExtractor extractor) {
logger.debug(String.format(String.format("Decoding classOfT : %s",classOfT.getCanonicalName())));
for (Decoder e : decoders) {
if (e.canDecode(classOfT, extraAnnotations)) {
- return e.decode(bitbuffer, classOfT,f, extraAnnotations);
+ return e.decode(bitbuffer, classOfT,f, extraAnnotations,extractor);
}
}
@@ -216,7 +248,7 @@ public final class UperEncoder {
}
- static <T> T decodeAsOpenType(BitBuffer bitbuffer, Class<T> classOfT,Field f, Annotation[] extraAnnotations) {
+ static <T> T decodeAsOpenType(BitBuffer bitbuffer, Class<T> classOfT,Field f, Annotation[] extraAnnotations,AsnExtractor extractor) {
logger.debug(String.format("OPEN TYPE for %s. Encoding preceedes length determinant", classOfT != null ? classOfT.getName() : "null"));
long numBytes = decodeLengthDeterminant(bitbuffer);
BitBuffer openTypeBitBuffer = ByteBitBuffer.allocate((int)numBytes * 8);
@@ -225,7 +257,7 @@ public final class UperEncoder {
}
openTypeBitBuffer.flip();
if (classOfT != null) {
- T result = decodeAny(openTypeBitBuffer, classOfT, f, extraAnnotations);
+ T result = decodeAny(openTypeBitBuffer, classOfT, f, extraAnnotations, extractor);
// Assert that padding bits are all 0.
logger.debug(String.format("open type had padding bits"));
for (int i = 0; i < openTypeBitBuffer.remaining(); i++) {
diff --git a/src/main/java/org/uic/barcode/dynamicFrame/api/IDynamicFrame.java b/src/main/java/org/uic/barcode/dynamicFrame/api/IDynamicFrame.java
index f357c4d..1e8a0ff 100644
--- a/src/main/java/org/uic/barcode/dynamicFrame/api/IDynamicFrame.java
+++ b/src/main/java/org/uic/barcode/dynamicFrame/api/IDynamicFrame.java
@@ -89,21 +89,23 @@ public interface IDynamicFrame{
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
- * @return the int
+ * @param data the data content
+ * @return the return error code
* @throws EncodingFormatException
*/
- public int validateLevel2() throws EncodingFormatException;
+ public int validateLevel2(byte[] data) throws EncodingFormatException;
/**
* Verify the level 2 signature
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
- * @param prov the prov
- * @return the int
+ * @param prov the registered security provider
+ * @param data the data content
+ * @return the return error code
* @throws EncodingFormatException
*/
- public int validateLevel2(Provider prov) throws EncodingFormatException;
+ public int validateLevel2(Provider prov, byte[] data) throws EncodingFormatException;
/**
* Verify the level 1 signature
@@ -111,23 +113,25 @@ public interface IDynamicFrame{
* Note: an appropriate security provider (e.g. BC) must be registered before
*
* @param key the key
- * @param prov the prov
- * @return the int
+ * @param data the data content
+ * @return the return error code
* @throws EncodingFormatException
*/
- public int validateLevel1(PublicKey key, Provider prov) throws EncodingFormatException;
+ public int validateLevel1(PublicKey key, byte[] data) throws EncodingFormatException;
-
/**
* Verify the level 1 signature
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
* @param key the key
- * @return the int
+ * @param prov the registered security provider
+ * @param the data content
+ * @return the return error code
* @throws EncodingFormatException
*/
- public int validateLevel1(PublicKey key) throws EncodingFormatException;
+ public int validateLevel1(PublicKey key, Provider prov, byte[] data) throws EncodingFormatException;
+
/**
* Sign level 2 data without a specific security provider.
diff --git a/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java b/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java
index 4c5c879..ec52758 100644
--- a/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java
+++ b/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java
@@ -12,6 +12,7 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
+import org.uic.barcode.asn1.uper.AsnUtils;
import org.uic.barcode.dynamicContent.api.DynamicContentCoder;
import org.uic.barcode.dynamicContent.api.IUicDynamicContent;
import org.uic.barcode.dynamicContent.fdc1.UicDynamicContentDataFDC1;
@@ -143,6 +144,22 @@ public class SimpleDynamicFrame implements IDynamicFrame {
return null;
}
+ private byte[] getEncoded(String path, byte[] data) throws EncodingFormatException {
+
+ if (Constants.DYNAMIC_BARCODE_FORMAT_VERSION_1.equals(format)) {
+
+ return DynamicFrameCoderV1.getEncoded(path, data);
+
+ } else if (Constants.DYNAMIC_BARCODE_FORMAT_VERSION_1.equals(format)) {
+
+ return DynamicFrameCoderV2.getEncoded(path, data);
+
+ }
+
+ return null;
+ }
+
+
private byte[] encode(ILevel2Data level2SignedData2) throws EncodingFormatException {
if (Constants.DYNAMIC_BARCODE_FORMAT_VERSION_1.equals(format)) {
@@ -213,9 +230,9 @@ public class SimpleDynamicFrame implements IDynamicFrame {
* @return the int
* @throws EncodingFormatException
*/
- public int validateLevel2() throws EncodingFormatException {
+ public int validateLevel2(byte[] data) throws EncodingFormatException {
- return validateLevel2(null);
+ return validateLevel2(null, data);
}
@@ -224,11 +241,11 @@ public class SimpleDynamicFrame implements IDynamicFrame {
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
- * @param prov the prov
- * @return the int
+ * @param prov the registered security provider
+ * @return the return error code
* @throws EncodingFormatException
*/
- public int validateLevel2(Provider prov) throws EncodingFormatException {
+ public int validateLevel2(Provider prov, byte[] data) throws EncodingFormatException {
String level2KeyAlg = this.getLevel2Data().getLevel1Data().getLevel2KeyAlg();
@@ -244,7 +261,7 @@ public class SimpleDynamicFrame implements IDynamicFrame {
String keyAlgName = null;
try {
- keyAlgName = AlgorithmNameResolver.getName(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, level2KeyAlg);
+ keyAlgName = AlgorithmNameResolver.getName(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, level2KeyAlg,prov);
} catch (Exception e1) {
return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED;
}
@@ -268,7 +285,7 @@ public class SimpleDynamicFrame implements IDynamicFrame {
String sigAlgName = null;
try {
- sigAlgName = AlgorithmNameResolver.getName(AlgorithmNameResolver.TYPE_SIGNATURE_ALG,level2SigAlg);
+ sigAlgName = AlgorithmNameResolver.getName(AlgorithmNameResolver.TYPE_SIGNATURE_ALG,level2SigAlg,prov);
} catch (Exception e1) {
return Constants.LEVEL2_VALIDATION_SIG_ALG_NOT_IMPLEMENTED;
}
@@ -293,8 +310,14 @@ public class SimpleDynamicFrame implements IDynamicFrame {
}
try {
- byte[] data = encode(level2Data);
- sig.update(data);
+ //TODO
+ //byte[] signedData = encode(level2Data);
+ //String s1 = AsnUtils.toBooleanString(signedData);
+
+ byte[] signedData2 = getEncoded("Level2Data", data);
+ //String s2 = AsnUtils.toBooleanString(signedData);
+
+ sig.update(signedData2);
} catch (SignatureException e) {
return Constants.LEVEL2_VALIDATION_SIG_ALG_NOT_IMPLEMENTED;
} catch (IllegalArgumentException e) {
@@ -325,7 +348,7 @@ public class SimpleDynamicFrame implements IDynamicFrame {
* @return the int
* @throws EncodingFormatException
*/
- public int validateLevel1(PublicKey key, Provider prov) throws EncodingFormatException {
+ public int validateLevel1(PublicKey key, Provider prov, byte[] data) throws EncodingFormatException {
if (level2Data == null) {
return Constants.LEVEL1_VALIDATION_NO_SIGNATURE;
@@ -342,7 +365,7 @@ public class SimpleDynamicFrame implements IDynamicFrame {
//find the algorithm name for the signature OID
String algo = null;
try {
- algo = AlgorithmNameResolver.getSignatureAlgorithmName(getLevel2Data().getLevel1Data().getLevel1SigningAlg());
+ algo = AlgorithmNameResolver.getSignatureAlgorithmName(getLevel2Data().getLevel1Data().getLevel1SigningAlg(), prov);
} catch (Exception e1) {
return Constants.LEVEL1_VALIDATION_SIG_ALG_NOT_IMPLEMENTED;
}
@@ -368,7 +391,15 @@ public class SimpleDynamicFrame implements IDynamicFrame {
}
try {
- sig.update(encode(level2Data.getLevel1Data()));
+
+ //byte[] encodedData = encode(level2Data.getLevel1Data());
+ //String s1 = AsnUtils.toBooleanString(encodedData);
+ //TODO
+ byte[] encodedData2 = getEncoded("Level1Data", data);
+ //String s2 = AsnUtils.toBooleanString(encodedData2);
+
+ sig.update(encodedData2);
+
} catch (SignatureException e) {
return Constants.LEVEL1_VALIDATION_SIG_ALG_NOT_IMPLEMENTED;
} catch (IllegalArgumentException e) {
@@ -402,9 +433,9 @@ public class SimpleDynamicFrame implements IDynamicFrame {
* @return the int
* @throws EncodingFormatException
*/
- public int validateLevel1(PublicKey key) throws EncodingFormatException {
+ public int validateLevel1(PublicKey key, byte[] data) throws EncodingFormatException {
- return validateLevel1(key, null);
+ return validateLevel1(key, null,data);
}
@@ -416,13 +447,7 @@ public class SimpleDynamicFrame implements IDynamicFrame {
*/
public void signLevel2(PrivateKey key) throws Exception {
- //find the algorithm name for the signature OID
- String algo = AlgorithmNameResolver.getSignatureAlgorithmName(level2Data.getLevel1Data().getLevel2SigningAlg());
- Signature sig = Signature.getInstance(algo);
- sig.initSign(key);
- byte[] data = encode(level2Data);
- sig.update(data);
- level2Signature = sig.sign();
+ signLevel2(key, null);
}
@@ -430,17 +455,22 @@ public class SimpleDynamicFrame implements IDynamicFrame {
* Sign level 2 data.
*
* @param key the key
- * @param prov the security Provider
+ * @param prov the registered security provider
* @throws Exception the exception
*/
public void signLevel2(PrivateKey key, Provider prov) throws Exception {
//find the algorithm name for the signature OID
- String algo = AlgorithmNameResolver.getSignatureAlgorithmName(this.getLevel2Data().getLevel1Data().getLevel2SigningAlg());
- Signature sig = Signature.getInstance(algo,prov);
+ String algo = AlgorithmNameResolver.getSignatureAlgorithmName(this.getLevel2Data().getLevel1Data().getLevel2SigningAlg(), prov);
+ Signature sig = null;
+ if (prov != null) {
+ sig = Signature.getInstance(algo,prov);
+ } else {
+ sig = Signature.getInstance(algo);
+ }
sig.initSign(key);
- byte[] data = encode(level2Data);
- sig.update(data);
+ byte[] signedData = encode(level2Data);
+ sig.update(signedData);
level2Signature = sig.sign();
}
@@ -453,8 +483,7 @@ public class SimpleDynamicFrame implements IDynamicFrame {
* @throws EncodingFormatException the encoding format exception
*/
public void addDynamicContent(IUicDynamicContent content) throws EncodingFormatException {
-
-
+
level2Data.setLevel2Data(new SimpleData());
level2Data.getLevel2Data().setFormat(DynamicContentCoder.dynamicContentDataFDC1);
@@ -501,19 +530,8 @@ public class SimpleDynamicFrame implements IDynamicFrame {
*/
public void signLevel1(PrivateKey key) throws Exception {
- if (level2Data == null) return;
-
- ILevel1Data level1Data = level2Data.getLevel1Data();
-
- if (level1Data == null) return;
+ signLevel1(key, null);
- //find the algorithm name for the signature OID
- String algo = AlgorithmNameResolver.getSignatureAlgorithmName(level1Data.getLevel1SigningAlg());
- Signature sig = Signature.getInstance(algo);
- sig.initSign(key);
- byte[] data = encode(level1Data);
- sig.update(data);
- level2Data.setLevel1Signature(sig.sign());
}
/**
@@ -538,16 +556,17 @@ public class SimpleDynamicFrame implements IDynamicFrame {
//find the algorithm name for the signature OID
String algo = AlgorithmNameResolver.getSignatureAlgorithmName(level1Data.getLevel1SigningAlg());
- Signature sig = Signature.getInstance(algo, prov);
+ Signature sig = null;
+ if (prov != null) {
+ sig = Signature.getInstance(algo, prov);
+ } else {
+ sig = Signature.getInstance(algo);
+ }
sig.initSign(key);
byte[] data = encode(level1Data);
sig.update(data);
level2Data.setLevel1Signature(sig.sign());
}
-
-
-
-
}
diff --git a/src/main/java/org/uic/barcode/dynamicFrame/v1/DynamicFrameCoderV1.java b/src/main/java/org/uic/barcode/dynamicFrame/v1/DynamicFrameCoderV1.java
index f7b3f3d..1cffa12 100644
--- a/src/main/java/org/uic/barcode/dynamicFrame/v1/DynamicFrameCoderV1.java
+++ b/src/main/java/org/uic/barcode/dynamicFrame/v1/DynamicFrameCoderV1.java
@@ -100,6 +100,19 @@ public class DynamicFrameCoderV1 {
return UperEncoder.encode(asn);
}
+
+ public static byte[] getEncoded(String path, byte[] data) {
+
+ if (path.endsWith("Level1Data")){
+ return UperEncoder.extract(data, "Level1DataType" ,DynamicFrame.class );
+ } else if (path.endsWith("Level2Data")){
+ return UperEncoder.extract(data, "Level2DataType" ,DynamicFrame.class );
+ }
+
+ return null;
+ }
+
+
public static byte[] encode(ILevel2Data level2SignedData) throws EncodingFormatException {
Level2DataType asn = populateAsn(level2SignedData);
@@ -183,6 +196,8 @@ public class DynamicFrameCoderV1 {
return asnLevel1;
}
+
+
diff --git a/src/main/java/org/uic/barcode/dynamicFrame/v2/DynamicFrameCoderV2.java b/src/main/java/org/uic/barcode/dynamicFrame/v2/DynamicFrameCoderV2.java
index 8987f59..bdaa31a 100644
--- a/src/main/java/org/uic/barcode/dynamicFrame/v2/DynamicFrameCoderV2.java
+++ b/src/main/java/org/uic/barcode/dynamicFrame/v2/DynamicFrameCoderV2.java
@@ -197,6 +197,17 @@ public class DynamicFrameCoderV2 {
return asnLevel1;
}
+
+ public static byte[] getEncoded(String path, byte[] data) {
+
+ if (path.endsWith("Level1Data")){
+ return UperEncoder.extract(data, "Level1DataType" ,DynamicFrame.class );
+ } else if (path.endsWith("Level2Data")){
+ return UperEncoder.extract(data, "Level2DataType" ,DynamicFrame.class );
+ }
+
+ return null;
+ }
diff --git a/src/main/java/org/uic/barcode/utils/AlgorithmNameResolver.java b/src/main/java/org/uic/barcode/utils/AlgorithmNameResolver.java
index 4491358..a3154f3 100644
--- a/src/main/java/org/uic/barcode/utils/AlgorithmNameResolver.java
+++ b/src/main/java/org/uic/barcode/utils/AlgorithmNameResolver.java
@@ -24,6 +24,26 @@ public class AlgorithmNameResolver {
}
+ public static String getSignatureAlgorithmName (String oid, Provider provider) throws Exception {
+
+ if (provider != null) {
+ Service service = provider.getService(AlgorithmNameResolver.TYPE_SIGNATURE_ALG,oid);
+ return service.getAlgorithm();
+ }
+
+
+ Provider[] provs = Security.getProviders();
+ for (Provider prov : provs) {
+ Service service = prov.getService(AlgorithmNameResolver.TYPE_SIGNATURE_ALG,oid);
+ if (service != null) {
+ return service.getAlgorithm();
+ }
+ }
+ return null;
+
+ }
+
+
public static String getName (String type, String oid) throws Exception {
Provider[] provs = Security.getProviders();
@@ -45,9 +65,22 @@ public class AlgorithmNameResolver {
}
- public static String getName(String type, String oid, Provider prov) throws Exception {
+ public static String getName(String type, String oid, Provider provider) throws Exception {
+
+ Service service = null;
+ if (provider == null) {
+
+ Provider[] provs = Security.getProviders();
+ for (Provider prov : provs) {
+ service = prov.getService(type,oid);
+ }
+
+ } else {
+ service = provider.getService(type,oid);
+ }
+
- Service service = prov.getService(type,oid);
+
if (service != null) {
return service.getAlgorithm();
}
diff --git a/src/test/java/org/uic/barcode/test/BinaryStringTest.java b/src/test/java/org/uic/barcode/test/BinaryStringTest.java
new file mode 100644
index 0000000..d5533fa
--- /dev/null
+++ b/src/test/java/org/uic/barcode/test/BinaryStringTest.java
@@ -0,0 +1,61 @@
+package org.uic.barcode.test;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.uic.barcode.asn1.uper.AsnUtils;
+import org.uic.barcode.ticket.EncodingFormatException;
+
+public class BinaryStringTest {
+
+
+
+
+ @Test public void testBinaryString() throws IOException, EncodingFormatException{
+
+ String bs1 = "01000000";
+ String ms1 = "1000000001000000001000000001000000001000000001000000001000000001";
+ String ms2 = "10000000010000000010000000010000";
+
+
+ //String bs1 = "1011111100001000011011100000000000000001000000010000010010000000";
+
+ byte[] bytes = AsnUtils.fromBooleanString(bs1);
+
+ String bs2 = AsnUtils.toBooleanString(bytes);
+
+
+
+ byte[] mask = new byte[] {
+ (byte) 0b1000_0000,
+ 0b0100_0000,
+ 0b0010_0000,
+ 0b0001_0000,
+ 0b0000_1000,
+ 0b0000_0100,
+ 0b0000_0010,
+ 0b0000_0001,
+ };
+ String bs3 = AsnUtils.toBooleanString(mask);
+ byte[] bytes2 = AsnUtils.fromBooleanString(bs3);
+
+
+ byte[] mask2 = new byte[] {
+ (byte) 0b1000_0000,
+ 0b0100_0000,
+ 0b0010_0000,
+ 0b0001_0000,
+ };
+ String bs4 = AsnUtils.toBooleanString(mask2);
+ byte[] bytes3 = AsnUtils.fromBooleanString(bs4);
+
+
+ assert(bs4.equals(ms2));
+
+ assert(bs3.equals(ms1));
+
+ assert(bs1.equals(bs2));
+
+ }
+
+
+} \ No newline at end of file
diff --git a/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java b/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java
index 5a70841..4d34c1b 100644
--- a/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java
+++ b/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java
@@ -10,8 +10,6 @@ import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;