p11_kit_iter_load_attributes (P11KitIter *iter,
                              CK_ATTRIBUTE *template,
                              CK_ULONG count)
{
	CK_ATTRIBUTE *original = NULL;
	CK_ULONG i;
	CK_RV rv;

	return_val_if_fail (iter != NULL, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->iterating, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->module != NULL, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->session != 0, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->object != 0, CKR_GENERAL_ERROR);

	if (count == 0)
		return CKR_OK;

	original = memdup (template, count * sizeof (CK_ATTRIBUTE));
	return_val_if_fail (original != NULL, CKR_HOST_MEMORY);

	for (i = 0; i < count; i++)
		template[i].pValue = NULL;

	rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count);

	switch (rv) {
	case CKR_OK:
	case CKR_ATTRIBUTE_TYPE_INVALID:
	case CKR_ATTRIBUTE_SENSITIVE:
	case CKR_BUFFER_TOO_SMALL:
		break;
	default:
		free (original);
		return rv;
	}

	for (i = 0; i < count; i++) {
		if (template[i].ulValueLen == (CK_ULONG)-1 ||
		    template[i].ulValueLen == 0) {
			free (original[i].pValue);

		} else if (original[i].pValue != NULL &&
		           template[i].ulValueLen == original[i].ulValueLen) {
			template[i].pValue = original[i].pValue;

		} else {
			template[i].pValue = realloc (original[i].pValue, template[i].ulValueLen);
			return_val_if_fail (template[i].pValue != NULL, CKR_HOST_MEMORY);
		}
	}

	free (original);

	rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count);

	switch (rv) {
	case CKR_OK:
	case CKR_ATTRIBUTE_TYPE_INVALID:
	case CKR_ATTRIBUTE_SENSITIVE:
		rv = CKR_OK;
		break;
	default:
		return_val_if_fail (rv != CKR_BUFFER_TOO_SMALL, rv);
		return rv;
	}

	for (i = 0; i < count; i++) {
		if (template[i].ulValueLen == (CK_ULONG)-1 ||
		    template[i].ulValueLen == 0) {
			free (template[i].pValue);
			template[i].pValue = NULL;
		}
	}

	return rv;
}
p11_kit_iter_load_attributes (P11KitIter *iter,
                              CK_ATTRIBUTE *template,
                              CK_ULONG count)
{
	CK_ATTRIBUTE *original = NULL;
	CK_ULONG i;
	CK_RV rv;

	return_val_if_fail (iter != NULL, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->iterating, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->module != NULL, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->session != 0, CKR_GENERAL_ERROR);
	return_val_if_fail (iter->object != 0, CKR_GENERAL_ERROR);

	if (count == 0)
		return CKR_OK;

	original = memdup (template, count * sizeof (CK_ATTRIBUTE));
	return_val_if_fail (original != NULL, CKR_HOST_MEMORY);

	for (i = 0; i < count; i++)
		template[i].pValue = NULL;

	rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count);

	switch (rv) {
	case CKR_OK:
	case CKR_ATTRIBUTE_TYPE_INVALID:
	case CKR_ATTRIBUTE_SENSITIVE:
	case CKR_BUFFER_TOO_SMALL:
		break;
	default:
		free (original);
		return rv;
	}

	for (i = 0; i < count; i++) {
		if (template[i].ulValueLen == (CK_ULONG)-1 ||
		    template[i].ulValueLen == 0) {
			free (original[i].pValue);

		} else if (original[i].pValue != NULL &&
		           template[i].ulValueLen == original[i].ulValueLen) {
			template[i].pValue = original[i].pValue;

		} else {
			template[i].pValue = realloc (original[i].pValue, template[i].ulValueLen);
			return_val_if_fail (template[i].pValue != NULL, CKR_HOST_MEMORY);
		}
	}

	free (original);

	rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count);

	switch (rv) {
	case CKR_OK:
	case CKR_ATTRIBUTE_TYPE_INVALID:
	case CKR_ATTRIBUTE_SENSITIVE:
		rv = CKR_OK;
		break;
	default:
		return_val_if_fail (rv != CKR_BUFFER_TOO_SMALL, rv);
		return rv;
	}

	for (i = 0; i < count; i++) {
		if (template[i].ulValueLen == (CK_ULONG)-1 ||
		    template[i].ulValueLen == 0) {
			free (template[i].pValue);
			template[i].pValue = NULL;
		}
	}

	return rv;
}