Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2021-2022 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2021-2022 Ping Identity Corporation
*
* Licensed 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.
*/
/*
* Copyright (C) 2021-2022 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldif;
import java.io.Serializable;
import com.unboundid.util.ByteString;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
/**
* This class defines a set of properties that can be used to indicate which
* types of optional base64-encoding should be performed by the LDAP SDK.
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class Base64EncodingStrategy
implements Serializable
{
/**
* A base64-encoding strategy that represents a safe default configuration.
* This includes:
*
*
* The presence of ASCII control characters will cause a value to be
* base64-encoded. This is not required by the LDIF specification, but is
* recommended.
*
*
* The presence of any non-ASCII characters (whether they may be
* displayable or not) will cause a value to be base64-encoded as required
* by the LDIF specification.
*
*
* The presence of non-UTF-8 data will cause a value to be base64-encoded
* as required by the LDIF specification.
*
*
*/
@NotNull public static final Base64EncodingStrategy DEFAULT =
new Base64EncodingStrategy(true, true, true, true);
/**
* A base64-encoding strategy that indicates that the LDAP SDK should perform
* the minimum amount of encoding required by the specification. The presence
* of ASCII control characters (other than NUL, LF, and CR, which must always
* be base64-encoded) will not cause values to be encoded. However, the
* presence of any non-ASCII characters or non-UTF-8 data will cause a value
* to be base64-=encoded as required by the LDIF specification.
*/
@NotNull public static final Base64EncodingStrategy MINIMAL_COMPLIANT =
new Base64EncodingStrategy(false, true, true, true);
/**
* A base64-encoding strategy that indicates that the presence of non-ASCII
* characters that the LDAP SDK considers displayable should not cause a
* value to be encoded. ASCII control characters, non-displayable non-ASCII
* characters, and non-UTF-8 data will cause a value to be base64-encoded.
* Note that this NOT compliant with the LDIF specification (which technically
* requires base64 encoding for all non-ASCII data), but it may be user
* friendly in some cases.
*/
@NotNull public static final Base64EncodingStrategy
USER_FRIENDLY_NON_COMPLIANT =
new Base64EncodingStrategy(true, false, true, true);
/**
* A base64-encoding strategy that indicates that the LDAP SDK should perform
* the maximum amount of base64 encoding that it considers necessary. Any
* ASCII control characters, any non-ASCII data, and any non-UTF-8 data will
* cause a value to be base64 encoded. This is equivalent to the
* {@link #DEFAULT} strategy.
*/
@NotNull public static final Base64EncodingStrategy MAXIMAL = DEFAULT;
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = -5787811215448347345L;
// Indicates whether the presence of one or more ASCII control characters
// should cause a value to be base64-encoded.
private final boolean encodeASCIIControlCharacters;
// Indicates whether the presence of one or more displayable non-ASCII
// characters should cause a value to be base64-encoded.
private final boolean encodeDisplayableNonASCIICharacters;
// Indicates whether the presence of one or more non-displayable non-ASCII
// characters should cause a value to be base64-encoded.
private final boolean encodeNonDisplayableNonASCIICharacters;
// Indicates whether values that do not represent valid UTF-8 strings should
// be base64-encoded.
private final boolean encodeNonUTF8Data;
/**
* Creates a new base64 encoding strategy with the specified settings.
*
* @param encodeASCIIControlCharacters
* Indicates whether the presence of one or more ASCII control
* characters (characters whose Unicode code point is less than
* or equal to 0x01F, or is equal to 0x7F) should cause a value
* to be base64-encoded. Note that as per RFC 2849, the presence
* of the null (0x00), line feed (0x0A), and carriage return
* (0x0D) ASCII control characters will always cause a value to
* be base64-encoded.
* @param encodeDisplayableNonASCIICharacters
* Indicates whether the presence of one or more non-ASCII
* characters (characters whose Unicode code point is greater
* than 0x7F) that are believed to be displayable (as determined
* by the {@link StaticUtils#isLikelyDisplayableCharacter}
* method) should cause a value to be base64-encoded.
* @param encodeNonDisplayableNonASCIICharacters
* Indicates whether the presence of one or more non-ASCII
* characters (characters whose Unicode code point is greater
* than 0x7F) that are not believed to be displayable (as
* determined by the
* {@link StaticUtils#isLikelyDisplayableCharacter} method)
* should cause a value to be base64-encoded.
* @param encodeNonUTF8Data
* Indicates whether non-UTF-8-encoded data should be
* base64-encoded. Note that if a value does not represent a
* valid UTF-8 string, then the
* {@code encodeDisplayableNonASCIICharacters} and
* {@code encodeNonDisplayableNonASCIICharacters} arguments will
* not be used.
*/
public Base64EncodingStrategy(final boolean encodeASCIIControlCharacters,
final boolean encodeDisplayableNonASCIICharacters,
final boolean encodeNonDisplayableNonASCIICharacters,
final boolean encodeNonUTF8Data)
{
this.encodeASCIIControlCharacters = encodeASCIIControlCharacters;
this.encodeDisplayableNonASCIICharacters =
encodeDisplayableNonASCIICharacters;
this.encodeNonDisplayableNonASCIICharacters =
encodeNonDisplayableNonASCIICharacters;
this.encodeNonUTF8Data = encodeNonUTF8Data;
}
/**
* Indicates whether the presence of one or more ASCII control characters
* should cause a value to be base64-encoded. ASCII control characters other
* than NUL, LF, and CR are not required to be base64-encoded by the LDIF
* specification, but it is generally recommended that they be encoded.
*
* @return {@code true} if the presence of one or more ASCII control
* characters should cause a value to be base64-encoded, or
* {@code false} if not.
*/
public boolean encodeASCIIControlCharacters()
{
return encodeASCIIControlCharacters;
}
/**
* Indicates whether the presence of one or more displayable non-ASCII
* characters (as determined by the
* {@link StaticUtils#isLikelyDisplayableCharacter} method) should cause a
* value to be base64-encoded. Note that this only applies to values that
* represent valid UTF-8 strings. Values that are not valid UTF-8 strings
* will use the setting represented by the {@link #encodeNonUTF8Data} method.
* Also note that all non-ASCII characters are required to be base64 encoded
* by the LDIF specification, but there may be cases in which it may be
* desirable to relax this behavior when displaying to an end user.
*
* @return {@code true} if the presence of one or more displayable
* non-ASCII characters should cause a value to be base64-encoded,
* or {@code false} if not.
*/
public boolean encodeDisplayableNonASCIICharacters()
{
return encodeDisplayableNonASCIICharacters;
}
/**
* Indicates whether the presence of one or more non-displayable non-ASCII
* characters (as determined by the
* {@link StaticUtils#isLikelyDisplayableCharacter} method) should cause a
* value to be base64-encoded. Note that this only applies to values that
* represent valid UTF-8 strings. Values that are not valid UTF-8 strings
* will use the setting represented by the {@link #encodeNonUTF8Data} method.
* Also note that all non-ASCII characters are required to be base64 encoded
* by the LDIF specification, but there may be cases in which it may be
* desirable to relax this behavior when displaying to an end user.
*
* @return {@code true} if the presence of one or more non-displayable
* non-ASCII characters should cause a value to be base64-encoded,
* or {@code false} if not.
*/
public boolean encodeNonDisplayableNonASCIICharacters()
{
return encodeNonDisplayableNonASCIICharacters;
}
/**
* Indicates whether values that do not represent valid UTF-8 strings (as
* determined by the {@link StaticUtils#isValidUTF8} method) should be
* base64-encoded. Note that all non-ASCII data (which includes all non-UTF-8
* data) is required to be base64 encoded, but there may be cases in which it
* may be desirable to relax this behavior when displaying to an end user,
* especially when using non-UTF-8 character sets.
*
* @return {@code true} if values that do not represent valid UTF-8 strings
* should be base64-encoded, or {@code false} if not.
*/
public boolean encodeNonUTF8Data()
{
return encodeNonUTF8Data;
}
/**
* Indicates whether the provided value should be base64-encoded in accordance
* with this strategy.
*
* @param value The value for which to make the determination. It must not
* be {@code null}.
*
* @return {@code true} if the provided value should be base64-encoded in
* accordance with this strategy, or {@code false} if not.
*/
public boolean shouldBase64Encode(@NotNull final byte[] value)
{
// If the value is empty, then it does not need to be encoded.
if ((value == null) || (value.length == 0))
{
return false;
}
// If the value starts with a space, colon, or less-than character, then it
// must be base64-encoded.
switch (value[0])
{
case ' ':
case ':':
case '<':
return true;
}
// If the value ends with a space, then it must be base64-encoded.
if (value[value.length - 1] == ' ')
{
return true;
}
// Examine all the bytes that make up the value. If we encounter any
// non-ASCII characters, then handle that specially.
for (int i=0; i < value.length; i++)
{
// Bytes that are between 0x00 and 0x1F are ASCII control characters. The
// null (0x00), line feed (0x0A) and carriage return (0x0D) characters
// must always base base64-encoded. For other bytes, use the
// encodeASCIIControlCharacters flag.
final byte b = value[i];
if ((b >= 0x00) && (b <= 0x1F))
{
switch (b)
{
case 0x00:
case 0x0A:
case 0x0D:
return true;
default:
if (encodeASCIIControlCharacters)
{
return true;
}
break;
}
}
// Byte 0x7F is the ASCII delete control character and should also be
// controlled by the encodeASCIIControlCharacters flag.
else if (b == 0x07F)
{
if (encodeASCIIControlCharacters)
{
return true;
}
}
// All bytes between 0x20 and 0x7E (inclusive) should be fine. All other
// bytes will have the most significant bit set, and because Java bytes
// are signed, they will be negative. If we encounter any negative bytes,
// then that means the value contains non-ASCII characters or doesn't
// represent a UTF-8 string. If it's not valid UTF-8, then we'll handle
// it in accordance with the encodeNonUTF8Data flag. Otherwise, we'll
// convert the remainder of the byte to a string and iterate across the
// code points for the rest of the determination.
else if (b < 0x00)
{
final byte[] remainingBytes = new byte[value.length - i];
System.arraycopy(value, i, remainingBytes, 0, remainingBytes.length);
if (StaticUtils.isValidUTF8(remainingBytes))
{
final String valueString = StaticUtils.toUTF8String(remainingBytes);
return shouldBase64EncodePreValidatedString(valueString);
}
else
{
return encodeNonUTF8Data;
}
}
}
// If we've gotten here, then the value does not need to be base64-encoded.
return false;
}
/**
* Indicates whether the provided value should be base64-encoded in accordance
* with this strategy.
*
* @param value The value for which to make the determination. It must not
* be {@code null}.
*
* @return {@code true} if the provided value should be base64-encoded in
* accordance with this strategy, or {@code false} if not.
*/
public boolean shouldBase64Encode(@NotNull final String value)
{
// If the value is empty, then it does not need to be encoded.
if ((value == null) || (value.length() == 0))
{
return false;
}
// If the value starts with a space, colon, or less-than character, then it
// must be base64-encoded.
switch (value.charAt(0))
{
case ' ':
case ':':
case '<':
return true;
}
// If the value ends with a space, then it must be base64-encoded.
if (value.charAt(value.length() - 1) == ' ')
{
return true;
}
// Examine all of the characters in the string as code points so that we can
// handle non-ASCII characters properly.
return shouldBase64EncodePreValidatedString(value);
}
/**
* Indicates whether the provided string should be base64-encoded in
* accordance with this strategy. Note that all of the appropriate first and
* last character validation must have already been performed.
*
* @param s The string to validate. It must not be {@code null}.
*
* @return {@code true} if the value should be base64-encoded in accordance
* with this strategry, or {@code false} if not.
*/
private boolean shouldBase64EncodePreValidatedString(@NotNull final String s)
{
int pos = 0;
while (pos < s.length())
{
final int codePoint = s.codePointAt(pos);
// Code points that are between 0x00 and 0x1F are ASCII control
// characters. The null (0x00), line feed (0x0A), and carriage return
// (0x0D) characters must always be base64-encoded. For other bytes, use
// the encodeASCIIControlCharacters flag.
//
// Note that code points will never be negative, so we don't have to check
// for a lower bound.
if (codePoint <=0x1F)
{
switch (codePoint)
{
case 0x00:
case 0x0A:
case 0x0D:
return true;
default:
if (encodeASCIIControlCharacters)
{
return true;
}
break;
}
}
// Code point 0x7F is the ASCII delete control character and should also
// be controlled by the encodeASCIIControlCharacters flag.
else if (codePoint == 0x7F)
{
if (encodeASCIIControlCharacters)
{
return true;
}
}
// If the code point is greater than 0x7F, then it's a non-ASCII character
// and the behavior should be controlled by either the
// encodeDisplayableNonASCIICharacters or
// encodeNonDisplayableNonASCIICharacters flag, whichever is appropriate.
else if (codePoint > 0x7F)
{
if (StaticUtils.isLikelyDisplayableCharacter(codePoint))
{
if (encodeDisplayableNonASCIICharacters)
{
return true;
}
}
else
{
if (encodeNonDisplayableNonASCIICharacters)
{
return true;
}
}
}
// Increment the position index based on the number of characters in the
// code point. Some code points may require multiple characters to
// represent.
final int charsPerCodePoint = Character.charCount(codePoint);
pos += charsPerCodePoint;
}
// If we've gotten here, then the value does not need to be base64-encoded.
return false;
}
/**
* Indicates whether the provided value should be base64-encoded in accordance
* with this strategy.
*
* @param value The value for which to make the determination. It must not
* be {@code null}.
*
* @return {@code true} if the provided value should be base64-encoded in
* accordance with this strategy, or {@code false} if not.
*/
public boolean shouldBase64Encode(@NotNull final ByteString value)
{
return shouldBase64Encode(value.getValue());
}
/**
* Retrieves a string representation of this base64 encoding strategy.
*
* @return A string representation of this base64 encoding strategy.
*/
@Override()
@NotNull()
public String toString()
{
final StringBuilder buffer = new StringBuilder();
toString(buffer);
return buffer.toString();
}
/**
* Appends a string representation of this base64 encoding strategy to the
* provided buffer.
*
* @param buffer The buffer to which the string representation should be
* appended.
*/
public void toString(@NotNull final StringBuilder buffer)
{
buffer.append("Base64EncodingStrategy(encodeASCIIControlCharacters=");
buffer.append(encodeASCIIControlCharacters);
buffer.append(", encodeDisplayableNonASCIICharacters=");
buffer.append(encodeDisplayableNonASCIICharacters);
buffer.append(", encodeNonDisplayableNonASCIICharacters=");
buffer.append(encodeNonDisplayableNonASCIICharacters);
buffer.append(", encodeNonUTF8Data=");
buffer.append(encodeNonUTF8Data);
buffer.append(')');
}
}