Home » openjdk-7 » javax » naming » ldap » [javadoc | source]

    1   /*
    2    * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.naming.ldap;
   27   
   28   import java.util.List;
   29   import java.util.ArrayList;
   30   
   31   import javax.naming.InvalidNameException;
   32   
   33   /*
   34    * RFC2253Parser implements a recursive descent parser for a single DN.
   35    */
   36   final class Rfc2253Parser {
   37   
   38           private final String name;      // DN being parsed
   39           private final char[] chars;     // characters in LDAP name being parsed
   40           private final int len;  // length of "chars"
   41           private int cur = 0;    // index of first unconsumed char in "chars"
   42   
   43           /*
   44            * Given an LDAP DN in string form, returns a parser for it.
   45            */
   46           Rfc2253Parser(String name) {
   47               this.name = name;
   48               len = name.length();
   49               chars = name.toCharArray();
   50           }
   51   
   52           /*
   53            * Parses the DN, returning a List of its RDNs.
   54            */
   55           // public List<Rdn> getDN() throws InvalidNameException {
   56   
   57           List parseDn() throws InvalidNameException {
   58               cur = 0;
   59   
   60               // ArrayList<Rdn> rdns =
   61               //  new ArrayList<Rdn>(len / 3 + 10);  // leave room for growth
   62   
   63               ArrayList rdns =
   64                   new ArrayList(len / 3 + 10);  // leave room for growth
   65   
   66               if (len == 0) {
   67                   return rdns;
   68               }
   69   
   70               rdns.add(doParse(new Rdn()));
   71               while (cur < len) {
   72                   if (chars[cur] == ',' || chars[cur] == ';') {
   73                       ++cur;
   74                       rdns.add(0, doParse(new Rdn()));
   75                   } else {
   76                       throw new InvalidNameException("Invalid name: " + name);
   77                   }
   78               }
   79               return rdns;
   80           }
   81   
   82           /*
   83            * Parses the DN, if it is known to contain a single RDN.
   84            */
   85           Rdn parseRdn() throws InvalidNameException {
   86               return parseRdn(new Rdn());
   87           }
   88   
   89           /*
   90            * Parses the DN, if it is known to contain a single RDN.
   91            */
   92           Rdn parseRdn(Rdn rdn) throws InvalidNameException {
   93               rdn = doParse(rdn);
   94               if (cur < len) {
   95                   throw new InvalidNameException("Invalid RDN: " + name);
   96               }
   97               return rdn;
   98           }
   99   
  100           /*
  101            * Parses the next RDN and returns it.  Throws an exception if
  102            * none is found.  Leading and trailing whitespace is consumed.
  103            */
  104            private Rdn doParse(Rdn rdn) throws InvalidNameException {
  105   
  106               while (cur < len) {
  107                   consumeWhitespace();
  108                   String attrType = parseAttrType();
  109                   consumeWhitespace();
  110                   if (cur >= len || chars[cur] != '=') {
  111                       throw new InvalidNameException("Invalid name: " + name);
  112                   }
  113                   ++cur;          // consume '='
  114                   consumeWhitespace();
  115                   String value = parseAttrValue();
  116                   consumeWhitespace();
  117   
  118                   rdn.put(attrType, Rdn.unescapeValue(value));
  119                   if (cur >= len || chars[cur] != '+') {
  120                       break;
  121                   }
  122                   ++cur;          // consume '+'
  123               }
  124               rdn.sort();
  125               return rdn;
  126           }
  127   
  128           /*
  129            * Returns the attribute type that begins at the next unconsumed
  130            * char.  No leading whitespace is expected.
  131            * This routine is more generous than RFC 2253.  It accepts
  132            * attribute types composed of any nonempty combination of Unicode
  133            * letters, Unicode digits, '.', '-', and internal space characters.
  134            */
  135           private String parseAttrType() throws InvalidNameException {
  136   
  137               final int beg = cur;
  138               while (cur < len) {
  139                   char c = chars[cur];
  140                   if (Character.isLetterOrDigit(c) ||
  141                           c == '.' ||
  142                           c == '-' ||
  143                           c == ' ') {
  144                       ++cur;
  145                   } else {
  146                       break;
  147                   }
  148               }
  149               // Back out any trailing spaces.
  150               while ((cur > beg) && (chars[cur - 1] == ' ')) {
  151                   --cur;
  152               }
  153   
  154               if (beg == cur) {
  155                   throw new InvalidNameException("Invalid name: " + name);
  156               }
  157               return new String(chars, beg, cur - beg);
  158           }
  159   
  160           /*
  161            * Returns the attribute value that begins at the next unconsumed
  162            * char.  No leading whitespace is expected.
  163            */
  164           private String parseAttrValue() throws InvalidNameException {
  165   
  166               if (cur < len && chars[cur] == '#') {
  167                   return parseBinaryAttrValue();
  168               } else if (cur < len && chars[cur] == '"') {
  169                   return parseQuotedAttrValue();
  170               } else {
  171                   return parseStringAttrValue();
  172               }
  173           }
  174   
  175           private String parseBinaryAttrValue() throws InvalidNameException {
  176               final int beg = cur;
  177               ++cur;                      // consume '#'
  178               while ((cur < len) &&
  179                       Character.isLetterOrDigit(chars[cur])) {
  180                   ++cur;
  181               }
  182               return new String(chars, beg, cur - beg);
  183           }
  184   
  185           private String parseQuotedAttrValue() throws InvalidNameException {
  186   
  187               final int beg = cur;
  188               ++cur;                      // consume '"'
  189   
  190               while ((cur < len) && chars[cur] != '"') {
  191                   if (chars[cur] == '\\') {
  192                       ++cur;              // consume backslash, then what follows
  193                   }
  194                   ++cur;
  195               }
  196               if (cur >= len) {   // no closing quote
  197                   throw new InvalidNameException("Invalid name: " + name);
  198               }
  199               ++cur;      // consume closing quote
  200   
  201               return new String(chars, beg, cur - beg);
  202           }
  203   
  204           private String parseStringAttrValue() throws InvalidNameException {
  205   
  206               final int beg = cur;
  207               int esc = -1;       // index of the most recently escaped character
  208   
  209               while ((cur < len) && !atTerminator()) {
  210                   if (chars[cur] == '\\') {
  211                       ++cur;              // consume backslash, then what follows
  212                       esc = cur;
  213                   }
  214                   ++cur;
  215               }
  216               if (cur > len) {            // 'twas backslash followed by nothing
  217                   throw new InvalidNameException("Invalid name: " + name);
  218               }
  219   
  220               // Trim off (unescaped) trailing whitespace.
  221               int end;
  222               for (end = cur; end > beg; end--) {
  223                   if (!isWhitespace(chars[end - 1]) || (esc == end - 1)) {
  224                       break;
  225                   }
  226               }
  227               return new String(chars, beg, end - beg);
  228           }
  229   
  230           private void consumeWhitespace() {
  231               while ((cur < len) && isWhitespace(chars[cur])) {
  232                   ++cur;
  233               }
  234           }
  235   
  236           /*
  237            * Returns true if next unconsumed character is one that terminates
  238            * a string attribute value.
  239            */
  240           private boolean atTerminator() {
  241               return (cur < len &&
  242                       (chars[cur] == ',' ||
  243                           chars[cur] == ';' ||
  244                           chars[cur] == '+'));
  245           }
  246   
  247           /*
  248            * Best guess as to what RFC 2253 means by "whitespace".
  249            */
  250           private static boolean isWhitespace(char c) {
  251               return (c == ' ' || c == '\r');
  252           }
  253       }

Home » openjdk-7 » javax » naming » ldap » [javadoc | source]