package com.hwlcn.ldap.ldap.matchingrules; import com.hwlcn.ldap.asn1.ASN1OctetString; import com.hwlcn.ldap.ldap.sdk.LDAPException; import com.hwlcn.ldap.ldap.sdk.ResultCode; import com.hwlcn.core.annotation.ThreadSafety; import com.hwlcn.ldap.util.ThreadSafetyLevel; import static com.hwlcn.ldap.ldap.matchingrules.MatchingRuleMessages.*; import static com.hwlcn.ldap.util.StaticUtils.*; @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) public final class IntegerMatchingRule extends MatchingRule { private static final IntegerMatchingRule INSTANCE = new IntegerMatchingRule(); public static final String EQUALITY_RULE_NAME = "integerMatch"; static final String LOWER_EQUALITY_RULE_NAME = toLowerCase(EQUALITY_RULE_NAME); public static final String EQUALITY_RULE_OID = "2.5.13.14"; public static final String ORDERING_RULE_NAME = "integerOrderingMatch"; static final String LOWER_ORDERING_RULE_NAME = toLowerCase(ORDERING_RULE_NAME); public static final String ORDERING_RULE_OID = "2.5.13.15"; private static final long serialVersionUID = -9056942146971528818L; public IntegerMatchingRule() { } public static IntegerMatchingRule getInstance() { return INSTANCE; } @Override() public String getEqualityMatchingRuleName() { return EQUALITY_RULE_NAME; } @Override() public String getEqualityMatchingRuleOID() { return EQUALITY_RULE_OID; } @Override() public String getOrderingMatchingRuleName() { return ORDERING_RULE_NAME; } @Override() public String getOrderingMatchingRuleOID() { return ORDERING_RULE_OID; } @Override() public String getSubstringMatchingRuleName() { return null; } @Override() public String getSubstringMatchingRuleOID() { return null; } @Override() public boolean valuesMatch(final ASN1OctetString value1, final ASN1OctetString value2) throws LDAPException { return normalize(value1).equals(normalize(value2)); } @Override() public boolean matchesSubstring(final ASN1OctetString value, final ASN1OctetString subInitial, final ASN1OctetString[] subAny, final ASN1OctetString subFinal) throws LDAPException { throw new LDAPException(ResultCode.INAPPROPRIATE_MATCHING, ERR_INTEGER_SUBSTRING_MATCHING_NOT_SUPPORTED.get()); } @Override() public int compareValues(final ASN1OctetString value1, final ASN1OctetString value2) throws LDAPException { final byte[] norm1Bytes = normalize(value1).getValue(); final byte[] norm2Bytes = normalize(value2).getValue(); if (norm1Bytes[0] == '-') { if (norm2Bytes[0] == '-') { if (norm1Bytes.length < norm2Bytes.length) { return 1; } else if (norm1Bytes.length > norm2Bytes.length) { return -1; } else { for (int i=1; i < norm1Bytes.length; i++) { final int difference = norm2Bytes[i] - norm1Bytes[i]; if (difference != 0) { return difference; } } return 0; } } else { return -1; } } else { if (norm2Bytes[0] == '-') { return 1; } else { if (norm1Bytes.length < norm2Bytes.length) { return -1; } else if (norm1Bytes.length > norm2Bytes.length) { return 1; } else { for (int i=0; i < norm1Bytes.length; i++) { final int difference = norm1Bytes[i] - norm2Bytes[i]; if (difference != 0) { return difference; } } return 0; } } } } @Override() public ASN1OctetString normalize(final ASN1OctetString value) throws LDAPException { final byte[] valueBytes = value.getValue(); if (valueBytes.length == 0) { throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_ZERO_LENGTH_NOT_ALLOWED.get()); } if ((valueBytes[0] == ' ') || (valueBytes[valueBytes.length-1] == ' ')) { final String valueStr = value.stringValue().trim(); if (valueStr.length() == 0) { throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_ZERO_LENGTH_NOT_ALLOWED.get()); } for (int i=0; i < valueStr.length(); i++) { switch (valueStr.charAt(i)) { case '-': if ((i != 0) || (valueStr.length() == 1)) { throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_INVALID_CHARACTER.get()); } break; case '0': if (((i == 0) && (valueStr.length() > 1)) || ((i == 1) && (valueStr.charAt(0) == '-'))) { throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_INVALID_LEADING_ZERO.get()); } break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // These are always acceptable. break; default: throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_INVALID_CHARACTER.get(i)); } } return new ASN1OctetString(valueStr); } for (int i=0; i < valueBytes.length; i++) { switch (valueBytes[i]) { case '-': if ((i != 0) || (valueBytes.length == 1)) { throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_INVALID_CHARACTER.get()); } break; case '0': if (((i == 0) && (valueBytes.length > 1)) || ((i == 1) && (valueBytes[0] == '-'))) { throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_INVALID_LEADING_ZERO.get()); } break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, ERR_INTEGER_INVALID_CHARACTER.get(i)); } } return value; } @Override() public ASN1OctetString normalizeSubstring(final ASN1OctetString value, final byte substringType) throws LDAPException { throw new LDAPException(ResultCode.INAPPROPRIATE_MATCHING, ERR_INTEGER_SUBSTRING_MATCHING_NOT_SUPPORTED.get()); } }