nl_tokens: Thank you OpenJDK!
pl_tokens: function parse ( name ) { if ( typeof ( name ) !== 'string' ) throw new TypeError ( 'name (string) required' ) ; var cur = 0 ; var len = name . length ; function parseRdn ( ) { var rdn = new RDN ( ) ; var order = 0 ; rdn . spLead = trim ( ) ; while ( cur < len ) { var opts = { <mask> : order } ; var attr = parseAttrType ( ) ; trim ( ) ; if ( cur >= len || name [ cur ++ ] !== '=' ) throw invalidDN ( name ) ; trim ( ) ; // Parameters about RDN value are set in 'opts' by parseAttrValue var value = parseAttrValue ( opts ) ; rdn . set ( attr , value , opts ) ; rdn . spTrail = trim ( ) ; if ( cur >= len || name [ cur ] !== '+' ) break ; ++ cur ; ++ order ; } return rdn ; } function trim ( ) { var count = 0 ; while ( ( cur < len ) && isWhitespace ( name [ cur ] ) ) { ++ cur ; count ++ ; } return count ; } function parseAttrType ( ) { var beg = cur ; while ( cur < len ) { var c = name [ cur ] ; if ( isAlphaNumeric ( c ) || c == '.' || c == '-' || c == ' ' ) { ++ cur ; } else { break ; } } // Back out any trailing spaces. while ( ( cur > beg ) && ( name [ cur - 1 ] == ' ' ) ) -- cur ; if ( beg == cur ) throw invalidDN ( name ) ; return name . slice ( beg , cur ) ; } function parseAttrValue ( opts ) { if ( cur < len && name [ cur ] == '#' ) { opts . binary = true ; return parseBinaryAttrValue ( ) ; } else if ( cur < len && name [ cur ] == '"' ) { opts . quoted = true ; return parseQuotedAttrValue ( ) ; } else { return parseStringAttrValue ( ) ; } } function parseBinaryAttrValue ( ) { var beg = cur ++ ; while ( cur < len && isAlphaNumeric ( name [ cur ] ) ) ++ cur ; return name . slice ( beg , cur ) ; } function parseQuotedAttrValue ( ) { var str = '' ; ++ cur ; // Consume the first quote while ( ( cur < len ) && name [ cur ] != '"' ) { if ( name [ cur ] === '\\' ) cur ++ ; str += name [ cur ++ ] ; } if ( cur ++ >= len ) // no closing quote throw invalidDN ( name ) ; return str ; } function parseStringAttrValue ( ) { var beg = cur ; var str = '' ; var esc = - 1 ; while ( ( cur < len ) && ! atTerminator ( ) ) { if ( name [ cur ] === '\\' ) { // Consume the backslash and mark its place just in case it's escaping // whitespace which needs to be preserved. esc = cur ++ ; } if ( cur === len ) // backslash followed by nothing throw invalidDN ( name ) ; str += name [ cur ++ ] ; } // Trim off (unescaped) trailing whitespace and rewind cursor to the end of // the AttrValue to record whitespace length. for ( ; cur > beg ; cur -- ) { if ( ! isWhitespace ( name [ cur - 1 ] ) || ( esc === ( cur - 1 ) ) ) break ; } return str . slice ( 0 , cur - beg ) ; } function atTerminator ( ) { return ( cur < len && ( name [ cur ] === ',' || name [ cur ] === ';' || name [ cur ] === '+' ) ) ; } var rdns = [ ] ; // Short-circuit for empty DNs if ( len === 0 ) return new DN ( rdns ) ; rdns . push ( parseRdn ( ) ) ; while ( cur < len ) { if ( name [ cur ] === ',' || name [ cur ] === ';' ) { ++ cur ; rdns . push ( parseRdn ( ) ) ; } else { throw invalidDN ( name ) ; } } return new DN ( rdns ) ; }