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