From c421420f3d2f50253e4fcb90ba29382b38b6ef65 Mon Sep 17 00:00:00 2001 From: Max Usachev Date: Tue, 8 Jun 2010 14:09:49 +0300 Subject: [PATCH] added LDIF Parser/Generator --- parsers/ldif.py | 454 ++++++++++++++++++++++++++++++++++++++++++++++++++ parsers/test_ldif.py | 24 +++ 2 files changed, 478 insertions(+) create mode 100644 parsers/ldif.py create mode 100644 parsers/test_ldif.py diff --git a/parsers/ldif.py b/parsers/ldif.py new file mode 100644 index 0000000..5fee12f --- /dev/null +++ b/parsers/ldif.py @@ -0,0 +1,454 @@ +""" +ldif - generate and parse LDIF data (see RFC 2849) + +See http://www.python-ldap.org/ for details. + +$Id: ldif.py,v 1.52 2009/12/03 22:11:26 stroeder Exp $ + +Python compability note: +Tested with Python 2.0+, but should work with Python 1.5.2+. +""" + +__version__ = '2.3.11' + +__all__ = [ + # constants + 'ldif_pattern', + # functions + 'AttrTypeandValueLDIF','CreateLDIF','ParseLDIF', + # classes + 'LDIFWriter', + 'LDIFParser', + 'LDIFRecordList', + 'LDIFCopy', +] + +import urlparse,urllib,base64,re,types + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +attrtype_pattern = r'[\w;.]+(;[\w_-]+)*' +attrvalue_pattern = r'(([^,]|\\,)+|".*?")' +rdn_pattern = attrtype_pattern + r'[ ]*=[ ]*' + attrvalue_pattern +dn_pattern = rdn_pattern + r'([ ]*,[ ]*' + rdn_pattern + r')*[ ]*' +dn_regex = re.compile('^%s$' % dn_pattern) + +ldif_pattern = '^((dn(:|::) %(dn_pattern)s)|(%(attrtype_pattern)s(:|::) .*)$)+' % vars() + +MOD_OP_INTEGER = { + 'add':0,'delete':1,'replace':2 +} + +MOD_OP_STR = { + 0:'add',1:'delete',2:'replace' +} + +CHANGE_TYPES = ['add','delete','modify','modrdn'] +valid_changetype_dict = {} +for c in CHANGE_TYPES: + valid_changetype_dict[c]=None + + +def is_dn(s): + """ + returns 1 if s is a LDAP DN + """ + if s=='': + return 1 + rm = dn_regex.match(s) + return rm!=None and rm.group(0)==s + + +SAFE_STRING_PATTERN = '(^(\000|\n|\r| |:|<)|[\000\n\r\200-\377]+|[ ]+$)' +safe_string_re = re.compile(SAFE_STRING_PATTERN) + +def list_dict(l): + """ + return a dictionary with all items of l being the keys of the dictionary + """ + return dict([(i,None) for i in l]) + + +class LDIFWriter: + """ + Write LDIF entry or change records to file object + Copy LDIF input to a file output object containing all data retrieved + via URLs + """ + + def __init__(self,output_file,base64_attrs=None,cols=76,line_sep='\n'): + """ + output_file + file object for output + base64_attrs + list of attribute types to be base64-encoded in any case + cols + Specifies how many columns a line may have before it's + folded into many lines. + line_sep + String used as line separator + """ + self._output_file = output_file + self._base64_attrs = list_dict([a.lower() for a in (base64_attrs or [])]) + self._cols = cols + self._line_sep = line_sep + self.records_written = 0 + + def _unfoldLDIFLine(self,line): + """ + Write string line as one or more folded lines + """ + # Check maximum line length + line_len = len(line) + if line_len<=self._cols: + self._output_file.write(line) + self._output_file.write(self._line_sep) + else: + # Fold line + pos = self._cols + self._output_file.write(line[0:min(line_len,self._cols)]) + self._output_file.write(self._line_sep) + while pos