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