asn1rt: first step to CLASS set / table constraint with non-unique key
This commit is contained in:
parent
2344b27e33
commit
199666cfdf
|
@ -1127,6 +1127,17 @@ def verify_modules(**kwargs):
|
|||
if not _verify_const_val(val, consts_glob, mod, name, Objs.index(O)):
|
||||
warn('{0}.{1}: internal object {2}, value outside of the constraint'\
|
||||
.format(mod, name, Objs.index(O)), raising)
|
||||
#
|
||||
# 4) for SEQ / SET, in case it contains an OPEN object with a table constraint
|
||||
# check the unicity of values associated to the key to the table
|
||||
elif O._mode == MODE_TYPE and O.TYPE in (TYPE_SET, TYPE_SEQ) and O._cont:
|
||||
for comp in O._cont.values():
|
||||
if comp.TYPE in (TYPE_OPEN, TYPE_ANY) and comp._const:
|
||||
for const in comp._const:
|
||||
if const['type'] == CONST_TABLE:
|
||||
if not _verify_seq_const_tab(O, comp._name, const):
|
||||
asnlog('WNG: {0}.{1}: internal object {2}, non-unique key subvalue '\
|
||||
'within a table constraint'.format(mod, name, Objs.index(O)))
|
||||
|
||||
|
||||
def _verify_const_size(val, consts):
|
||||
|
@ -1169,6 +1180,47 @@ def _verify_const_val(val, consts, mod, name, ind):
|
|||
return False
|
||||
|
||||
|
||||
def _verify_seq_const_tab(Obj, open_name, const_tab):
|
||||
# check within a sequence with one of its component being an OPEN type
|
||||
# that the key to the table constraint has unique values
|
||||
comp_open = Obj._cont[open_name]
|
||||
tab_key = const_tab['at']
|
||||
if not tab_key or len(tab_key) != 2 or tab_key[0] != '..' or tab_key[1] not in Obj._cont:
|
||||
# no key component defined or
|
||||
# complex path to key component, unable to make the verification
|
||||
return True
|
||||
# get the full tab put into a single list of values
|
||||
tab = const_tab['tab']._val['root']
|
||||
if const_tab['tab']._val['ext']:
|
||||
# create a new list concatenating the root and ext part
|
||||
tab = tab + const_tab['tab']._val['ext']
|
||||
# for all values, check the one associated to the key component
|
||||
comp_key = Obj._cont[tab_key[1]]
|
||||
id_key = comp_key.get_typeref()._name
|
||||
val_key, val_all, ret = [], [], True
|
||||
for val in tab:
|
||||
if id_key not in val:
|
||||
#asnlog('[WNG] constraint table value without key subvalue %s: %r' % (id_key, val))
|
||||
pass
|
||||
else:
|
||||
if val[id_key] in val_key:
|
||||
# duplicated key subvalue, get the corresponding complete value
|
||||
if val != val_all[ val_key.index(val[id_key]) ]:
|
||||
# Houston, we got a problem !
|
||||
#asnlog('[WNG] constraint table with duplicated key subvalue %s: %r, '\
|
||||
# 'and different associated value' % (id_key, val[id_key]))
|
||||
#assert()
|
||||
ret = False
|
||||
else:
|
||||
# duplicated key subvalue, with hopefully same value
|
||||
# nothing to do here
|
||||
pass
|
||||
else:
|
||||
val_key.append( val[id_key] )
|
||||
val_all.append( val )
|
||||
return ret
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------#
|
||||
# ASN.1 modules generation
|
||||
#------------------------------------------------------------------------------#
|
||||
|
|
|
@ -82,6 +82,11 @@ Specific method:
|
|||
TYPE = TYPE_CLASS
|
||||
TAG = None
|
||||
|
||||
# this is to always enumerate all class set of values,
|
||||
# for when the UNIQUE field is actually not unique and the class set is
|
||||
# not defined at the module root (and hence has not _lut attribute)
|
||||
_CLASET_MULT = False
|
||||
|
||||
def _safechk_val(self, val):
|
||||
if not isinstance(val, dict) or not all([k in self._cont for k in val]):
|
||||
raise(ASN1ObjErr('{0}: invalid value, {1!r}'.format(self.fullname(), val)))
|
||||
|
@ -160,6 +165,61 @@ Specific method:
|
|||
pass
|
||||
return None
|
||||
|
||||
def get(self, key, val):
|
||||
# this is using the _lut attribute, which is built at module init
|
||||
# for every CLASS set defined at the root of a module
|
||||
if hasattr(self, '_lut'):
|
||||
if key == self._lut['__lut__']:
|
||||
return self._lut.get(val, (CLASET_NONE, None))
|
||||
if self._CLASET_MULT:
|
||||
return self.get_mult(key, val)
|
||||
else:
|
||||
return self.get_uniq(key, val)
|
||||
|
||||
def get_uniq(self, name, val):
|
||||
# this is using an enumeration of all CLASS set of values,
|
||||
# and returns the first corresponding value found
|
||||
ret = None
|
||||
if self._mode != MODE_SET:
|
||||
return ret
|
||||
if self._val.root:
|
||||
for v in self._val.root:
|
||||
try:
|
||||
if v[name] == val:
|
||||
return v
|
||||
except KeyError:
|
||||
pass
|
||||
if self._val.ext:
|
||||
for v in self._val.ext:
|
||||
try:
|
||||
if v[name] == val:
|
||||
return v
|
||||
except KeyError:
|
||||
pass
|
||||
return ret
|
||||
|
||||
def get_mult(self, name, val):
|
||||
# this is using a complete enumeration of all CLASS set of values,
|
||||
# and returns the list of corresponding values found
|
||||
ret = []
|
||||
if self._mode != MODE_SET:
|
||||
return ret
|
||||
if self._val.root:
|
||||
for v in self._val.root:
|
||||
try:
|
||||
if v[name] == val:
|
||||
ret.append(v)
|
||||
except KeyError:
|
||||
pass
|
||||
if self._val.ext:
|
||||
for v in self._val.ext:
|
||||
try:
|
||||
if v[name] == val:
|
||||
ret.append(v)
|
||||
except KeyError:
|
||||
pass
|
||||
return ret
|
||||
|
||||
# this is very experimental... and may certainly raise() in case of
|
||||
# MODE_SET or MODE_TYPE field setting
|
||||
def from_asn1(self, txt):
|
||||
|
|
|
@ -203,10 +203,16 @@ def init_modules(*args, **kwargs):
|
|||
elif Obj.TYPE == TYPE_OID and Obj._mode == MODE_VALUE:
|
||||
if Obj._val in GLOB.OID and GLOB.OID[Obj._val] != Obj._name:
|
||||
if not Obj._SILENT:
|
||||
asnlog('init_modules: different OID objects (%s, %s) with same OID value (%r)'\
|
||||
asnlog('init_modules: different OID objects (%s, %s) with same OID value %r'\
|
||||
% (Obj._name, GLOB.OID[Obj._val], Obj._val))
|
||||
elif Obj._val is not None:
|
||||
GLOB.OID[Obj._val] = Obj._name
|
||||
#
|
||||
elif Obj.TYPE == TYPE_CLASS and Obj._mode == MODE_SET and Obj._val:
|
||||
# this should not conflict with the previous check on TYPE_CLASS
|
||||
# which must have self._cont defined (hence being MODE_TYPE)
|
||||
build_classset_dict(Obj)
|
||||
|
||||
#
|
||||
# lists all objects defined
|
||||
Objs = [Obj for Mod in args for Obj in Mod._all_]
|
||||
|
@ -351,6 +357,7 @@ def get_typeref(Obj, GLOB=GLOBAL):
|
|||
#
|
||||
return tr
|
||||
|
||||
|
||||
def get_tag_chain(Obj):
|
||||
"""
|
||||
returns the list of tags from self up to the last referred object
|
||||
|
@ -372,6 +379,7 @@ def get_tag_chain(Obj):
|
|||
tagc.append( (0, Obj.TAG) )
|
||||
return tagc
|
||||
|
||||
|
||||
def get_cont_tags_dict(Obj):
|
||||
"""
|
||||
returns the ASN1Dict of tags, object for the content of Obj (SET and CHOICE)
|
||||
|
@ -403,6 +411,7 @@ def get_cont_tags_dict(Obj):
|
|||
tagd[Comp._tagc[0]] = ident
|
||||
return tagd
|
||||
|
||||
|
||||
def get_cont_tags_canon(Obj):
|
||||
"""
|
||||
returns the list of components in the canonical order of their tags
|
||||
|
@ -430,6 +439,7 @@ def get_cont_tags_canon(Obj):
|
|||
# order the whole stuff
|
||||
return [tagcan[k] for k in sorted(tagcan.keys())]
|
||||
|
||||
|
||||
def bind_attrs(Obj, *attrs):
|
||||
attr = attrs[0]
|
||||
if getattr(Obj, attr) is None:
|
||||
|
@ -454,6 +464,7 @@ def bind_attrs(Obj, *attrs):
|
|||
else:
|
||||
tr = tr._tr if (tr._tr is not None and not tr._tr._param) else None
|
||||
|
||||
|
||||
def bind_all_attrs(Obj):
|
||||
# bind content and constraints from typeref objects
|
||||
# _cont, _root, _ext, _root_mand, _root_opt, _ext_ident, _ext_group, cont_tags
|
||||
|
@ -491,3 +502,43 @@ def bind_all_attrs(Obj):
|
|||
bind_attrs(Obj, '_cont', '_root', '_root_mand', '_root_opt')
|
||||
bind_attrs(Obj, '_ext')
|
||||
|
||||
|
||||
def build_classset_dict(Obj):
|
||||
key = None
|
||||
tr = get_typeref(Obj)
|
||||
while not tr._cont:
|
||||
tr = get_typeref(tr)
|
||||
if tr is None:
|
||||
break
|
||||
if tr._cont is None:
|
||||
# something is screwed somewhere
|
||||
return
|
||||
for Comp in tr._cont.values():
|
||||
if Comp._uniq:
|
||||
key = Comp._name
|
||||
if key is None:
|
||||
return
|
||||
# check the key (UNIQUE) component
|
||||
Obj._lut = {'__key__': key}
|
||||
__build_classet_dict(Obj, key, Obj._val.root)
|
||||
if Obj._val.ext:
|
||||
__build_classet_dict(Obj, key, Obj._val.ext)
|
||||
|
||||
|
||||
def __build_classet_dict(Obj, key, valset):
|
||||
for val in valset:
|
||||
if key in val:
|
||||
keyval = val[key]
|
||||
if keyval in Obj._lut:
|
||||
# this is not as UNIQUE as one can think...
|
||||
lutval = Obj._lut[keyval]
|
||||
if lutval[0] == CLASET_UNIQ:
|
||||
# switching to MULT
|
||||
Obj._lut[keyval] = (CLASET_MULT, [lutval, val])
|
||||
else:
|
||||
# already defined as MULT
|
||||
lutval[1].append(val)
|
||||
else:
|
||||
# this is the first (and hopefully UNIQUE) value
|
||||
Obj._lut[keyval] = (CLASET_UNIQ, val)
|
||||
|
||||
|
|
|
@ -291,6 +291,11 @@ FLAG_UNIQ = 'UNIQUE'
|
|||
FLAG_DEF = 'DEFAULT'
|
||||
FLAG_DEFBY = 'DEFINED BY'
|
||||
|
||||
# specific flags for CLASS set of values, for specific use as table constraint
|
||||
CLASET_UNIQ = 'U'
|
||||
CLASET_MULT = 'M'
|
||||
CLASET_NONE = 'N'
|
||||
|
||||
#------------------------------------------------------------------------------#
|
||||
# asn1rt naming routine
|
||||
#------------------------------------------------------------------------------#
|
||||
|
|
Loading…
Reference in New Issue