2 if not text:
3 return None
4 l = text.split(None, 1)
5 word = l[0]
6 try:
7 text = l[1]
8 except IndexError:
9 text = ''
10 return word, text
11
13 if not text:
14 return None
15 return text.split(None, 1)[0]
16
19 """Split text into $-separated list."""
20 r=[]
21 for x in text.split("$"):
22 x = x.strip()
23 assert x
24 r.append(x)
25 return tuple(r)
26
28 """Split ''-quoted strings into list."""
29 r=[]
30 while text:
31 text = text.lstrip()
32 if not text:
33 break
34 assert text[0]=="'", "Text %s must start with a single quote."%repr(text)
35 text=text[1:]
36 end=text.index("'")
37 r.append(text[:end])
38 text=text[end+1:]
39 return tuple(r)
40
42 s = ' '.join([self._str(x) for x in l])
43 if len(l) > 1:
44 s = '( %s )' % s
45 return s
46
48 s = ' $ '.join([x for x in l])
49 if len(l) > 1:
50 s = '( %s )' % s
51 return s
52
55
57 """
58 ASN Syntax::
59
60 d = "0" / "1" / "2" / "3" / "4" /
61 "5" / "6" / "7" / "8" / "9"
62
63 numericstring = 1*d
64
65 numericoid = numericstring *( "." numericstring )
66
67 space = 1*" "
68
69 whsp = [ space ]
70
71 descr = keystring
72
73 qdescr = whsp "'" descr "'" whsp
74
75 qdescrlist = [ qdescr *( qdescr ) ]
76
77 ; object descriptors used as schema element names
78 qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp )
79
80 dstring = 1*utf8
81
82 qdstring = whsp "'" dstring "'" whsp
83
84 descr = keystring
85
86 oid = descr / numericoid
87
88 woid = whsp oid whsp
89
90 ; set of oids of either form
91 oids = woid / ( "(" oidlist ")" )
92
93 ObjectClassDescription = "(" whsp
94 numericoid whsp ; ObjectClass identifier
95 [ "NAME" qdescrs ]
96 [ "DESC" qdstring ]
97 [ "OBSOLETE" whsp ]
98 [ "SUP" oids ] ; Superior ObjectClasses
99 [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
100 ; default structural
101 [ "MUST" oids ] ; AttributeTypes
102 [ "MAY" oids ] ; AttributeTypes
103 whsp ")"
104 """
105
106
108 self.oid=None
109 self.name=None
110 self.desc=None
111 self.obsolete=0
112 self.sup=[]
113 self.type=None
114 self.must=[]
115 self.may=[]
116
117 if text is not None:
118 self._parse(text)
119
121 assert text[0]=='(', "Text %s must be in parentheses."%repr(text)
122 assert text[-1]==')', "Text %s must be in parentheses."%repr(text)
123 text=text[1:-1]
124 text = text.lstrip()
125
126
127 self.oid, text = extractWord(text)
128
129 text = text.lstrip()
130
131 if peekWord(text) == "NAME":
132 text=text[len("NAME "):]
133 text = text.lstrip()
134 if text[0]=="'":
135 text=text[1:]
136 end=text.index("'")
137 self.name=(text[:end],)
138 text=text[end+1:]
139 elif text[0]=="(":
140 text=text[1:]
141 text = text.lstrip()
142 end=text.index(")")
143 self.name=self._strings_to_list(text[:end])
144 text=text[end+1:]
145 else:
146 raise NotImplementedError("TODO")
147
148
149 text = text.lstrip()
150
151 if peekWord(text) == "DESC":
152 text=text[len("DESC "):]
153 text = text.lstrip()
154 assert text[0]=="'"
155 text=text[1:]
156 end=text.index("'")
157 self.desc=text[:end]
158 text=text[end+1:]
159
160 text = text.lstrip()
161
162 if peekWord(text) == "OBSOLETE":
163 self.obsolete=1
164 text=text[len("OBSOLETE "):]
165
166 text = text.lstrip()
167
168 if peekWord(text) == "SUP":
169 text=text[len("SUP "):]
170 text = text.lstrip()
171 if text[0]=="(":
172 text=text[1:]
173 text = text.lstrip()
174 end=text.index(")")
175 self.sup=self._to_list(text[:end])
176 text=text[end+1:]
177 else:
178 s, text = extractWord(text)
179 self.sup=[s]
180
181 text = text.lstrip()
182
183 if peekWord(text) == "ABSTRACT":
184 assert self.type is None
185 self.type="ABSTRACT"
186 text=text[len("ABSTRACT "):]
187
188 text = text.lstrip()
189
190 if peekWord(text) == "STRUCTURAL":
191 assert self.type is None
192 self.type="STRUCTURAL"
193 text=text[len("STRUCTURAL "):]
194
195 text = text.lstrip()
196
197 if peekWord(text) == "AUXILIARY":
198 assert self.type is None
199 self.type="AUXILIARY"
200 text=text[len("AUXILIARY "):]
201
202 text = text.lstrip()
203
204 if peekWord(text) == "MUST":
205 text=text[len("MUST "):]
206 text = text.lstrip()
207 if text[0]=="(":
208 text=text[1:]
209 text = text.lstrip()
210 end=text.index(")")
211 self.must.extend(self._to_list(text[:end]))
212 text=text[end+1:]
213 else:
214 s, text = extractWord(text)
215 self.must.append(s)
216
217 text = text.lstrip()
218
219 if peekWord(text) == "MAY":
220 text=text[len("MAY "):]
221 text = text.lstrip()
222 if text[0]=="(":
223 text=text[1:]
224 text = text.lstrip()
225 end=text.index(")")
226 self.may.extend(self._to_list(text[:end]))
227 text=text[end+1:]
228 else:
229 s, text = extractWord(text)
230 self.may.append(s)
231
232 text = text.lstrip()
233
234 assert text=="", "Text was not empty: %s"%repr(text)
235
236 if not self.type:
237 self.type="STRUCTURAL"
238
239 assert self.oid
240 for c in self.oid:
241 assert c in "0123456789."
242 assert self.name is None or self.name
243 assert self.type in ("ABSTRACT", "STRUCTURAL", "AUXILIARY")
244
246 nice = {}
247 for k,v in self.__dict__.items():
248 nice[k]=repr(v)
249 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
250 +(" oid=%(oid)s name=%(name)s desc=%(desc)s"
251 +" obsolete=%(obsolete)s sup=%(sup)s type=%(type)s"
252 +" must=%(must)s may=%(may)s>")%nice)
253
255 r=[]
256 if self.name is not None:
257 r.append('NAME %s' % self._str_list(self.name))
258 if self.desc is not None:
259 r.append('DESC %s' % self._str(self.desc))
260 if self.obsolete:
261 r.append('OBSOLETE')
262 if self.sup:
263 r.append('SUP %s' % self._list(self.sup))
264 r.append('%s' % self.type)
265 if self.must:
266 r.append('MUST %s' % self._list(self.must))
267 if self.may:
268 r.append('MAY %s' % self._list(self.may))
269 return ('( %s ' % self.oid
270 + '\n '.join(r)
271 + ' )')
272
280
288
291
294
306
308 return not (self == other)
309
311 """
312 ASN Syntax::
313
314 AttributeTypeDescription = "(" whsp
315 numericoid whsp ; AttributeType identifier
316 [ "NAME" qdescrs ] ; name used in AttributeType
317 [ "DESC" qdstring ] ; description
318 [ "OBSOLETE" whsp ]
319 [ "SUP" woid ] ; derived from this other AttributeType
320 [ "EQUALITY" woid ; Matching Rule name
321 [ "ORDERING" woid ; Matching Rule name
322 [ "SUBSTR" woid ] ; Matching Rule name
323 [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3
324 [ "SINGLE-VALUE" whsp ] ; default multi-valued
325 [ "COLLECTIVE" whsp ] ; default not collective
326 [ "NO-USER-MODIFICATION" whsp ]; default user modifiable
327 [ "USAGE" whsp AttributeUsage ]; default userApplications
328 whsp ")"
329
330 AttributeUsage =
331 "userApplications" /
332 "directoryOperation" /
333 "distributedOperation" / ; DSA-shared
334 "dSAOperation" ; DSA-specific, value depends on server
335
336 noidlen = numericoid [ "{" len "}" ]
337
338 len = numericstring
339 """
340
342 self.oid=None
343 self.name=None
344 self.desc=None
345 self.obsolete=0
346 self.sup=None
347 self.equality=None
348 self.ordering=None
349 self.substr=None
350 self.syntax=None
351 self.single_value=None
352 self.collective=None
353 self.no_user_modification=None
354 self.usage=None
355
356
357
358 self.x_attrs=[]
359
360 if text is not None:
361 self._parse(text)
362
364 assert text[0]=='(', "Text %s must be in parentheses."%repr(text)
365 assert text[-1]==')', "Text %s must be in parentheses."%repr(text)
366 text=text[1:-1]
367 text = text.lstrip()
368
369
370 self.oid, text = extractWord(text)
371
372 text = text.lstrip()
373
374 if peekWord(text) == "NAME":
375 text=text[len("NAME "):]
376 text = text.lstrip()
377 if text[0]=="'":
378 text=text[1:]
379 end=text.index("'")
380 self.name=(text[:end],)
381 text=text[end+1:]
382 elif text[0]=="(":
383 text=text[1:]
384 text = text.lstrip()
385 end=text.index(")")
386 self.name=self._strings_to_list(text[:end])
387 text=text[end+1:]
388 else:
389 raise NotImplementedError("TODO")
390
391
392 text = text.lstrip()
393
394 if peekWord(text) == "DESC":
395 text=text[len("DESC "):]
396 text = text.lstrip()
397 assert text[0]=="'"
398 text=text[1:]
399 end=text.index("'")
400 self.desc=text[:end]
401 text=text[end+1:]
402
403 text = text.lstrip()
404
405 if peekWord(text) == "OBSOLETE":
406 self.obsolete=1
407 text=text[len("OBSOLETE "):]
408
409 text = text.lstrip()
410
411 if peekWord(text) == "SUP":
412 text=text[len("SUP "):]
413 text = text.lstrip()
414 self.sup, text = extractWord(text)
415
416 text = text.lstrip()
417
418 if peekWord(text) == "EQUALITY":
419 text=text[len("EQUALITY "):]
420 text = text.lstrip()
421 self.equality, text = extractWord(text)
422
423 text = text.lstrip()
424
425 if peekWord(text) == "ORDERING":
426 text=text[len("ORDERING "):]
427 text = text.lstrip()
428 self.ordering, text = extractWord(text)
429
430 text = text.lstrip()
431
432 if peekWord(text) == "SUBSTR":
433 text=text[len("SUBSTR "):]
434 text = text.lstrip()
435 self.substr, text = extractWord(text)
436
437 text = text.lstrip()
438
439 if peekWord(text) == "SYNTAX":
440 text=text[len("SYNTAX "):]
441 text = text.lstrip()
442 self.syntax, text = extractWord(text)
443
444 text = text.lstrip()
445
446 if peekWord(text) == "SINGLE-VALUE":
447 assert self.single_value is None
448 self.single_value=1
449 text=text[len("SINGLE-VALUE "):]
450
451 text = text.lstrip()
452
453 if peekWord(text) == "COLLECTIVE":
454 assert self.collective is None
455 self.collective=1
456 text=text[len("COLLECTIVE "):]
457
458 text = text.lstrip()
459
460 if peekWord(text) == "NO-USER-MODIFICATION":
461 assert self.no_user_modification is None
462 self.no_user_modification=1
463 text=text[len("NO-USER-MODIFICATION "):]
464
465 text = text.lstrip()
466
467 if peekWord(text) == "USAGE":
468 assert self.usage is None
469 text=text[len("USAGE "):]
470 text = text.lstrip()
471 self.usage, text = extractWord(text)
472
473
474 while True:
475 text = text.lstrip()
476
477 word = peekWord(text)
478 if word is None:
479 break
480
481 if word.startswith('X-'):
482 text=text[len(word+" "):]
483 text = text.lstrip()
484 if text[0]=="'":
485 text=text[1:]
486 end=text.index("'")
487 value=text[:end]
488 text=text[end+1:]
489 elif text[0]=="(":
490 text=text[1:]
491 text = text.lstrip()
492 end=text.index(")")
493 value=self._strings_to_list(text[:end])
494 text=text[end+1:]
495 else:
496 raise "TODO"
497
498 self.x_attrs.append((word, value))
499 else:
500 raise RuntimeError('Unhandled attributeType: %r', word)
501
502 assert text=="", "Text was not empty: %s"%repr(text)
503
504 if self.single_value is None:
505 self.single_value=0
506
507 if self.collective is None:
508 self.collective=0
509
510 if self.no_user_modification is None:
511 self.no_user_modification=0
512
513 assert self.oid
514 for c in self.oid:
515 assert c in "0123456789."
516 assert self.name is None or self.name
517 assert self.usage is None or self.usage in (
518 "userApplications",
519 "directoryOperation",
520 "distributedOperation",
521 "dSAOperation",
522 )
523
525 nice = {}
526 for k,v in self.__dict__.items():
527 nice[k]=repr(v)
528 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
529 +(" oid=%(oid)s name=%(name)s desc=%(desc)s"
530 +" obsolete=%(obsolete)s sup=%(sup)s"
531 +" equality=%(equality)s ordering=%(ordering)s"
532 +" substr=%(substr)s syntax=%(syntax)s"
533 +" single_value=%(single_value)s"
534 +" collective=%(collective)s"
535 +" no_user_modification=%(no_user_modification)s"
536 +" usage=%(usage)s>")%nice)
537
539 r=[]
540 if self.name is not None:
541 r.append('NAME %s' % self._str_list(self.name))
542 if self.desc is not None:
543 r.append('DESC %s' % self._str(self.desc))
544 if self.obsolete:
545 r.append('OBSOLETE')
546 if self.sup is not None:
547 r.append('SUP %s' % self.sup)
548 if self.equality is not None:
549 r.append('EQUALITY %s' % self.equality)
550 if self.ordering is not None:
551 r.append('ORDERING %s' % self.ordering)
552 if self.substr is not None:
553 r.append('SUBSTR %s' % self.substr)
554 if self.syntax is not None:
555 r.append('SYNTAX %s' % self.syntax)
556 if self.single_value:
557 r.append('SINGLE-VALUE')
558 if self.collective:
559 r.append('COLLECTIVE')
560 if self.no_user_modification:
561 r.append('NO-USER-MODIFICATION')
562 if self.usage is not None:
563 r.append('USAGE %s' % self.usage)
564 for name, value in self.x_attrs:
565 if isinstance(value, basestring):
566 r.append("%s '%s'" % (name, value))
567 else:
568 r.append(
569 '%s ( %s )' % (
570 name,
571 ' '.join("'%s'" % s for s in value),
572 ),
573 )
574 return ('( %s ' % self.oid
575 + '\n '.join(r)
576 + ' )')
577
579 """
580 ASN Syntax::
581
582 SyntaxDescription = "(" whsp
583 numericoid whsp
584 [ "DESC" qdstring ]
585 whsp ")"
586 """
587
589 self.oid=None
590 self.desc=None
591
592 assert text[0]=='('
593 assert text[-1]==')'
594 text=text[1:-1]
595 text = text.lstrip()
596
597
598 self.oid, text = extractWord(text)
599
600 text = text.lstrip()
601
602 if peekWord(text) == "DESC":
603 text=text[len("DESC "):]
604 text = text.lstrip()
605 assert text[0]=="'"
606 text=text[1:]
607 end=text.index("'")
608 self.desc=text[:end]
609 text=text[end+1:]
610
611 text = text.lstrip()
612
613 if peekWord(text) == "X-BINARY-TRANSFER-REQUIRED":
614 text=text[len("X-BINARY-TRANSFER-REQUIRED "):]
615 text = text.lstrip()
616 assert text[0]=="'"
617 text=text[1:]
618 end=text.index("'")
619 self.desc=text[:end]
620 text=text[end+1:]
621
622 text = text.lstrip()
623
624 if peekWord(text) == "X-NOT-HUMAN-READABLE":
625 text=text[len("X-NOT-HUMAN-READABLE "):]
626 text = text.lstrip()
627 assert text[0]=="'"
628 text=text[1:]
629 end=text.index("'")
630 self.desc=text[:end]
631 text=text[end+1:]
632
633 text = text.lstrip()
634
635 assert text=="", "Text was not empty: %s"%repr(text)
636
637 assert self.oid
638 for c in self.oid:
639 assert c in "0123456789."
640
642 nice = {}
643 for k,v in self.__dict__.items():
644 nice[k]=repr(v)
645 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
646 +(" oid=%(oid)s desc=%(desc)s>")%nice)
647
648
649
651 """
652 ASN Syntax::
653
654 MatchingRuleDescription = "(" whsp
655 numericoid whsp ; MatchingRule identifier
656 [ "NAME" qdescrs ]
657 [ "DESC" qdstring ]
658 [ "OBSOLETE" whsp ]
659 "SYNTAX" numericoid
660 whsp ")"
661 """
662
664 self.oid=None
665 self.name=None
666 self.desc=None
667 self.obsolete=None
668 self.syntax=None
669
670 assert text[0]=='('
671 assert text[-1]==')'
672 text=text[1:-1]
673 text = text.lstrip()
674
675
676 self.oid, text = extractWord(text)
677
678 text = text.lstrip()
679
680 if peekWord(text) == "NAME":
681 text=text[len("NAME "):]
682 text = text.lstrip()
683 if text[0]=="'":
684 text=text[1:]
685 end=text.index("'")
686 self.name=(text[:end],)
687 text=text[end+1:]
688 elif text[0]=="(":
689 text=text[1:]
690 text = text.lstrip()
691 end=text.index(")")
692 self.name=self._strings_to_list(text[:end])
693 text=text[end+1:]
694 else:
695 raise NotImplementedError("TODO")
696
697 text = text.lstrip()
698
699 if peekWord(text) == "DESC":
700 text=text[len("DESC "):]
701 text = text.lstrip()
702 assert text[0]=="'"
703 text=text[1:]
704 end=text.index("'")
705 self.desc=text[:end]
706 text=text[end+1:]
707
708 text = text.lstrip()
709
710 if peekWord(text) == "OBSOLETE":
711 self.obsolete=1
712 text=text[len("OBSOLETE "):]
713
714 text = text.lstrip()
715
716 if peekWord(text) == "SYNTAX":
717 text=text[len("SYNTAX "):]
718 text = text.lstrip()
719 self.syntax, text = extractWord(text)
720
721 text = text.lstrip()
722
723 assert text=="", "Text was not empty: %s"%repr(text)
724
725 if self.obsolete is None:
726 self.obsolete=0
727 assert self.oid
728 for c in self.oid:
729 assert c in "0123456789."
730 assert self.syntax
731
733 nice = {}
734 for k,v in self.__dict__.items():
735 nice[k]=repr(v)
736 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self))
737 +(" oid=%(oid)s desc=%(desc)s>")%nice)
738