Repository: olingo-odata4 Updated Branches: refs/heads/master 9ef6863ca -> b01b78447
[OLINGO-391] Proved working on Android: needed also to get rid of StringUtils and few other Base64 methods Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/b01b7844 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/b01b7844 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/b01b7844 Branch: refs/heads/master Commit: b01b78447787758905e6c120f098d04311c2db94 Parents: 9ef6863 Author: Francesco Chicchiriccò <--global> Authored: Fri Aug 1 10:54:19 2014 +0200 Committer: Francesco Chicchiriccò <--global> Committed: Fri Aug 1 10:54:19 2014 +0200 ---------------------------------------------------------------------- .../core/edm/primitivetype/EdmBinary.java | 130 +++++++++++++++---- 1 file changed, 105 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b01b7844/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java ---------------------------------------------------------------------- diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java index 2f78745..4c1be32 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java @@ -18,8 +18,8 @@ */ package org.apache.olingo.commons.core.edm.primitivetype; +import java.nio.charset.Charset; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.StringUtils; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; /** @@ -27,6 +27,38 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; */ public class EdmBinary extends SingletonPrimitiveType { + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + /** + * Byte used to pad output. + * + * <b>NOTE</b>: this is provided here from Commons Codec for Android compatibility. + */ + private static final byte PAD_DEFAULT = '='; + + /** + * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in + * Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 alphabet + * but fall within the bounds of the array are translated to -1. + * + * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both + * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit). + * + * Thanks to "commons" project in ws.apache.org for this code. + * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ + * + * <b>NOTE</b>: this is provided here from Commons Codec for Android compatibility. + */ + private static final byte[] DECODE_TABLE = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; + private static final EdmBinary INSTANCE = new EdmBinary(); { @@ -43,23 +75,75 @@ public class EdmBinary extends SingletonPrimitiveType { return byte[].class; } + /** + * Checks if a byte value is whitespace or not. Whitespace is taken to mean: space, tab, CR, LF + * <br/> + * <b>NOTE</b>: this method is provided here from Commons Codec for Android compatibility. + * + * @param byteToCheck the byte to check + * @return true if byte is whitespace, false otherwise + */ + private static boolean isWhiteSpace(final byte byteToCheck) { + switch (byteToCheck) { + case ' ': + case '\n': + case '\r': + case '\t': + return true; + default: + return false; + } + } + + /** + * Returns whether or not the <code>octet</code> is in the base 64 alphabet. + * <br/> + * <b>NOTE</b>: this method is provided here from Commons Codec for Android compatibility. + * + * @param octet The value to test + * @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise. + * @since 1.4 + */ + private static boolean isBase64(final byte octet) { + return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); + } + + /** + * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the + * method treats whitespace as valid. + * <br/> + * <b>NOTE</b>: this method is provided here from Commons Codec for Android compatibility. + * + * @param arrayOctet byte array to test + * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; + * {@code false}, otherwise + */ + private static boolean isBase64(final byte[] arrayOctet) { + for (int i = 0; i < arrayOctet.length; i++) { + if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) { + return false; + } + } + return true; + } + @Override public boolean validate(final String value, - final Boolean isNullable, final Integer maxLength, final Integer precision, - final Integer scale, final Boolean isUnicode) { + final Boolean isNullable, final Integer maxLength, final Integer precision, + final Integer scale, final Boolean isUnicode) { return value == null - ? isNullable == null || isNullable - : Base64.isBase64(value) && validateMaxLength(value, maxLength); + ? isNullable == null || isNullable + : isBase64(value.getBytes(UTF_8)) && validateMaxLength(value, maxLength); } private static boolean validateMaxLength(final String value, final Integer maxLength) { - return maxLength == null ? true : - // Every three bytes are represented as four base-64 characters. - // Additionally, there could be up to two padding "=" characters - // if the number of bytes is not a multiple of three, - // and there could be line feeds, possibly with carriage returns. - maxLength >= (value.length() - lineEndingsLength(value)) * 3 / 4 + return maxLength == null ? true + : // Every three bytes are represented as four base-64 characters. + // Additionally, there could be up to two padding "=" characters + // if the number of bytes is not a multiple of three, + // and there could be line feeds, possibly with carriage returns. + maxLength >= (value.length() - lineEndingsLength(value)) * 3 / 4 - (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0); } @@ -75,18 +159,18 @@ public class EdmBinary extends SingletonPrimitiveType { @Override protected <T> T internalValueOfString(final String value, - final Boolean isNullable, final Integer maxLength, final Integer precision, - final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException { + final Boolean isNullable, final Integer maxLength, final Integer precision, + final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException { - if (!Base64.isBase64(value)) { + if (value == null || !isBase64(value.getBytes(UTF_8))) { throw new EdmPrimitiveTypeException("EdmPrimitiveTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value)"); } if (!validateMaxLength(value, maxLength)) { throw new EdmPrimitiveTypeException( - "EdmPrimitiveTypeException.LITERAL_FACETS_NOT_MATCHED.addContent(value, facets)"); + "EdmPrimitiveTypeException.LITERAL_FACETS_NOT_MATCHED.addContent(value, facets)"); } - final byte[] result = Base64.decodeBase64(value); + final byte[] result = Base64.decodeBase64(value.getBytes(UTF_8)); if (returnType.isAssignableFrom(byte[].class)) { return returnType.cast(result); @@ -103,8 +187,8 @@ public class EdmBinary extends SingletonPrimitiveType { @Override protected <T> String internalValueToString(final T value, - final Boolean isNullable, final Integer maxLength, final Integer precision, - final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException { + final Boolean isNullable, final Integer maxLength, final Integer precision, + final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException { byte[] byteArrayValue; if (value instanceof byte[]) { @@ -117,18 +201,14 @@ public class EdmBinary extends SingletonPrimitiveType { } } else { throw new EdmPrimitiveTypeException( - "EdmPrimitiveTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(value.getClass())"); + "EdmPrimitiveTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(value.getClass())"); } if (maxLength != null && byteArrayValue.length > maxLength) { throw new EdmPrimitiveTypeException( - "EdmPrimitiveTypeException.VALUE_FACETS_NOT_MATCHED.addContent(value, facets)"); + "EdmPrimitiveTypeException.VALUE_FACETS_NOT_MATCHED.addContent(value, facets)"); } - return base64EncodeToString(byteArrayValue); - } - - private static String base64EncodeToString(final byte[] bytes) { - return StringUtils.newStringUtf8(Base64.encodeBase64(bytes, false)); + return new String(Base64.encodeBase64(byteArrayValue, false), UTF_8); } }
