@@ -47,6 +47,16 @@ cdef assertRV(rv) with gil:
4747    raise  map_rv_to_error(rv)
4848
4949
50+ cdef inline CK_BBOOL _is_template_attr(CK_ATTRIBUTE_TYPE type ):
51+     cdef CK_ULONG mask =  0xf 
52+     cdef CK_ULONG mask_result =  (type  ^  ATTR_TEMPLATE_ATTRIBUTE) &  ~ mask
53+     return  < CK_BBOOL>  (not  mask_result)
54+ 
55+ 
56+ def  template_as_attribute_list (template , attribute_mapper = None ):
57+     return  AttributeList.from_template(template, attribute_mapper or  AttributeMapper())
58+ 
59+ 
5060cdef class  AttributeList:
5161    """ 
5262    A list of CK_ATTRIBUTE objects. 
@@ -81,15 +91,22 @@ cdef class AttributeList:
8191        cdef bytes value_bytes
8292        cdef CK_CHAR *  value_ptr
8393        cdef Py_ssize_t value_len
94+         cdef AttributeList template_list
8495        for  index, (key, value) in  enumerate (template.items()):
8596            lst.data[index].type =  key
86-             value_bytes =  attribute_mapper.pack_attribute(key, value)
87-             value_len =  len (value_bytes)
88-             #  copy the result into a pointer that we manage, for consistency with the other init method
89-             value_ptr =  < CK_CHAR * >  PyMem_Malloc(value_len)
90-             if  value_ptr is  NULL :
91-                 raise  MemoryError ()
92-             memcpy(value_ptr, < CK_CHAR * >  value_bytes, < size_t>  value_len)
97+             if  _is_template_attr(key):
98+                 template_list =  AttributeList.from_template(value, attribute_mapper)
99+                 value_len =  < Py_ssize_t>  template_list.count *  sizeof(CK_ATTRIBUTE)
100+                 value_ptr =  < CK_CHAR * >  template_list.data
101+                 template_list.data =  NULL 
102+             else :
103+                 value_bytes =  attribute_mapper.pack_attribute(key, value)
104+                 value_len =  len (value_bytes)
105+                 #  copy the result into a pointer that we manage, for consistency with the other init method
106+                 value_ptr =  < CK_CHAR * >  PyMem_Malloc(value_len)
107+                 if  value_ptr is  NULL :
108+                     raise  MemoryError ()
109+                 memcpy(value_ptr, < CK_CHAR * >  value_bytes, < size_t>  value_len)
93110            lst.data[index].pValue =  < CK_CHAR * >  value_ptr
94111            lst.data[index].ulValueLen =  < CK_ULONG>  value_len
95112
@@ -102,10 +119,21 @@ cdef class AttributeList:
102119        cdef CK_ATTRIBUTE *  attr
103120        if  index <  self .count:
104121            attr =  & self .data[index]
105-             return  attribute_mapper.unpack_attributes(
106-                 attr.type,
107-                 PyBytes_FromStringAndSize(< char  * >  attr.pValue, < Py_ssize_t>  attr.ulValueLen)
108-             )
122+             if  _is_template_attr(attr.type):
123+                 template_lst =  AttributeList.from_owned_pointer(
124+                     < CK_ATTRIBUTE * >  attr.pValue,
125+                     attr.ulValueLen //  sizeof(CK_ATTRIBUTE)
126+                 )
127+                 result =  template_lst.as_dict(attribute_mapper)
128+                 #  prevent __dealloc__ from cleaning up this memory,
129+                 #  we just needed the .as_dict(...)
130+                 template_lst.data =  NULL 
131+                 return  result
132+             else :
133+                 return  attribute_mapper.unpack_attributes(
134+                     attr.type,
135+                     PyBytes_FromStringAndSize(< char  * >  attr.pValue, < Py_ssize_t>  attr.ulValueLen)
136+                 )
109137        else :
110138            raise  IndexError ()
111139
@@ -125,12 +153,25 @@ cdef class AttributeList:
125153                return  self .at_index(index, attribute_mapper)
126154        raise  KeyError (item)
127155
128-     def   __dealloc__ (self ):
156+     cdef _free (self ):
129157        cdef CK_ULONG index =  0 
158+         cdef CK_ATTRIBUTE current
130159        if  self .data is  not  NULL :
131160            for  index in  range (self .count):
132-                 PyMem_Free(self .data[index].pValue)
161+                 current =  self .data[index]
162+                 if  _is_template_attr(current.type):
163+                     #  ensure template lists are cleaned up
164+                     AttributeList.from_owned_pointer(
165+                         < CK_ATTRIBUTE * >  current.pValue,
166+                         current.ulValueLen //  sizeof(CK_ATTRIBUTE)
167+                     )._free()
168+                 else :
169+                     PyMem_Free(current.pValue)
133170            PyMem_Free(self .data)
171+             self .data =  NULL 
172+ 
173+     def  __dealloc__ (self ):
174+         self ._free()
134175
135176
136177cdef class  MechanismWithParam:
0 commit comments