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