1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.ldap.model.name;
21
22
23 import java.util.List;
24
25 import org.apache.directory.api.i18n.I18n;
26 import org.apache.directory.api.ldap.model.exception.LdapException;
27 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
28 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
29 import org.apache.directory.api.ldap.model.schema.AttributeType;
30 import org.apache.directory.api.ldap.model.schema.SchemaManager;
31 import org.apache.directory.api.util.Position;
32 import org.apache.directory.api.util.Strings;
33
34
35
36
37
38
39
40
41 enum FastDnParser
42 {
43 INSTANCE;
44
45
46
47
48
49
50
51
52 static Dn parse( String name ) throws LdapException
53 {
54 Dn dn = new Dn();
55 parseDn( null, name, dn );
56
57 return dn;
58 }
59
60
61
62
63
64
65
66
67
68
69 static Dn parse( SchemaManager schemaManager, String name ) throws LdapException
70 {
71 Dn dn = new Dn( schemaManager );
72 parseDn( schemaManager, name, dn );
73
74 return dn;
75 }
76
77
78
79
80
81
82
83
84
85
86
87 static void parseDn( SchemaManager schemaManager, String name, Dn dn ) throws LdapInvalidDnException
88 {
89 String normName = parseDn( schemaManager, name, dn.rdns );
90 dn.setUpName( name );
91 dn.setNormName( normName );
92 }
93
94
95 static String parseDn( SchemaManager schemaManager, String name, List<Rdn> rdns ) throws LdapInvalidDnException
96 {
97 if ( ( name == null ) || ( name.trim().length() == 0 ) )
98 {
99
100 return "";
101 }
102
103 Position pos = new Position();
104 char[] chars = name.toCharArray();
105
106 pos.start = 0;
107 pos.length = chars.length;
108 StringBuilder sb = new StringBuilder();
109
110 while ( true )
111 {
112 Rdn rdn = new Rdn( schemaManager );
113 parseRdnInternal( schemaManager, name, pos, rdn );
114 sb.append( rdn.getNormName() );
115 rdns.add( rdn );
116
117 if ( !hasMoreChars( pos ) )
118 {
119
120 break;
121 }
122
123 char c = nextChar( chars, pos, true );
124
125 switch ( c )
126 {
127 case ',':
128 case ';':
129
130 sb.append( ',' );
131 break;
132
133 default:
134 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13601_EXPECTED_COMMA_SEMI_COLON, c,
135 pos.start ) );
136 }
137 }
138
139 return sb.toString();
140 }
141
142
143
144
145
146
147
148
149
150
151
152 static void parseRdn( SchemaManager schemaManager, String name, Rdn rdn ) throws LdapInvalidDnException
153 {
154 if ( Strings.isEmpty( name ) )
155 {
156 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13602_RDN_EMPTY ) );
157 }
158
159 Position pos = new Position();
160 pos.start = 0;
161 pos.length = name.length();
162
163 parseRdnInternal( schemaManager, name, pos, rdn );
164 }
165
166
167 private static void parseRdnInternal( SchemaManager schemaManager, String name, Position pos, Rdn rdn ) throws LdapInvalidDnException
168 {
169 StringBuilder sbNormName = new StringBuilder();
170 int rdnStart = pos.start;
171 char[] chars = name.toCharArray();
172
173
174 matchSpaces( chars, pos );
175
176
177 String type = matchAttributeType( chars, pos );
178
179
180 matchSpaces( chars, pos );
181
182
183 matchEquals( chars, pos );
184
185
186 matchSpaces( chars, pos );
187
188
189
190 String upValue = matchValue( chars, pos );
191
192 if ( rdn != null )
193 {
194 String upName = name.substring( rdnStart, pos.start );
195 Ava ava = new Ava( schemaManager, type, upValue );
196
197 rdn.addAVA( schemaManager, ava );
198
199 if ( schemaManager != null )
200 {
201 AttributeType attributeType = ava.getAttributeType();
202
203 if ( attributeType != null )
204 {
205 sbNormName.append( ava.getNormType() );
206 sbNormName.append( '=' );
207 sbNormName.append( ava.getValue().getNormalized() );
208 }
209 else
210 {
211 sbNormName.append( type );
212 sbNormName.append( '=' );
213 sbNormName.append( upValue );
214 }
215 }
216 else
217 {
218 sbNormName.append( Strings.toLowerCaseAscii( type ) );
219 sbNormName.append( '=' );
220 sbNormName.append( upValue );
221 }
222
223 rdn.setUpName( upName );
224 rdn.setNormName( sbNormName.toString() );
225 rdn.hashCode();
226 }
227 }
228
229
230
231
232
233
234
235
236
237 private static void matchSpaces( char[] name, Position pos ) throws LdapInvalidDnException
238 {
239 while ( hasMoreChars( pos ) )
240 {
241 char c = nextChar( name, pos, true );
242
243 if ( c != ' ' )
244 {
245 pos.start--;
246 break;
247 }
248 }
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262 private static String matchAttributeType( char[] name, Position pos ) throws LdapInvalidDnException
263 {
264 char c = nextChar( name, pos, false );
265
266 switch ( c )
267 {
268 case 'A':
269 case 'B':
270 case 'C':
271 case 'D':
272 case 'E':
273 case 'F':
274 case 'G':
275 case 'H':
276 case 'I':
277 case 'J':
278 case 'K':
279 case 'L':
280 case 'M':
281 case 'N':
282 case 'O':
283 case 'P':
284 case 'Q':
285 case 'R':
286 case 'S':
287 case 'T':
288 case 'U':
289 case 'V':
290 case 'W':
291 case 'X':
292 case 'Y':
293 case 'Z':
294 case 'a':
295 case 'b':
296 case 'c':
297 case 'd':
298 case 'e':
299 case 'f':
300 case 'g':
301 case 'h':
302 case 'i':
303 case 'j':
304 case 'k':
305 case 'l':
306 case 'm':
307 case 'n':
308 case 'o':
309 case 'p':
310 case 'q':
311 case 'r':
312 case 's':
313 case 't':
314 case 'u':
315 case 'v':
316 case 'w':
317 case 'x':
318 case 'y':
319 case 'z':
320
321 return matchAttributeTypeDescr( name, pos );
322
323 case '0':
324 case '1':
325 case '2':
326 case '3':
327 case '4':
328 case '5':
329 case '6':
330 case '7':
331 case '8':
332 case '9':
333
334 return matchAttributeTypeNumericOid( name, pos );
335
336 default:
337
338 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13604_START_AT_EXPECTED, c,
339 pos.start ) );
340 }
341 }
342
343
344
345
346
347
348
349
350
351
352
353
354 private static String matchAttributeTypeDescr( char[] name, Position pos ) throws LdapInvalidDnException
355 {
356 int start = pos.start;
357
358 while ( hasMoreChars( pos ) )
359 {
360 char c = nextChar( name, pos, true );
361
362 switch ( c )
363 {
364 case 'A':
365 case 'B':
366 case 'C':
367 case 'D':
368 case 'E':
369 case 'F':
370 case 'G':
371 case 'H':
372 case 'I':
373 case 'J':
374 case 'K':
375 case 'L':
376 case 'M':
377 case 'N':
378 case 'O':
379 case 'P':
380 case 'Q':
381 case 'R':
382 case 'S':
383 case 'T':
384 case 'U':
385 case 'V':
386 case 'W':
387 case 'X':
388 case 'Y':
389 case 'Z':
390 case 'a':
391 case 'b':
392 case 'c':
393 case 'd':
394 case 'e':
395 case 'f':
396 case 'g':
397 case 'h':
398 case 'i':
399 case 'j':
400 case 'k':
401 case 'l':
402 case 'm':
403 case 'n':
404 case 'o':
405 case 'p':
406 case 'q':
407 case 'r':
408 case 's':
409 case 't':
410 case 'u':
411 case 'v':
412 case 'w':
413 case 'x':
414 case 'y':
415 case 'z':
416 case '0':
417 case '1':
418 case '2':
419 case '3':
420 case '4':
421 case '5':
422 case '6':
423 case '7':
424 case '8':
425 case '9':
426 case '-':
427 case '_':
428
429 break;
430
431 case ' ':
432 case '=':
433 pos.start--;
434 return new String( name, start, pos.start - start );
435
436 case '.':
437
438 throw TooComplexDnException.INSTANCE;
439
440 default:
441
442 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13605_START_AT_DESCR_EXPECTED, c,
443 pos.start ) );
444 }
445 }
446
447 return new String( name, start, pos.start - start );
448 }
449
450
451
452
453
454
455
456
457
458
459
460
461 private static String matchAttributeTypeNumericOid( char[] name, Position pos ) throws LdapInvalidDnException
462 {
463 int dotCount = 0;
464 int start = pos.start;
465
466 while ( true )
467 {
468 char c = nextChar( name, pos, true );
469
470 switch ( c )
471 {
472 case '0':
473
474 c = nextChar( name, pos, true );
475
476 switch ( c )
477 {
478 case '.':
479 dotCount++;
480 break;
481
482 case ' ':
483 case '=':
484 pos.start--;
485 break;
486
487 default:
488 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err(
489 I18n.ERR_13606_EXPECTED_NUMERICOID, c, pos.start ) );
490 }
491
492 break;
493
494 case '1':
495 case '2':
496 case '3':
497 case '4':
498 case '5':
499 case '6':
500 case '7':
501 case '8':
502 case '9':
503 boolean inInnerLoop = true;
504
505 while ( inInnerLoop )
506 {
507 c = nextChar( name, pos, true );
508
509 switch ( c )
510 {
511 case ' ':
512 case '=':
513 inInnerLoop = false;
514 pos.start--;
515 break;
516
517 case '.':
518 inInnerLoop = false;
519 dotCount++;
520 break;
521
522 case '0':
523 case '1':
524 case '2':
525 case '3':
526 case '4':
527 case '5':
528 case '6':
529 case '7':
530 case '8':
531 case '9':
532 break;
533
534 default:
535 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err(
536 I18n.ERR_13606_EXPECTED_NUMERICOID, c, pos.start ) );
537 }
538 }
539
540 break;
541
542 case ' ':
543 case '=':
544 pos.start--;
545
546 if ( dotCount > 0 )
547 {
548 return new String( name, start, pos.start - start );
549 }
550 else
551 {
552 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13607_DOT_MISSING_IN_OID ) );
553 }
554
555 default:
556 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13608_START_AT_NUMERICOID_EXPECTED, c,
557 pos.start ) );
558 }
559 }
560 }
561
562
563
564
565
566
567
568
569
570
571 private static void matchEquals( char[] name, Position pos ) throws LdapInvalidDnException
572 {
573 char c = nextChar( name, pos, true );
574
575 if ( c != '=' )
576 {
577 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13609_EQUAL_EXPECTED, c, pos.start ) );
578 }
579 }
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594 private static String matchValue( char[] name, Position pos ) throws LdapInvalidDnException
595 {
596 int start = pos.start;
597 int numTrailingSpaces = 0;
598
599 while ( true )
600 {
601 if ( !hasMoreChars( pos ) )
602 {
603 return new String( name, start, pos.start - numTrailingSpaces - start );
604 }
605
606 char c = nextChar( name, pos, true );
607
608 switch ( c )
609 {
610 case '\\':
611 case '+':
612 case '#':
613 case '"':
614 throw TooComplexDnException.INSTANCE;
615
616 case ',':
617 case ';':
618 pos.start--;
619 return new String( name, start, pos.start - numTrailingSpaces - start );
620
621 case ' ':
622 numTrailingSpaces++;
623 break;
624
625 default:
626 numTrailingSpaces = 0;
627 }
628 }
629 }
630
631
632
633
634
635
636
637
638
639
640
641
642 private static char nextChar( char[] name, Position pos, boolean increment ) throws LdapInvalidDnException
643 {
644 if ( !hasMoreChars( pos ) )
645 {
646 throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_13610_NO_MORE_CHAR_AVAILABLE, pos.start ) );
647 }
648
649 char c = name[pos.start];
650
651 if ( increment )
652 {
653 pos.start++;
654 }
655
656 return c;
657 }
658
659
660
661
662
663
664
665
666
667 private static boolean hasMoreChars( Position pos )
668 {
669 return pos.start < pos.length;
670 }
671 }