diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractBinaryAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractBinaryAdapter.java index 56c15d659..673759bb1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractBinaryAdapter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractBinaryAdapter.java @@ -48,17 +48,41 @@ protected AbstractBinaryAdapter( super(ByteBuffer.class, itemClass, castExecutor); } + /** + * Get the binary decoder to use to decode encoded data. + * + * @return the decoder + */ @NonNull protected abstract BinaryDecoder getDecoder(); + /** + * Get the binary encoder to use to encode data. + * + * @return the encoder + */ @NonNull protected abstract BinaryEncoder getEncoder(); + /** + * Get the raw bytes, encoded as UTF8, for the provided text string. + * + * @param text + * the text string to get the bytes for + * @return the UTF8 encoded bytes for the text string + */ @NonNull private static byte[] stringToBytes(@NonNull String text) { - return text.getBytes(StandardCharsets.UTF_8); + return ObjectUtils.notNull(text.getBytes(StandardCharsets.UTF_8)); } + /** + * Get a text string based on the provided raw bytes, encoded as UTF8. + * + * @param bytes + * a byte array encoded as UTF8 + * @return the decoded text string + */ @NonNull private static String bytesToString(@NonNull byte[] bytes) { return new String(bytes, StandardCharsets.UTF_8); @@ -68,6 +92,14 @@ private static String elide(@NonNull String text, int length) { return text.length() <= length ? text : text.substring(0, length) + "…"; } + /** + * Encode the provided bytes using the encoding supported by this class. + * + * @param decodedBytes + * the bytes to encode + * @return the encoded bytes + * @see #getEncoder() + */ @NonNull public byte[] encode(@NonNull byte[] decodedBytes) { try { @@ -79,24 +111,58 @@ public byte[] encode(@NonNull byte[] decodedBytes) { } } + /** + * Encode the provided bytes using the encoding supported by this class. + * + * @param decodedBuffer + * a buffer containing the bytes to encode + * @return a buffer containing the encoded bytes + * @see #getEncoder() + */ @NonNull public ByteBuffer encodeToByteBuffer(@NonNull ByteBuffer decodedBuffer) { byte[] decodedBytes = bufferToBytes(decodedBuffer, false); return encodeToByteBuffer(decodedBytes); } + /** + * Encode the provided string using the encoding supported by this class. + *
+ * The provided string is first encoded as a stream of UTF8 bytes. + * + * @param decodedText + * the string to encode + * @return a buffer containing the encoded bytes + * @see #getEncoder() + */ @NonNull - public ByteBuffer encodeToByteBuffer(String decodedText) { + public ByteBuffer encodeToByteBuffer(@NonNull String decodedText) { byte[] decodedBytes = stringToBytes(decodedText); return encodeToByteBuffer(decodedBytes); } + /** + * Encode the provided bytes using the encoding supported by this class. + * + * @param decodedBytes + * the bytes to encode + * @return a buffer containing the encoded bytes + * @see #getEncoder() + */ @NonNull - public ByteBuffer encodeToByteBuffer(byte[] decodedBytes) { + public ByteBuffer encodeToByteBuffer(@NonNull byte[] decodedBytes) { byte[] encodedBytes = encode(decodedBytes); return ObjectUtils.notNull(ByteBuffer.wrap(encodedBytes)); } + /** + * Decode the provided bytes using the encoding supported by this class. + * + * @param enodedBytes + * the bytes to decode + * @return the decoded bytes + * @see #getDecoder() + */ @NonNull public byte[] decode(@NonNull byte[] enodedBytes) { try { @@ -108,6 +174,14 @@ public byte[] decode(@NonNull byte[] enodedBytes) { } } + /** + * Decode the provided bytes using the encoding supported by this class. + * + * @param encodedBuffer + * a buffer containing the the bytes to decode + * @return a buffer containing the decoded bytes + * @see #getDecoder() + */ @NonNull public ByteBuffer decode(@NonNull ByteBuffer encodedBuffer) { byte[] encodedBytes = bufferToBytes(encodedBuffer, false); @@ -115,6 +189,16 @@ public ByteBuffer decode(@NonNull ByteBuffer encodedBuffer) { return ObjectUtils.notNull(ByteBuffer.wrap(decodedBytes)); } + /** + * Decode the provided bytes using the encoding supported by this class. + *
+ * The decoded bytes are decoded as a stream of UTF8 bytes to produce the string.
+ *
+ * @param encodedBytes
+ * the bytes to decode
+ * @return the decoded string
+ * @see #getDecoder()
+ */
@NonNull
public String decodeToString(@NonNull byte[] encodedBytes) {
byte[] decodedBytes = decode(encodedBytes);
@@ -169,6 +253,15 @@ public ByteBuffer copy(Object obj) {
return clone;
}
+ /**
+ * Get the array of bytes stored in the buffer.
+ *
+ * @param buffer
+ * the buffer
+ * @param copy
+ * if {@code true} ensure the resulting array is a copy
+ * @return the array of bytes
+ */
@NonNull
public static byte[] bufferToBytes(@NonNull ByteBuffer buffer, boolean copy) {
byte[] array;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpBase64Decode.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpBase64Decode.java
new file mode 100644
index 000000000..90fc35e35
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpBase64Decode.java
@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.function.library;
+
+import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
+import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
+import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
+import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
+import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
+import gov.nist.secauto.metaschema.core.metapath.item.IItem;
+import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBase64BinaryItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
+import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+
+import java.util.List;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * Provides a new Metapath function that decodes provided encoded text using base64.
+ *
+ */
+public final class MpBase64Decode {
+ private static final String NAME = "base64-decode-text";
+
+ @NonNull
+ static final IFunction SIGNATURE_ONE_ARG = IFunction.builder()
+ .name(NAME)
+ .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_EXTENDED)
+ .deterministic()
+ .contextIndependent()
+ .focusIndependent()
+ .argument(IArgument.builder()
+ .name("encodedText")
+ .type(IBase64BinaryItem.type())
+ .one()
+ .build())
+ .returnType(IStringItem.type())
+ .returnOne()
+ .functionHandler(MpBase64Decode::executeOneArg)
+ .build();
+
+ private MpBase64Decode() {
+ // disable construction
+ }
+
+ @SuppressWarnings("unused")
+ @NonNull
+ private static ISequence
+ * The provided string is first encoded as a stream of UTF8 bytes.
+ *
+ * @param text
+ * the string to encode
+ * @return a base64 item representing the encoded data
+ */
+ static IBase64BinaryItem encode(@NonNull String text) {
+ return valueOf(MetaschemaDataTypeProvider.BASE64.encodeToByteBuffer(text));
}
+ /**
+ * Base64 encode the provided bytes.
+ *
+ * @param bytes
+ * the bytes to encode
+ * @return a base64 item representing the encoded data
+ */
@NonNull
static IBase64BinaryItem encode(@NonNull byte[] bytes) {
return valueOf(MetaschemaDataTypeProvider.BASE64.encodeToByteBuffer(bytes));
}
+ /**
+ * Base64 encode the bytes from the provided buffer.
+ *
+ * @param buffer
+ * the bytes to encode
+ * @return a base64 item representing the encoded data
+ */
@NonNull
static IBase64BinaryItem encode(@NonNull ByteBuffer buffer) {
return valueOf(MetaschemaDataTypeProvider.BASE64.encodeToByteBuffer(buffer));
}
+ /**
+ * Base64 decode this item as a new hex binary item.
+ *
+ * @return a new hex binary item containing the decoded bytes
+ */
default IHexBinaryItem decode() {
return IHexBinaryItem.valueOf(MetaschemaDataTypeProvider.BASE64.decode(asByteBuffer()));
}
+ /**
+ * Base64 decode this item as a string.
+ *
+ * @return a new string item containing the decoded text
+ */
default IStringItem decodeAsString() {
return IStringItem.valueOf(MetaschemaDataTypeProvider.BASE64.decodeToString(asBytes()));
}
/**
- * Construct a new base64 byte sequence item using the provided base64 encoded
- * string {@code value}.
+ * Construct a new base64 byte sequence item using the provided base64 encoded string {@code value}.
*
* @param value
* a string representing base64 encoded data
@@ -82,12 +114,11 @@ static IBase64BinaryItem valueOf(@NonNull String value) {
}
/**
- * Construct a new URI base64 encoded byte sequence using the provided
- * {@link ByteBuffer} {@code value}.
+ * Construct a new URI base64 encoded byte sequence using the provided {@link ByteBuffer}
+ * {@code value}.
*
- * The provided buffer will be managed by this instance. Make a copy of the
- * buffer to ensure that the position, limit, and mark of the original are not
- * affect by this.
+ * The provided buffer will be managed by this instance. Make a copy of the buffer to ensure that
+ * the position, limit, and mark of the original are not affect by this.
*
* @param buffer
* a byte buffer
@@ -103,8 +134,7 @@ static IBase64BinaryItem valueOf(@NonNull ByteBuffer buffer) {
*
* @param item
* the item to cast
- * @return the original item if it is already this type, otherwise a new item
- * cast to this type
+ * @return the original item if it is already this type, otherwise a new item cast to this type
* @throws InvalidValueForCastFunctionException
* if the provided {@code item} cannot be cast to this type
*/
@@ -135,8 +165,8 @@ default int compareTo(IAnyAtomicItem item) {
*
* @param item
* the item to compare with this value
- * @return a negative integer, zero, or a positive integer if this value is less
- * than, equal to, or greater than the {@code item}.
+ * @return a negative integer, zero, or a positive integer if this value is less than, equal to, or
+ * greater than the {@code item}.
*/
default int compareTo(@NonNull IBase64BinaryItem item) {
return asByteBuffer().compareTo(item.asByteBuffer());
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64AdapterTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64AdapterTest.java
new file mode 100644
index 000000000..f23d66826
--- /dev/null
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64AdapterTest.java
@@ -0,0 +1,61 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.datatype.adapter;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.nio.ByteBuffer;
+import java.util.stream.Stream;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+class Base64AdapterTest {
+ private static Stream