diff -aurN incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/ldap/UnsolicitedNotificationEvent.java ../harmony/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/ldap/UnsolicitedNotificationEvent.java
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/ldap/UnsolicitedNotificationEvent.java 2006-10-03 10:45:02.000000000 -0300
+++ ../harmony/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/ldap/UnsolicitedNotificationEvent.java 2006-10-03 11:02:37.000000000 -0300
@@ -1,62 +1,104 @@
-/*
- * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
- *
- * 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
- *
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ * 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.
*/
+
package javax.naming.ldap;
import java.util.EventObject;
-import javax.naming.ldap.UnsolicitedNotificationListener;
-import javax.naming.ldap.UnsolicitedNotification;
-
/**
+ * This event is fired when an LDAP server sends an unsolited notification.
+ * (See RFC2251).
*
- * @ar.org.fitc.spec_ref
*
- * @version 0.0.1
- *
*/
public class UnsolicitedNotificationEvent extends EventObject {
- private static final long serialVersionUID = -2382603380799883705L;
-
- private UnsolicitedNotification notice;
+ /*
+ * -------------------------------------------------------------------
+ * Constants
+ * -------------------------------------------------------------------
+ */
+
+ /*
+ * This constant is used during deserialization to check the J2SE version
+ * which created the serialized object.
+ */
+ static final long serialVersionUID = -2382603380799883705L; //J2SE 1.4.2
+
+ /*
+ * -------------------------------------------------------------------
+ * Instance variables
+ * -------------------------------------------------------------------
+ */
/**
- * @ar.org.fitc.spec_ref
+ * The specific notification.
+ *
+ * @serial
+ */
+ private UnsolicitedNotification notice;
+
+ /*
+ * -------------------------------------------------------------------
+ * Constructors
+ * -------------------------------------------------------------------
*/
- public UnsolicitedNotificationEvent (Object src, UnsolicitedNotification notice) {
- super(src);
- if (notice == null) {
- throw new IllegalArgumentException("notice is null");
- }
- this.notice = notice;
+
+ /**
+ * Constructs an UnsolicitedNotificationEvent instance using
+ * the supplied UnsolicitedNotification instance.
+ *
+ * @param o the source of the event which cannot be null
+ * @param un the UnsolicitedNotification instance which
+ * cannot be null
+ */
+ public UnsolicitedNotificationEvent(Object o, UnsolicitedNotification un) {
+ super(o);
+ this.notice = un;
}
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
/**
- * @ar.org.fitc.spec_ref
+ * Returns the UnsolicitedNotification instance associated with
+ * this event.
+ *
+ * @return the UnsolicitedNotification instance associated
+ * with this event
*/
- public UnsolicitedNotification getNotification () {
+ public UnsolicitedNotification getNotification() {
return notice;
}
-
+
/**
- * @ar.org.fitc.spec_ref
+ * Uses this event to trigger a notification received on the supplied
+ * listener.
+ *
+ * @param unl the listener to dispatch this event to. It cannot be null.
*/
- public void dispatch (UnsolicitedNotificationListener listener) {
- listener.notificationReceived(this);
+ public void dispatch(UnsolicitedNotificationListener unl) {
+ unl.notificationReceived(this);
}
}
+
+
diff -aurN incubator/harmony/enhanced/classlib/trunk/modules/security/src/java/common/org/apache/harmony/security/x509/DNParser.java ../harmony/incubator/harmony/enhanced/classlib/trunk/modules/security/src/java/common/org/apache/harmony/security/x509/DNParser.java
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/java/common/org/apache/harmony/security/x509/DNParser.java 1969-12-31 21:00:00.000000000 -0300
+++ ../harmony/incubator/harmony/enhanced/classlib/trunk/modules/security/src/java/common/org/apache/harmony/security/x509/DNParser.java 2006-10-03 12:01:08.000000000 -0300
@@ -0,0 +1,466 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+* @author Alexander V. Esin, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+import org.apache.harmony.security.x501.AttributeValue;
+
+
+/**
+ * Distinguished Name Parser.
+ *
+ * Parses a distinguished name(DN) string according
+ * BNF syntax specified in RFC 2253 and RFC 1779
+ *
+ * RFC 2253: Lightweight Directory Access Protocol (v3):
+ * UTF-8 String Representation of Distinguished Names
+ * http://www.ietf.org/rfc/rfc2253.txt
+ *
+ * RFC 1779: A String Representation of Distinguished Names
+ * http://www.ietf.org/rfc/rfc1779.txt
+ */
+public class DNParser {
+
+ // length of distinguished name string
+ private final int length;
+
+ // tmp vars to store positions of the currently parsed item
+ private int pos, beg, end, cur;
+
+ // distinguished name chars
+ private char[] chars;
+
+ // raw string contains '"' or '\'
+ private boolean hasQE;
+
+ // DER encoding of currently parsed item
+ private byte[] encoded;
+
+ /**
+ * Constructs DN parser
+ *
+ * @param dn - distinguished name string to be parsed
+ */
+ public DNParser(String dn) throws IOException {
+ this.length = dn.length();
+ chars = dn.toCharArray();
+ }
+
+ // gets next attribute type: (ALPHA 1*keychar) / oid
+ private String nextAT() throws IOException {
+
+ hasQE = false; // reset
+
+ // skip preceding space chars, they can present after
+ // comma or semicolon (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+ if (pos == length) {
+ return null; // reached the end of DN
+ }
+
+ // mark the beginning of attribute type
+ beg = pos;
+
+ // attribute type chars
+ pos++;
+ for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
+ // we don't follow exact BNF syntax here:
+ // accept any char except space and '='
+ }
+ if (pos >= length) {
+ // unexpected end of DN
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ // mark the end of attribute type
+ end = pos;
+
+ // skip trailing space chars between attribute type and '='
+ // (compatibility with RFC 1779)
+ if (chars[pos] == ' ') {
+ for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
+ }
+
+ if (chars[pos] != '=' || pos == length) {
+ // unexpected end of DN
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+ }
+
+ pos++; //skip '=' char
+
+ // skip space chars between '=' and attribute value
+ // (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+
+ // in case of oid attribute type skip its prefix: "oid." or "OID."
+ // (compatibility with RFC 1779)
+ if ((end - beg > 4) && (chars[beg + 3] == '.')
+ && (chars[beg] == 'O' || chars[beg] == 'o')
+ && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
+ && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
+ beg += 4;
+ }
+
+ return new String(chars, beg, end - beg);
+ }
+
+ // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
+ private String quotedAV() throws IOException {
+
+ pos++;
+ beg = pos;
+ end = beg;
+ while (true) {
+
+ if (pos == length) {
+ // unexpected end of DN
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ if (chars[pos] == '"') {
+ // enclosing quotation was found
+ pos++;
+ break;
+ } else if (chars[pos] == '\\') {
+ chars[end] = getEscaped();
+ } else {
+ // shift char: required for string with escaped chars
+ chars[end] = chars[pos];
+ }
+ pos++;
+ end++;
+ }
+
+ // skip trailing space chars before comma or semicolon.
+ // (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+
+ return new String(chars, beg, end - beg);
+ }
+
+ // gets hex string attribute value: "#" hexstring
+ private String hexAV() throws IOException {
+
+ if (pos + 4 >= length) {
+ // encoded byte array must be not less then 4 c
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ beg = pos; // store '#' position
+ pos++;
+ while (true) {
+
+ // check for end of attribute value
+ // looks for space and component separators
+ if (pos == length || chars[pos] == '+' || chars[pos] == ','
+ || chars[pos] == ';') {
+ end = pos;
+ break;
+ }
+
+ if (chars[pos] == ' ') {
+ end = pos;
+ pos++;
+ // skip trailing space chars before comma or semicolon.
+ // (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+ break;
+ } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
+ chars[pos] += 32; //to low case
+ }
+
+ pos++;
+ }
+
+ // verify length of hex string
+ // encoded byte array must be not less then 4 and must be even number
+ int hexLen = end - beg; // skip first '#' char
+ if (hexLen < 5 || (hexLen & 1) == 0) {
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ // get byte encoding from string representation
+ encoded = new byte[hexLen / 2];
+ for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
+ encoded[i] = (byte) getByte(p);
+ }
+
+ return new String(chars, beg, hexLen);
+ }
+
+ // gets string attribute value: *( stringchar / pair )
+ private String escapedAV() throws IOException {
+
+ beg = pos;
+ end = pos;
+ while (true) {
+
+ if (pos >= length) {
+ // the end of DN has been found
+ return new String(chars, beg, end - beg);
+ }
+
+ switch (chars[pos]) {
+ case '+':
+ case ',':
+ case ';':
+ // separator char has beed found
+ return new String(chars, beg, end - beg);
+ case '\\':
+ // escaped char
+ chars[end++] = getEscaped();
+ pos++;
+ break;
+ case ' ':
+ // need to figure out whether space defines
+ // the end of attribute value or not
+ cur = end;
+
+ pos++;
+ chars[end++] = ' ';
+
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ chars[end++] = ' ';
+ }
+ if (pos == length || chars[pos] == ',' || chars[pos] == '+'
+ || chars[pos] == ';') {
+ // separator char or the end of DN has beed found
+ return new String(chars, beg, cur - beg);
+ }
+ break;
+ default:
+ chars[end++] = chars[pos];
+ pos++;
+ }
+ }
+ }
+
+ // returns escaped char
+ private char getEscaped() throws IOException {
+
+ pos++;
+ if (pos == length) {
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ switch (chars[pos]) {
+ case '"':
+ case '\\':
+ hasQE = true;
+ case ',':
+ case '=':
+ case '+':
+ case '<':
+ case '>':
+ case '#':
+ case ';':
+ case ' ':
+ //FIXME: escaping is allowed only for leading or trailing space char
+ return chars[pos];
+ default:
+ // RFC doesn't explicitly say that escaped hex pair is
+ // interpreted as UTF-8 char. It only contains an example of such DN.
+ return getUTF8();
+ }
+ }
+
+ // decodes UTF-8 char
+ // see http://www.unicode.org for UTF-8 bit distribution table
+ private char getUTF8() throws IOException {
+
+ int res = getByte(pos);
+ pos++; //FIXME tmp
+
+ if (res < 128) { // one byte: 0-7F
+ return (char) res;
+ } else if (res >= 192 && res <= 247) {
+
+ int count;
+ if (res <= 223) { // two bytes: C0-DF
+ count = 1;
+ res = res & 0x1F;
+ } else if (res <= 239) { // three bytes: E0-EF
+ count = 2;
+ res = res & 0x0F;
+ } else { // four bytes: F0-F7
+ count = 3;
+ res = res & 0x07;
+ }
+
+ int b;
+ for (int i = 0; i < count; i++) {
+ pos++;
+ if (pos == length || chars[pos] != '\\') {
+ return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+ }
+ pos++;
+
+ b = getByte(pos);
+ pos++; //FIXME tmp
+ if ((b & 0xC0) != 0x80) {
+ return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+ }
+
+ res = (res << 6) + (b & 0x3F);
+ }
+ return (char) res;
+ } else {
+ return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+ }
+ }
+
+ // Returns byte representation of a char pair
+ // The char pair is composed of DN char in
+ // specified 'position' and the next char
+ // According to BNF syntax:
+ // hexchar = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+ // / "a" / "b" / "c" / "d" / "e" / "f"
+ private int getByte(int position) throws IOException {
+
+ if ((position + 1) >= length) {
+ // to avoid ArrayIndexOutOfBoundsException
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ int b1, b2;
+
+ b1 = chars[position];
+ if (b1 >= '0' && b1 <= '9') {
+ b1 = b1 - '0';
+ } else if (b1 >= 'a' && b1 <= 'f') {
+ b1 = b1 - 87; // 87 = 'a' - 10
+ } else if (b1 >= 'A' && b1 <= 'F') {
+ b1 = b1 - 55; // 55 = 'A' - 10
+ } else {
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ b2 = chars[position + 1];
+ if (b2 >= '0' && b2 <= '9') {
+ b2 = b2 - '0';
+ } else if (b2 >= 'a' && b2 <= 'f') {
+ b2 = b2 - 87; // 87 = 'a' - 10
+ } else if (b2 >= 'A' && b2 <= 'F') {
+ b2 = b2 - 55; // 55 = 'A' - 10
+ } else {
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ return (b1 << 4) + b2;
+ }
+
+ /**
+ * Parses DN
+ *
+ * @return a list of Relative Distinguished Names(RND),
+ * each RDN is represented as a list of AttributeTypeAndValue objects
+ */
+ public List parse() throws IOException {
+
+ List list = new ArrayList();
+
+ String attValue;
+ String attType = nextAT();
+ if (attType == null) {
+ return list; //empty list of RDNs
+ }
+
+ List atav = new ArrayList();
+ while (true) {
+
+ if (pos == length) {
+
+ //empty Attribute Value
+ atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+ "", false))); //$NON-NLS-1$
+ list.add(0, atav);
+
+ return list;
+ }
+
+ switch (chars[pos]) {
+ case '"':
+ attValue = quotedAV();
+ atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+ attValue, hasQE)));
+ break;
+ case '#':
+ attValue = hexAV();
+
+ atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+ attValue, encoded)));
+ break;
+ case '+':
+ case ',':
+ case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+ //empty attribute value
+ atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+ "", false))); //$NON-NLS-1$
+ break;
+ default:
+ attValue = escapedAV();
+ atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+ attValue, hasQE)));
+ }
+
+ if (pos >= length) {
+ list.add(0, atav);
+ return list;
+ }
+
+ if (chars[pos] == ',' || chars[pos] == ';') {
+ list.add(0, atav);
+ atav = new ArrayList();
+ } else if (chars[pos] != '+') {
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+
+ pos++;
+ attType = nextAT();
+ if (attType == null) {
+ throw new IOException(
+ Messages.getString("security.192")); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff -aurN incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/DNParser.java ../harmony/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/DNParser.java
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/DNParser.java 2006-09-20 13:50:29.000000000 -0300
+++ ../harmony/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/DNParser.java 1969-12-31 21:00:00.000000000 -0300
@@ -1,448 +0,0 @@
-package org.apache.harmony.security.x509;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.harmony.security.x501.AttributeTypeAndValue;
-import org.apache.harmony.security.x501.AttributeValue;
-
-
-/**
- * Distinguished Name Parser.
- *
- * Parses a distinguished name(DN) string according
- * BNF syntax specified in RFC 2253 and RFC 1779
- *
- * RFC 2253: Lightweight Directory Access Protocol (v3):
- * UTF-8 String Representation of Distinguished Names
- * http://www.ietf.org/rfc/rfc2253.txt
- *
- * RFC 1779: A String Representation of Distinguished Names
- * http://www.ietf.org/rfc/rfc1779.txt
- */
-public class DNParser {
-
- // length of distinguished name string
- protected final int length;
-
- protected int pos;
-
- protected int beg;
-
- protected int end;
-
- // tmp vars to store positions of the currently parsed item
- protected int cur;
-
- // distinguished name chars
- protected char[] chars;
-
- // raw string contains '"' or '\'
- protected boolean hasQE;
-
- // DER encoding of currently parsed item
- protected byte[] encoded;
-
- /**
- * Constructs DN parser
- *
- * @param dn - distinguished name string to be parsed
- */
- public DNParser(String dn) throws IOException {
- this.length = dn.length();
- chars = dn.toCharArray();
- }
-
- // gets next attribute type: (ALPHA 1*keychar) / oid
- protected String nextAT() throws IOException {
-
- hasQE = false; // reset
-
- // skip preceding space chars, they can present after
- // comma or semicolon (compatibility with RFC 1779)
- for (; pos < length && chars[pos] == ' '; pos++) {
- }
- if (pos == length) {
- return null; // reached the end of DN
- }
-
- // mark the beginning of attribute type
- beg = pos;
-
- // attribute type chars
- pos++;
- for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
- // we don't follow exact BNF syntax here:
- // accept any char except space and '='
- }
- if (pos >= length) {
- // unexpected end of DN
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- // mark the end of attribute type
- end = pos;
-
- // skip trailing space chars between attribute type and '='
- // (compatibility with RFC 1779)
- if (chars[pos] == ' ') {
- for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
- }
-
- if (chars[pos] != '=' || pos == length) {
- // unexpected end of DN
- throw new IOException(
- "Invalid distinguished name string");
- }
- }
-
- pos++; //skip '=' char
-
- // skip space chars between '=' and attribute value
- // (compatibility with RFC 1779)
- for (; pos < length && chars[pos] == ' '; pos++) {
- }
-
- // in case of oid attribute type skip its prefix: "oid." or "OID."
- // (compatibility with RFC 1779)
- if ((end - beg > 4) && (chars[beg + 3] == '.')
- && (chars[beg] == 'O' || chars[beg] == 'o')
- && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
- && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
- beg += 4;
- }
-
- return new String(chars, beg, end - beg);
- }
-
- // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
- protected String quotedAV() throws IOException {
-
- pos++;
- beg = pos;
- end = beg;
- while (true) {
-
- if (pos == length) {
- // unexpected end of DN
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- if (chars[pos] == '"') {
- // enclosing quotation was found
- pos++;
- break;
- } else if (chars[pos] == '\\') {
- chars[end] = getEscaped();
- } else {
- // shift char: required for string with escaped chars
- chars[end] = chars[pos];
- }
- pos++;
- end++;
- }
-
- // skip trailing space chars before comma or semicolon.
- // (compatibility with RFC 1779)
- for (; pos < length && chars[pos] == ' '; pos++) {
- }
-
- return new String(chars, beg, end - beg);
- }
-
- // gets hex string attribute value: "#" hexstring
- protected String hexAV() throws IOException {
-
- if (pos + 4 >= length) {
- // encoded byte array must be not less then 4 c
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- beg = pos; // store '#' position
- pos++;
- while (true) {
-
- // check for end of attribute value
- // looks for space and component separators
- if (pos == length || chars[pos] == '+' || chars[pos] == ','
- || chars[pos] == ';') {
- end = pos;
- break;
- }
-
- if (chars[pos] == ' ') {
- end = pos;
- pos++;
- // skip trailing space chars before comma or semicolon.
- // (compatibility with RFC 1779)
- for (; pos < length && chars[pos] == ' '; pos++) {
- }
- break;
- } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
- chars[pos] += 32; //to low case
- }
-
- pos++;
- }
-
- // verify length of hex string
- // encoded byte array must be not less then 4 and must be even number
- int hexLen = end - beg; // skip first '#' char
- if (hexLen < 5 || (hexLen & 1) == 0) {
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- // get byte encoding from string representation
- encoded = new byte[hexLen / 2];
- for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
- encoded[i] = (byte) getByte(p);
- }
-
- return new String(chars, beg, hexLen);
- }
-
- // gets string attribute value: *( stringchar / pair )
- protected String escapedAV() throws IOException {
-
- beg = pos;
- end = pos;
- while (true) {
-
- if (pos >= length) {
- // the end of DN has been found
- return new String(chars, beg, end - beg);
- }
-
- switch (chars[pos]) {
- case '+':
- case ',':
- case ';':
- // separator char has beed found
- return new String(chars, beg, end - beg);
- case '\\':
- // escaped char
- chars[end++] = getEscaped();
- pos++;
- break;
- case ' ':
- // need to figure out whether space defines
- // the end of attribute value or not
- cur = end;
-
- pos++;
- chars[end++] = ' ';
-
- for (; pos < length && chars[pos] == ' '; pos++) {
- chars[end++] = ' ';
- }
- if (pos == length || chars[pos] == ',' || chars[pos] == '+'
- || chars[pos] == ';') {
- // separator char or the end of DN has beed found
- return new String(chars, beg, cur - beg);
- }
- break;
- default:
- chars[end++] = chars[pos];
- pos++;
- }
- }
- }
-
- // returns escaped char
- protected char getEscaped() throws IOException {
- pos++;
- if (pos == length) {
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- switch (chars[pos]) {
- case '"':
- case '\\':
- hasQE = true;
- case ',':
- case '=':
- case '+':
- case '<':
- case '>':
- case '#':
- case ';':
- case ' ':
- //FIXME: escaping is allowed only for leading or trailing space char
- return chars[pos];
- default:
- // RFC doesn't explicitly say that escaped hex pair is
- // interpreted as UTF-8 char. It only contains an example of such DN.
- return getUTF8();
- }
- }
-
- // decodes UTF-8 char
- // see http://www.unicode.org for UTF-8 bit distribution table
- protected char getUTF8() throws IOException {
-
- int res = getByte(pos);
- pos++; //FIXME tmp
-
- if (res < 128) { // one byte: 0-7F
- return (char) res;
- } else if (res >= 192 && res <= 247) {
-
- int count;
- if (res <= 223) { // two bytes: C0-DF
- count = 1;
- res = res & 0x1F;
- } else if (res <= 239) { // three bytes: E0-EF
- count = 2;
- res = res & 0x0F;
- } else { // four bytes: F0-F7
- count = 3;
- res = res & 0x07;
- }
-
- int b;
- for (int i = 0; i < count; i++) {
- pos++;
- if (pos == length || chars[pos] != '\\') {
- return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
- }
- pos++;
-
- b = getByte(pos);
- pos++; //FIXME tmp
- if ((b & 0xC0) != 0x80) {
- return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
- }
-
- res = (res << 6) + (b & 0x3F);
- }
- return (char) res;
- } else {
- return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
- }
- }
-
- // Returns byte representation of a char pair
- // The char pair is composed of DN char in
- // specified 'position' and the next char
- // According to BNF syntax:
- // hexchar = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
- // / "a" / "b" / "c" / "d" / "e" / "f"
- protected int getByte(int position) throws IOException {
-
- if ((position + 1) >= length) {
- // to avoid ArrayIndexOutOfBoundsException
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- int b1, b2;
-
- b1 = chars[position];
- if (b1 >= '0' && b1 <= '9') {
- b1 = b1 - '0';
- } else if (b1 >= 'a' && b1 <= 'f') {
- b1 = b1 - 87; // 87 = 'a' - 10
- } else if (b1 >= 'A' && b1 <= 'F') {
- b1 = b1 - 55; // 55 = 'A' - 10
- } else {
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- b2 = chars[position + 1];
- if (b2 >= '0' && b2 <= '9') {
- b2 = b2 - '0';
- } else if (b2 >= 'a' && b2 <= 'f') {
- b2 = b2 - 87; // 87 = 'a' - 10
- } else if (b2 >= 'A' && b2 <= 'F') {
- b2 = b2 - 55; // 55 = 'A' - 10
- } else {
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- return (b1 << 4) + b2;
- }
-
- /**
- * Parses DN
- *
- * @return a list of Relative Distinguished Names(RND),
- * each RDN is represented as a list of AttributeTypeAndValue objects
- */
- public List parse() throws IOException {
-
- List list = new ArrayList();
-
- String attValue;
- String attType = nextAT();
- if (attType == null) {
- return list; //empty list of RDNs
- }
-
- List atav = new ArrayList();
- while (true) {
-
- if (pos == length) {
-
- //empty Attribute Value
- atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
- "", false)));
- list.add(0, atav);
-
- return list;
- }
-
- switch (chars[pos]) {
- case '"':
- attValue = quotedAV();
- atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
- attValue, hasQE)));
- break;
- case '#':
- attValue = hexAV();
-
- atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
- attValue, encoded)));
- break;
- case '+':
- case ',':
- case ';': // compatibility with RFC 1779: semicolon can separate RDNs
- //empty attribute value
- atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
- "", false)));
- break;
- default:
- attValue = escapedAV();
- atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
- attValue, hasQE)));
- }
-
- if (pos >= length) {
- list.add(0, atav);
- return list;
- }
-
- if (chars[pos] == ',' || chars[pos] == ';') {
- list.add(0, atav);
- atav = new ArrayList();
- } else if (chars[pos] != '+') {
- throw new IOException(
- "Invalid distinguished name string");
- }
-
- pos++;
- attType = nextAT();
- if (attType == null) {
- throw new IOException(
- "Invalid distinguished name string");
- }
- }
- }
-}