@@ -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