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.filter;
21
22
23 import java.text.ParseException;
24
25 import org.apache.directory.api.i18n.I18n;
26 import org.apache.directory.api.ldap.model.entry.AttributeUtils;
27 import org.apache.directory.api.ldap.model.entry.BinaryValue;
28 import org.apache.directory.api.ldap.model.entry.StringValue;
29 import org.apache.directory.api.ldap.model.entry.Value;
30 import org.apache.directory.api.ldap.model.exception.LdapException;
31 import org.apache.directory.api.ldap.model.schema.AttributeType;
32 import org.apache.directory.api.ldap.model.schema.SchemaManager;
33 import org.apache.directory.api.util.Chars;
34 import org.apache.directory.api.util.Hex;
35 import org.apache.directory.api.util.Position;
36 import org.apache.directory.api.util.Strings;
37 import org.apache.directory.api.util.Unicode;
38
39
40
41
42
43
44
45 public class FilterParser
46 {
47
48
49
50 public FilterParser()
51 {
52 }
53
54
55
56
57
58
59
60
61
62 private static ExprNode parseExtensible( SchemaManager schemaManager, String attribute, byte[] filter,
63 Position pos, boolean relaxed ) throws LdapException, ParseException
64 {
65 ExtensibleNode node = null;
66
67 if ( schemaManager != null )
68 {
69 AttributeType attributeType = schemaManager.getAttributeType( attribute );
70
71 if ( attributeType != null )
72 {
73 node = new ExtensibleNode( attributeType );
74 }
75 else
76 {
77 return UndefinedNode.UNDEFINED_NODE;
78 }
79 }
80 else
81 {
82 node = new ExtensibleNode( attribute );
83 }
84
85 if ( attribute != null )
86 {
87
88 if ( Strings.areEquals( filter, pos.start, "dn" ) >= 0 )
89 {
90
91 node.setDnAttributes( true );
92 pos.start += 2;
93 }
94 else
95 {
96
97 pos.start--;
98 }
99
100
101 if ( Strings.byteAt( filter, pos.start ) == ':' )
102 {
103 pos.start++;
104
105 if ( Strings.byteAt( filter, pos.start ) == '=' )
106 {
107 pos.start++;
108
109
110 node.setValue( parseAssertionValue( schemaManager, attribute, filter, pos ) );
111
112 return node;
113 }
114 else
115 {
116 String matchingRuleId = AttributeUtils.parseAttribute( filter, pos, false, relaxed );
117
118 node.setMatchingRuleId( matchingRuleId );
119
120 if ( Strings.areEquals( filter, pos.start, ":=" ) >= 0 )
121 {
122 pos.start += 2;
123
124
125 node.setValue( parseAssertionValue( schemaManager, attribute, filter, pos ) );
126
127 return node;
128 }
129 else
130 {
131 throw new ParseException( I18n.err( I18n.ERR_04146 ), pos.start );
132 }
133 }
134 }
135 else
136 {
137 throw new ParseException( I18n.err( I18n.ERR_04147 ), pos.start );
138 }
139 }
140 else
141 {
142 boolean oidRequested = false;
143
144
145 if ( Strings.areEquals( filter, pos.start, ":dn" ) >= 0 )
146 {
147
148 node.setDnAttributes( true );
149 pos.start += 3;
150 }
151 else
152 {
153 oidRequested = true;
154 }
155
156
157 if ( Strings.byteAt( filter, pos.start ) == ':' )
158 {
159 pos.start++;
160
161 if ( Strings.byteAt( filter, pos.start ) == '=' )
162 {
163 if ( oidRequested )
164 {
165 throw new ParseException( I18n.err( I18n.ERR_04148 ), pos.start );
166 }
167
168 pos.start++;
169
170
171 node.setValue( parseAssertionValue( schemaManager, attribute, filter, pos ) );
172
173 return node;
174 }
175 else
176 {
177 String matchingRuleId = AttributeUtils.parseAttribute( filter, pos, false, relaxed );
178
179 node.setMatchingRuleId( matchingRuleId );
180
181 if ( Strings.areEquals( filter, pos.start, ":=" ) >= 0 )
182 {
183 pos.start += 2;
184
185
186 node.setValue( parseAssertionValue( schemaManager, attribute, filter, pos ) );
187
188 return node;
189 }
190 else
191 {
192 throw new ParseException( I18n.err( I18n.ERR_04146 ), pos.start );
193 }
194 }
195 }
196 else
197 {
198 throw new ParseException( I18n.err( I18n.ERR_04147 ), pos.start );
199 }
200 }
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236 private static Value<?> parseAssertionValue( SchemaManager schemaManager, String attribute, byte[] filter,
237 Position pos ) throws ParseException
238 {
239 byte b = Strings.byteAt( filter, pos.start );
240
241
242 byte[] value = new byte[filter.length - pos.start];
243 int current = 0;
244
245 do
246 {
247 if ( Unicode.isUnicodeSubset( b ) )
248 {
249 value[current++] = b;
250 pos.start++;
251 }
252 else if ( Strings.isCharASCII( filter, pos.start, '\\' ) )
253 {
254
255 pos.start++;
256
257
258 if ( Chars.isHex( filter, pos.start ) )
259 {
260 pos.start++;
261 }
262 else
263 {
264 throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
265 }
266
267
268 if ( Chars.isHex( filter, pos.start ) )
269 {
270 value[current++] = Hex.getHexValue( filter[pos.start - 1], filter[pos.start] );
271 pos.start++;
272 }
273 else
274 {
275 throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
276 }
277 }
278 else
279 {
280
281 break;
282 }
283 }
284 while ( ( b = Strings.byteAt( filter, pos.start ) ) != '\0' );
285
286 if ( current != 0 )
287 {
288 byte[] result = new byte[current];
289 System.arraycopy( value, 0, result, 0, current );
290
291 if ( schemaManager != null )
292 {
293 AttributeType attributeType = schemaManager.getAttributeType( attribute );
294
295 if ( attributeType == null )
296 {
297 return new BinaryValue( result );
298 }
299
300 if ( attributeType.getSyntax().isHumanReadable() )
301 {
302 return new StringValue( Strings.utf8ToString( result ) );
303 }
304 else
305 {
306 return new BinaryValue( result );
307 }
308 }
309 else
310 {
311 return new BinaryValue( result );
312 }
313 }
314 else
315 {
316 if ( schemaManager != null )
317 {
318 AttributeType attributeType = schemaManager.getAttributeType( attribute );
319
320 if ( attributeType.getEquality().getSyntax().isHumanReadable() )
321 {
322 return new StringValue( ( String ) null );
323 }
324 else
325 {
326 return new BinaryValue( null );
327 }
328 }
329 else
330 {
331 return new BinaryValue( ( byte[] ) null );
332 }
333 }
334 }
335
336
337
338
339
340 private static ExprNode parseSubstring( SchemaManager schemaManager, String attribute, Value<?> initial,
341 byte[] filter, Position pos )
342 throws ParseException, LdapException
343 {
344 if ( Strings.isCharASCII( filter, pos.start, '*' ) )
345 {
346
347 SubstringNode node = null;
348
349 if ( schemaManager != null )
350 {
351 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute );
352
353 if ( attributeType != null )
354 {
355 node = new SubstringNode( schemaManager.lookupAttributeTypeRegistry( attribute ) );
356 }
357 else
358 {
359 return null;
360 }
361 }
362 else
363 {
364 node = new SubstringNode( attribute );
365 }
366
367 if ( ( initial != null ) && !initial.isNull() )
368 {
369
370
371 String initialStr = initial.getString();
372 node.setInitial( initialStr );
373 }
374
375 pos.start++;
376
377
378 while ( true )
379 {
380 Value<?> assertionValue = parseAssertionValue( schemaManager, attribute, filter, pos );
381
382
383 if ( Strings.isCharASCII( filter, pos.start, ')' ) )
384 {
385
386
387 if ( !assertionValue.isNull() )
388 {
389 String finalStr = assertionValue.getString();
390 node.setFinal( finalStr );
391 }
392
393 return node;
394 }
395 else if ( Strings.isCharASCII( filter, pos.start, '*' ) )
396 {
397
398
399
400 if ( !assertionValue.isNull() )
401 {
402 String anyStr = assertionValue.getString();
403 node.addAny( anyStr );
404 }
405
406 pos.start++;
407 }
408 else
409 {
410
411 throw new ParseException( I18n.err( I18n.ERR_04150 ), pos.start );
412 }
413 }
414 }
415 else
416 {
417
418 throw new ParseException( I18n.err( I18n.ERR_04150 ), pos.start );
419 }
420 }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447 @SuppressWarnings(
448 { "rawtypes", "unchecked" })
449 private static ExprNode parsePresenceEqOrSubstring( SchemaManager schemaManager, String attribute, byte[] filter,
450 Position pos )
451 throws ParseException, LdapException
452 {
453 if ( Strings.isCharASCII( filter, pos.start, '*' ) )
454 {
455
456 pos.start++;
457
458 if ( Strings.isCharASCII( filter, pos.start, ')' ) )
459 {
460
461 if ( schemaManager != null )
462 {
463 AttributeType attributeType = schemaManager.getAttributeType( attribute );
464
465 if ( attributeType != null )
466 {
467 return new PresenceNode( attributeType );
468 }
469 else
470 {
471 return null;
472 }
473 }
474 else
475 {
476 return new PresenceNode( attribute );
477 }
478 }
479 else
480 {
481
482
483 pos.start--;
484 return parseSubstring( schemaManager, attribute, null, filter, pos );
485 }
486 }
487 else if ( Strings.isCharASCII( filter, pos.start, ')' ) )
488 {
489
490 if ( schemaManager != null )
491 {
492 AttributeType attributeType = schemaManager.getAttributeType( attribute );
493
494 if ( attributeType != null )
495 {
496 return new EqualityNode( attributeType, new BinaryValue( ( byte[] ) null ) );
497 }
498
499 else
500 {
501 return null;
502 }
503 }
504 else
505 {
506 return new EqualityNode( attribute, new BinaryValue( ( byte[] ) null ) );
507 }
508 }
509 else
510 {
511
512 Value<?> value = parseAssertionValue( schemaManager, attribute, filter, pos );
513
514
515 if ( Strings.isCharASCII( filter, pos.start, ')' ) )
516 {
517
518 if ( schemaManager != null )
519 {
520 AttributeType attributeType = schemaManager.getAttributeType( attribute );
521
522 if ( attributeType != null )
523 {
524 return new EqualityNode( attributeType, value );
525 }
526 else
527 {
528 return null;
529 }
530 }
531 else
532 {
533 return new EqualityNode( attribute, value );
534 }
535 }
536
537 return parseSubstring( schemaManager, attribute, value, filter, pos );
538 }
539 }
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555 @SuppressWarnings(
556 { "rawtypes", "unchecked" })
557 private static ExprNode parseItem( SchemaManager schemaManager, byte[] filter, Position pos, byte b,
558 boolean relaxed ) throws ParseException, LdapException
559 {
560 String attribute = null;
561
562 if ( b == '\0' )
563 {
564 throw new ParseException( I18n.err( I18n.ERR_04151 ), pos.start );
565 }
566
567 if ( b == ':' )
568 {
569
570 return parseExtensible( schemaManager, null, filter, pos, relaxed );
571 }
572 else
573 {
574
575 attribute = AttributeUtils.parseAttribute( filter, pos, true, relaxed );
576
577
578 b = Strings.byteAt( filter, pos.start );
579
580 switch ( b )
581 {
582 case '=':
583
584 pos.start++;
585 return parsePresenceEqOrSubstring( schemaManager, attribute, filter, pos );
586
587 case '~':
588
589 pos.start++;
590
591
592 if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
593 {
594 throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
595 }
596
597 pos.start++;
598
599
600 if ( schemaManager == null )
601 {
602 return new ApproximateNode( attribute, parseAssertionValue( schemaManager, attribute, filter,
603 pos ) );
604 }
605 else
606 {
607 AttributeType attributeType = schemaManager.getAttributeType( attribute );
608
609 if ( attributeType != null )
610 {
611 return new ApproximateNode( attributeType, parseAssertionValue( schemaManager, attribute,
612 filter, pos ) );
613 }
614 else
615 {
616 return UndefinedNode.UNDEFINED_NODE;
617 }
618 }
619
620 case '>':
621
622 pos.start++;
623
624
625 if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
626 {
627 throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
628 }
629
630 pos.start++;
631
632
633 if ( schemaManager == null )
634 {
635 return new GreaterEqNode( attribute,
636 parseAssertionValue( schemaManager, attribute, filter, pos ) );
637 }
638 else
639 {
640 AttributeType attributeType = schemaManager.getAttributeType( attribute );
641
642 if ( attributeType != null )
643 {
644 return new GreaterEqNode( attributeType, parseAssertionValue( schemaManager, attribute,
645 filter, pos ) );
646 }
647 else
648 {
649 return UndefinedNode.UNDEFINED_NODE;
650 }
651 }
652
653 case '<':
654
655 pos.start++;
656
657
658 if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
659 {
660 throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
661 }
662
663 pos.start++;
664
665
666 if ( schemaManager == null )
667 {
668 return new LessEqNode( attribute, parseAssertionValue( schemaManager, attribute, filter, pos ) );
669 }
670 else
671 {
672 AttributeType attributeType = schemaManager.getAttributeType( attribute );
673
674 if ( attributeType != null )
675 {
676 return new LessEqNode( attributeType, parseAssertionValue( schemaManager, attribute,
677 filter, pos ) );
678 }
679 else
680 {
681 return UndefinedNode.UNDEFINED_NODE;
682 }
683 }
684
685 case ':':
686
687 pos.start++;
688 return parseExtensible( schemaManager, attribute, filter, pos, relaxed );
689
690 default:
691
692 throw new ParseException( I18n.err( I18n.ERR_04153 ), pos.start );
693 }
694 }
695 }
696
697
698
699
700
701
702
703
704
705
706
707
708 private static ExprNode parseBranchNode( SchemaManager schemaManager, ExprNode node, byte[] filter, Position pos,
709 boolean relaxed ) throws ParseException, LdapException
710 {
711 BranchNode branchNode = ( BranchNode ) node;
712 int nbChildren = 0;
713
714
715 ExprNode child = parseFilterInternal( schemaManager, filter, pos, relaxed );
716
717 if ( child != UndefinedNode.UNDEFINED_NODE )
718 {
719
720 branchNode.addNode( child );
721
722 if ( branchNode instanceof NotNode )
723 {
724 return node;
725 }
726
727 nbChildren++;
728 }
729 else if ( node instanceof AndNode )
730 {
731 return UndefinedNode.UNDEFINED_NODE;
732 }
733
734
735 while ( ( child = parseFilterInternal( schemaManager, filter, pos, relaxed ) ) != UndefinedNode.UNDEFINED_NODE )
736 {
737
738 if ( child != null )
739 {
740 branchNode.addNode( child );
741 nbChildren++;
742 }
743 else if ( node instanceof AndNode )
744 {
745 return UndefinedNode.UNDEFINED_NODE;
746 }
747 }
748
749 if ( nbChildren > 0 )
750 {
751 return node;
752 }
753 else
754 {
755 return UndefinedNode.UNDEFINED_NODE;
756 }
757 }
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774 private static ExprNode parseFilterComp( SchemaManager schemaManager, byte[] filter, Position pos,
775 boolean relaxed ) throws ParseException, LdapException
776 {
777 ExprNode node = null;
778
779 if ( pos.start == pos.length )
780 {
781 throw new ParseException( I18n.err( I18n.ERR_04154 ), pos.start );
782 }
783
784 byte c = Strings.byteAt( filter, pos.start );
785
786 switch ( c )
787 {
788 case '&':
789
790 pos.start++;
791 node = new AndNode();
792 node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
793 break;
794
795 case '|':
796
797 pos.start++;
798 node = new OrNode();
799 node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
800 break;
801
802 case '!':
803
804 pos.start++;
805 node = new NotNode();
806 node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
807 break;
808
809 default:
810
811 node = parseItem( schemaManager, filter, pos, c, relaxed );
812 break;
813
814 }
815
816 return node;
817 }
818
819
820
821
822
823
824 private static ExprNode parseFilterInternal( SchemaManager schemaManager, byte[] filter, Position pos,
825 boolean relaxed ) throws ParseException, LdapException
826 {
827
828 if ( !Strings.isCharASCII( filter, pos.start, '(' ) )
829 {
830
831 if ( ( pos.start == 0 ) && ( pos.length != 0 ) )
832 {
833 throw new ParseException( I18n.err( I18n.ERR_04155 ), 0 );
834 }
835 else
836 {
837 return UndefinedNode.UNDEFINED_NODE;
838 }
839 }
840
841 pos.start++;
842
843
844 ExprNode node = parseFilterComp( schemaManager, filter, pos, relaxed );
845
846 if ( node == UndefinedNode.UNDEFINED_NODE )
847 {
848 return UndefinedNode.UNDEFINED_NODE;
849 }
850
851
852 if ( !Strings.isCharASCII( filter, pos.start, ')' ) )
853 {
854 throw new ParseException( I18n.err( I18n.ERR_04157 ), pos.start );
855 }
856
857 pos.start++;
858
859 return node;
860 }
861
862
863
864
865
866
867
868
869 public static ExprNode parse( String filter ) throws ParseException
870 {
871 return parse( null, Strings.getBytesUtf8( filter ), false );
872 }
873
874
875
876
877
878 public static ExprNode parse( byte[] filter ) throws ParseException
879 {
880 return parse( null, filter, false );
881 }
882
883
884
885
886
887 public static ExprNode parse( SchemaManager schemaManager, String filter ) throws ParseException
888 {
889 return parse( schemaManager, Strings.getBytesUtf8( filter ), false );
890 }
891
892
893
894
895
896 public static ExprNode parse( SchemaManager schemaManager, byte[] filter ) throws ParseException
897 {
898 return parse( schemaManager, filter, false );
899 }
900
901
902 private static ExprNode parse( SchemaManager schemaManager, byte[] filter, boolean relaxed )
903 throws ParseException
904 {
905
906 if ( Strings.isEmpty( filter ) )
907 {
908 throw new ParseException( I18n.err( I18n.ERR_04158 ), 0 );
909 }
910
911 Position pos = new Position();
912 pos.start = 0;
913 pos.end = 0;
914 pos.length = filter.length;
915
916 try
917 {
918 return parseFilterInternal( schemaManager, filter, pos, relaxed );
919 }
920 catch ( LdapException le )
921 {
922 throw new ParseException( le.getMessage(), pos.start );
923 }
924 }
925
926
927
928
929
930 public static ExprNode parse( SchemaManager schemaManager, String filter, Position pos ) throws ParseException
931 {
932
933 if ( Strings.isEmpty( filter ) )
934 {
935 throw new ParseException( I18n.err( I18n.ERR_04158 ), 0 );
936 }
937
938 pos.start = 0;
939 pos.end = 0;
940 pos.length = filter.length();
941
942 try
943 {
944 return parseFilterInternal( schemaManager, Strings.getBytesUtf8( filter ), pos, false );
945 }
946 catch ( LdapException le )
947 {
948 throw new ParseException( le.getMessage(), pos.start );
949 }
950 }
951
952
953
954
955
956
957
958
959
960
961
962 public static ExprNode parse( String filter, boolean relaxed ) throws ParseException
963 {
964 return parse( null, Strings.getBytesUtf8( filter ), relaxed );
965 }
966 }