xref: /freebsd/contrib/pkgconf/cli/spdxtool/software.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery  * SPDX-License-Identifier: BSD-2-Clause
3*592efe25SPierre Pronchery  *
4*592efe25SPierre Pronchery  *​ Copyright (c) 2025 The FreeBSD Foundation
5*592efe25SPierre Pronchery  *​
6*592efe25SPierre Pronchery  *​ Portions of this software were developed by
7*592efe25SPierre Pronchery  * Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
8*592efe25SPierre Pronchery  * the FreeBSD Foundation
9*592efe25SPierre Pronchery  */
10*592efe25SPierre Pronchery 
11*592efe25SPierre Pronchery #include <stdlib.h>
12*592efe25SPierre Pronchery #include <string.h>
13*592efe25SPierre Pronchery #include <libpkgconf/libpkgconf.h>
14*592efe25SPierre Pronchery #include "util.h"
15*592efe25SPierre Pronchery #include "serialize.h"
16*592efe25SPierre Pronchery #include "software.h"
17*592efe25SPierre Pronchery #include "core.h"
18*592efe25SPierre Pronchery 
19*592efe25SPierre Pronchery /*
20*592efe25SPierre Pronchery  * !doc
21*592efe25SPierre Pronchery  *
22*592efe25SPierre Pronchery  * .. c:function:: spdxtool_software_sbom_t *spdxtool_software_sbom_new(pkgconf_client_t *client, const char *spdx_id, const char *creation_id, const char *sbom_type)
23*592efe25SPierre Pronchery  *
24*592efe25SPierre Pronchery  *    Create new /Software/Sbom struct
25*592efe25SPierre Pronchery  *
26*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
27*592efe25SPierre Pronchery  *    :param const char *spdx_id: spdxId for this SBOM element
28*592efe25SPierre Pronchery  *    :param const char *creation_id: id for CreationInfo
29*592efe25SPierre Pronchery  *    :param const char *sbom_type: Sbom types can be found SPDX documention
30*592efe25SPierre Pronchery  *    :return: NULL if some problem occurs and Sbom struct if not
31*592efe25SPierre Pronchery  */
32*592efe25SPierre Pronchery spdxtool_software_sbom_t *
spdxtool_software_sbom_new(pkgconf_client_t * client,const char * spdx_id,const char * creation_id,const char * sbom_type)33*592efe25SPierre Pronchery spdxtool_software_sbom_new(pkgconf_client_t *client, const char *spdx_id, const char *creation_id, const char *sbom_type)
34*592efe25SPierre Pronchery {
35*592efe25SPierre Pronchery 	if (!client || !spdx_id || !creation_id || !sbom_type)
36*592efe25SPierre Pronchery 		return NULL;
37*592efe25SPierre Pronchery 
38*592efe25SPierre Pronchery 	spdxtool_software_sbom_t *sbom = calloc(1, sizeof(spdxtool_software_sbom_t));
39*592efe25SPierre Pronchery 	if (!sbom)
40*592efe25SPierre Pronchery 		goto err;
41*592efe25SPierre Pronchery 
42*592efe25SPierre Pronchery 	sbom->type = "software_Sbom";
43*592efe25SPierre Pronchery 	sbom->spdx_id = strdup(spdx_id);
44*592efe25SPierre Pronchery 	sbom->creation_info = strdup(creation_id);
45*592efe25SPierre Pronchery 	sbom->sbom_type = strdup(sbom_type);
46*592efe25SPierre Pronchery 
47*592efe25SPierre Pronchery 	if (!sbom->spdx_id || !sbom->creation_info || !sbom->sbom_type)
48*592efe25SPierre Pronchery 		goto err;
49*592efe25SPierre Pronchery 
50*592efe25SPierre Pronchery 	return sbom;
51*592efe25SPierre Pronchery 
52*592efe25SPierre Pronchery err:
53*592efe25SPierre Pronchery 	pkgconf_error(client, "spdxtool_software_sbom_new: out of memory");
54*592efe25SPierre Pronchery 	spdxtool_software_sbom_free(sbom);
55*592efe25SPierre Pronchery 	return NULL;
56*592efe25SPierre Pronchery }
57*592efe25SPierre Pronchery 
58*592efe25SPierre Pronchery /*
59*592efe25SPierre Pronchery  * !doc
60*592efe25SPierre Pronchery  *
61*592efe25SPierre Pronchery  * .. c:function:: void spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom)
62*592efe25SPierre Pronchery  *
63*592efe25SPierre Pronchery  *    Free /Software/Sbom struct
64*592efe25SPierre Pronchery  *
65*592efe25SPierre Pronchery  *    :param spdxtool_software_sbom_t *sbom: Sbom struct to be freed.
66*592efe25SPierre Pronchery  *    :return: nothing
67*592efe25SPierre Pronchery  */
68*592efe25SPierre Pronchery void
spdxtool_software_sbom_free(spdxtool_software_sbom_t * sbom)69*592efe25SPierre Pronchery spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom)
70*592efe25SPierre Pronchery {
71*592efe25SPierre Pronchery 	if(!sbom)
72*592efe25SPierre Pronchery 		return;
73*592efe25SPierre Pronchery 
74*592efe25SPierre Pronchery 	free(sbom->spdx_id);
75*592efe25SPierre Pronchery 	free(sbom->creation_info);
76*592efe25SPierre Pronchery 	free(sbom->sbom_type);
77*592efe25SPierre Pronchery 
78*592efe25SPierre Pronchery 	free(sbom);
79*592efe25SPierre Pronchery }
80*592efe25SPierre Pronchery 
81*592efe25SPierre Pronchery /*
82*592efe25SPierre Pronchery  * !doc
83*592efe25SPierre Pronchery  *
84*592efe25SPierre Pronchery  * .. c:function:: spdxtool_serialize_value_t *spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbom_t *sbom)
85*592efe25SPierre Pronchery  *
86*592efe25SPierre Pronchery  *    Serialize /Software/Sbom struct to a JSON value tree. As a side effect,
87*592efe25SPierre Pronchery  *    the package associated with the SBOM's rootElement is registered on the
88*592efe25SPierre Pronchery  *    document via spdxtool_core_spdx_document_add_package, and relationship
89*592efe25SPierre Pronchery  *    element IDs are registered via spdxtool_core_spdx_document_add_element.
90*592efe25SPierre Pronchery  *
91*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
92*592efe25SPierre Pronchery  *    :param spdxtool_software_sbom_t *sbom: Sbom struct to be serialized.
93*592efe25SPierre Pronchery  *    :return: spdxtool_serialize_value_t * representing the Sbom object.
94*592efe25SPierre Pronchery  */
95*592efe25SPierre Pronchery spdxtool_serialize_value_t *
spdxtool_software_sbom_to_object(pkgconf_client_t * client,spdxtool_software_sbom_t * sbom)96*592efe25SPierre Pronchery spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbom_t *sbom)
97*592efe25SPierre Pronchery {
98*592efe25SPierre Pronchery 	spdxtool_serialize_value_t *ret = NULL;
99*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_t *object_list = NULL;
100*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *sbom_type_array = NULL;
101*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *root_element_array = NULL;
102*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *element_array = NULL;
103*592efe25SPierre Pronchery 	char *spdx_id = NULL;
104*592efe25SPierre Pronchery 
105*592efe25SPierre Pronchery 	char sep = spdxtool_util_get_uri_separator(client);
106*592efe25SPierre Pronchery 
107*592efe25SPierre Pronchery 	spdx_id = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "spdxId");
108*592efe25SPierre Pronchery 	if (!spdx_id)
109*592efe25SPierre Pronchery 		goto err;
110*592efe25SPierre Pronchery 
111*592efe25SPierre Pronchery 	object_list = spdxtool_serialize_object_list_new();
112*592efe25SPierre Pronchery 	if (!object_list)
113*592efe25SPierre Pronchery 		goto err;
114*592efe25SPierre Pronchery 
115*592efe25SPierre Pronchery 	sbom_type_array = spdxtool_serialize_array_new();
116*592efe25SPierre Pronchery 	if (!sbom_type_array)
117*592efe25SPierre Pronchery 		goto err;
118*592efe25SPierre Pronchery 
119*592efe25SPierre Pronchery 	if (!spdxtool_serialize_array_add_string(sbom_type_array, sbom->sbom_type))
120*592efe25SPierre Pronchery 		goto err;
121*592efe25SPierre Pronchery 
122*592efe25SPierre Pronchery 	root_element_array = spdxtool_serialize_array_new();
123*592efe25SPierre Pronchery 	if (!root_element_array)
124*592efe25SPierre Pronchery 		goto err;
125*592efe25SPierre Pronchery 
126*592efe25SPierre Pronchery 	if (!spdxtool_serialize_array_add_string(root_element_array, spdx_id))
127*592efe25SPierre Pronchery 		goto err;
128*592efe25SPierre Pronchery 
129*592efe25SPierre Pronchery 	element_array = spdxtool_serialize_array_new();
130*592efe25SPierre Pronchery 	if (!element_array)
131*592efe25SPierre Pronchery 		goto err;
132*592efe25SPierre Pronchery 
133*592efe25SPierre Pronchery 	pkgconf_node_t *node = NULL;
134*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(sbom->rootElement->required.head, node)
135*592efe25SPierre Pronchery 	{
136*592efe25SPierre Pronchery 		pkgconf_dependency_t *dep = node->data;
137*592efe25SPierre Pronchery 		pkgconf_pkg_t *match = dep->match;
138*592efe25SPierre Pronchery 		pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
139*592efe25SPierre Pronchery 
140*592efe25SPierre Pronchery 		/* an unresolved (but tolerated) dependency has no match */
141*592efe25SPierre Pronchery 		if (match == NULL)
142*592efe25SPierre Pronchery 			continue;
143*592efe25SPierre Pronchery 
144*592efe25SPierre Pronchery 		pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id);
145*592efe25SPierre Pronchery 		char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
146*592efe25SPierre Pronchery 		if (!relationship_str)
147*592efe25SPierre Pronchery 			goto err;
148*592efe25SPierre Pronchery 
149*592efe25SPierre Pronchery 		char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
150*592efe25SPierre Pronchery 		free(relationship_str);
151*592efe25SPierre Pronchery 		if (!spdx_id_relation)
152*592efe25SPierre Pronchery 			goto err;
153*592efe25SPierre Pronchery 
154*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(element_array, spdx_id_relation))
155*592efe25SPierre Pronchery 		{
156*592efe25SPierre Pronchery 			free(spdx_id_relation);
157*592efe25SPierre Pronchery 			goto err;
158*592efe25SPierre Pronchery 		}
159*592efe25SPierre Pronchery 
160*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, spdx_id_relation))
161*592efe25SPierre Pronchery 		{
162*592efe25SPierre Pronchery 			free(spdx_id_relation);
163*592efe25SPierre Pronchery 			goto err;
164*592efe25SPierre Pronchery 		}
165*592efe25SPierre Pronchery 
166*592efe25SPierre Pronchery 		free(spdx_id_relation);
167*592efe25SPierre Pronchery 	}
168*592efe25SPierre Pronchery 
169*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(sbom->rootElement->requires_private.head, node)
170*592efe25SPierre Pronchery 	{
171*592efe25SPierre Pronchery 		pkgconf_dependency_t *dep = node->data;
172*592efe25SPierre Pronchery 		pkgconf_pkg_t *match = dep->match;
173*592efe25SPierre Pronchery 		pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
174*592efe25SPierre Pronchery 
175*592efe25SPierre Pronchery 		/* an unresolved (but tolerated) dependency has no match */
176*592efe25SPierre Pronchery 		if (match == NULL)
177*592efe25SPierre Pronchery 			continue;
178*592efe25SPierre Pronchery 
179*592efe25SPierre Pronchery 		pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id);
180*592efe25SPierre Pronchery 		char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
181*592efe25SPierre Pronchery 		if (!relationship_str)
182*592efe25SPierre Pronchery 			goto err;
183*592efe25SPierre Pronchery 
184*592efe25SPierre Pronchery 		char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
185*592efe25SPierre Pronchery 		free(relationship_str);
186*592efe25SPierre Pronchery 		if (!spdx_id_relation)
187*592efe25SPierre Pronchery 			goto err;
188*592efe25SPierre Pronchery 
189*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(element_array, spdx_id_relation))
190*592efe25SPierre Pronchery 		{
191*592efe25SPierre Pronchery 			free(spdx_id_relation);
192*592efe25SPierre Pronchery 			goto err;
193*592efe25SPierre Pronchery 		}
194*592efe25SPierre Pronchery 
195*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, spdx_id_relation))
196*592efe25SPierre Pronchery 		{
197*592efe25SPierre Pronchery 			free(spdx_id_relation);
198*592efe25SPierre Pronchery 			goto err;
199*592efe25SPierre Pronchery 		}
200*592efe25SPierre Pronchery 
201*592efe25SPierre Pronchery 		free(spdx_id_relation);
202*592efe25SPierre Pronchery 	}
203*592efe25SPierre Pronchery 
204*592efe25SPierre Pronchery 	char *value = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "hasDeclaredLicense");
205*592efe25SPierre Pronchery 	if (value)
206*592efe25SPierre Pronchery 	{
207*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(element_array, value))
208*592efe25SPierre Pronchery 		{
209*592efe25SPierre Pronchery 			free(value);
210*592efe25SPierre Pronchery 			goto err;
211*592efe25SPierre Pronchery 		}
212*592efe25SPierre Pronchery 
213*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, value))
214*592efe25SPierre Pronchery 		{
215*592efe25SPierre Pronchery 			free(value);
216*592efe25SPierre Pronchery 			goto err;
217*592efe25SPierre Pronchery 		}
218*592efe25SPierre Pronchery 
219*592efe25SPierre Pronchery 		free(value);
220*592efe25SPierre Pronchery 	}
221*592efe25SPierre Pronchery 
222*592efe25SPierre Pronchery 	value = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "hasConcludedLicense");
223*592efe25SPierre Pronchery 	if (value)
224*592efe25SPierre Pronchery 	{
225*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(element_array, value))
226*592efe25SPierre Pronchery 		{
227*592efe25SPierre Pronchery 			free(value);
228*592efe25SPierre Pronchery 			goto err;
229*592efe25SPierre Pronchery 		}
230*592efe25SPierre Pronchery 
231*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, value))
232*592efe25SPierre Pronchery 		{
233*592efe25SPierre Pronchery 			free(value);
234*592efe25SPierre Pronchery 			goto err;
235*592efe25SPierre Pronchery 		}
236*592efe25SPierre Pronchery 
237*592efe25SPierre Pronchery 		free(value);
238*592efe25SPierre Pronchery 	}
239*592efe25SPierre Pronchery 
240*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_string(object_list, "type", sbom->type) &&
241*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "creationInfo", sbom->creation_info) &&
242*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "spdxId", sbom->spdx_id)))
243*592efe25SPierre Pronchery 	{
244*592efe25SPierre Pronchery 		goto err;
245*592efe25SPierre Pronchery 	}
246*592efe25SPierre Pronchery 
247*592efe25SPierre Pronchery 	/* object_add_array always takes ownership of the array (it is freed even on
248*592efe25SPierre Pronchery 	 * failure), so clear our reference before checking the result to avoid a
249*592efe25SPierre Pronchery 	 * double free at the error label.
250*592efe25SPierre Pronchery 	 */
251*592efe25SPierre Pronchery 	bool ok = spdxtool_serialize_object_add_array(object_list, "software_sbomType", sbom_type_array);
252*592efe25SPierre Pronchery 	sbom_type_array = NULL;
253*592efe25SPierre Pronchery 	if (!ok)
254*592efe25SPierre Pronchery 		goto err;
255*592efe25SPierre Pronchery 
256*592efe25SPierre Pronchery 	ok = spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array);
257*592efe25SPierre Pronchery 	root_element_array = NULL;
258*592efe25SPierre Pronchery 	if (!ok)
259*592efe25SPierre Pronchery 		goto err;
260*592efe25SPierre Pronchery 
261*592efe25SPierre Pronchery 	ok = spdxtool_serialize_object_add_array(object_list, "element", element_array);
262*592efe25SPierre Pronchery 	element_array = NULL;
263*592efe25SPierre Pronchery 	if (!ok)
264*592efe25SPierre Pronchery 		goto err;
265*592efe25SPierre Pronchery 
266*592efe25SPierre Pronchery 	if (!spdxtool_core_spdx_document_add_package(client, sbom->spdx_document, sbom->rootElement))
267*592efe25SPierre Pronchery 		goto err;
268*592efe25SPierre Pronchery 
269*592efe25SPierre Pronchery 	ret = spdxtool_serialize_value_object(object_list);
270*592efe25SPierre Pronchery 	object_list = NULL;
271*592efe25SPierre Pronchery 
272*592efe25SPierre Pronchery err:
273*592efe25SPierre Pronchery 	if (!ret)
274*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_software_sbom_to_object: out of memory");
275*592efe25SPierre Pronchery 
276*592efe25SPierre Pronchery 	free(spdx_id);
277*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_free(object_list);
278*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(sbom_type_array);
279*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(root_element_array);
280*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(element_array);
281*592efe25SPierre Pronchery 	return ret;
282*592efe25SPierre Pronchery }
283*592efe25SPierre Pronchery 
284*592efe25SPierre Pronchery static bool
serialize_copyright_lines_to_object(spdxtool_serialize_object_list_t * object_list,const pkgconf_list_t * copyright_lines)285*592efe25SPierre Pronchery serialize_copyright_lines_to_object(spdxtool_serialize_object_list_t *object_list, const pkgconf_list_t *copyright_lines)
286*592efe25SPierre Pronchery {
287*592efe25SPierre Pronchery 	pkgconf_buffer_t copyright_buf = PKGCONF_BUFFER_INITIALIZER;
288*592efe25SPierre Pronchery 	const pkgconf_node_t *node;
289*592efe25SPierre Pronchery 
290*592efe25SPierre Pronchery 	if (copyright_lines->head == NULL)
291*592efe25SPierre Pronchery 		return spdxtool_serialize_object_add_string(object_list, "software_copyrightText", "NOASSERTION") != NULL;
292*592efe25SPierre Pronchery 
293*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(copyright_lines->head, node)
294*592efe25SPierre Pronchery 	{
295*592efe25SPierre Pronchery 		const pkgconf_bufferset_t *set = node->data;
296*592efe25SPierre Pronchery 		pkgconf_buffer_join(&copyright_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL);
297*592efe25SPierre Pronchery 	}
298*592efe25SPierre Pronchery 
299*592efe25SPierre Pronchery 	bool ok = spdxtool_serialize_object_add_string(object_list, "software_copyrightText", pkgconf_buffer_str_or_empty(&copyright_buf)) != NULL;
300*592efe25SPierre Pronchery 	pkgconf_buffer_finalize(&copyright_buf);
301*592efe25SPierre Pronchery 	return ok;
302*592efe25SPierre Pronchery }
303*592efe25SPierre Pronchery 
304*592efe25SPierre Pronchery /*
305*592efe25SPierre Pronchery  * !doc
306*592efe25SPierre Pronchery  *
307*592efe25SPierre Pronchery  * .. c:function:: spdxtool_serialize_value_t *spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg, spdxtool_core_spdx_document_t *spdx)
308*592efe25SPierre Pronchery  *
309*592efe25SPierre Pronchery  *    Serialize /Software/Package struct to a JSON value tree. As a side effect,
310*592efe25SPierre Pronchery  *    any license and dependency relationships generated during serialization are
311*592efe25SPierre Pronchery  *    added to the document via spdxtool_core_spdx_document_add_relationship.
312*592efe25SPierre Pronchery  *
313*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
314*592efe25SPierre Pronchery  *    :param pkgconf_pkg_t *pkg: Package struct to be serialized.
315*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument to which generated relationships are added.
316*592efe25SPierre Pronchery  *    :return: spdxtool_serialize_value_t * representing the Package object.
317*592efe25SPierre Pronchery  */
318*592efe25SPierre Pronchery spdxtool_serialize_value_t *
spdxtool_software_package_to_object(pkgconf_client_t * client,pkgconf_pkg_t * pkg,spdxtool_core_spdx_document_t * spdx)319*592efe25SPierre Pronchery spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg, spdxtool_core_spdx_document_t *spdx)
320*592efe25SPierre Pronchery {
321*592efe25SPierre Pronchery 	spdxtool_serialize_value_t *ret = NULL;
322*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_t *object_list = NULL;
323*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *originated_by = NULL;
324*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *supplied_by = NULL;
325*592efe25SPierre Pronchery 	char *creation_info = NULL;
326*592efe25SPierre Pronchery 	char *spdx_id = NULL;
327*592efe25SPierre Pronchery 	char *agent = NULL;
328*592efe25SPierre Pronchery 	char *supplier = NULL;
329*592efe25SPierre Pronchery 	char *spdx_id_license = NULL;
330*592efe25SPierre Pronchery 	pkgconf_list_t relations = PKGCONF_LIST_INITIALIZER;
331*592efe25SPierre Pronchery 	pkgconf_list_t *cpy_relations = NULL;
332*592efe25SPierre Pronchery 	pkgconf_node_t *node = NULL;
333*592efe25SPierre Pronchery 	char sep = spdxtool_util_get_uri_separator(client);
334*592efe25SPierre Pronchery 
335*592efe25SPierre Pronchery 	creation_info = spdxtool_util_tuple_lookup(client, &pkg->vars, "creationInfo");
336*592efe25SPierre Pronchery 	spdx_id = spdxtool_util_tuple_lookup(client, &pkg->vars, "spdxId");
337*592efe25SPierre Pronchery 	agent = spdxtool_util_tuple_lookup(client, &pkg->vars, "agent");
338*592efe25SPierre Pronchery 
339*592efe25SPierre Pronchery 	if (!creation_info || !spdx_id || !agent)
340*592efe25SPierre Pronchery 		goto err;
341*592efe25SPierre Pronchery 
342*592efe25SPierre Pronchery 	object_list = spdxtool_serialize_object_list_new();
343*592efe25SPierre Pronchery 	if (!object_list)
344*592efe25SPierre Pronchery 		goto err;
345*592efe25SPierre Pronchery 
346*592efe25SPierre Pronchery 	originated_by = spdxtool_serialize_array_new();
347*592efe25SPierre Pronchery 	if (!originated_by)
348*592efe25SPierre Pronchery 		goto err;
349*592efe25SPierre Pronchery 
350*592efe25SPierre Pronchery 	if (!spdxtool_serialize_array_add_string(originated_by, agent))
351*592efe25SPierre Pronchery 		goto err;
352*592efe25SPierre Pronchery 
353*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_string(object_list, "type", "software_Package") &&
354*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "creationInfo", creation_info) &&
355*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "spdxId", spdx_id) &&
356*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "name", pkg->realname)))
357*592efe25SPierre Pronchery 	{
358*592efe25SPierre Pronchery 		goto err;
359*592efe25SPierre Pronchery 	}
360*592efe25SPierre Pronchery 
361*592efe25SPierre Pronchery 	/* object_add_array always takes ownership of the array (it is freed even on
362*592efe25SPierre Pronchery 	 * failure), so clear our reference before checking the result to avoid a
363*592efe25SPierre Pronchery 	 * double free at the error label.
364*592efe25SPierre Pronchery 	 */
365*592efe25SPierre Pronchery 	bool ok = spdxtool_serialize_object_add_array(object_list, "originatedBy", originated_by);
366*592efe25SPierre Pronchery 	originated_by = NULL;
367*592efe25SPierre Pronchery 	if (!ok)
368*592efe25SPierre Pronchery 		goto err;
369*592efe25SPierre Pronchery 
370*592efe25SPierre Pronchery 	supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy");
371*592efe25SPierre Pronchery 	if (supplier)
372*592efe25SPierre Pronchery 	{
373*592efe25SPierre Pronchery 		supplied_by = spdxtool_serialize_array_new();
374*592efe25SPierre Pronchery 		if (!supplied_by)
375*592efe25SPierre Pronchery 			goto err;
376*592efe25SPierre Pronchery 
377*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(supplied_by, supplier))
378*592efe25SPierre Pronchery 			goto err;
379*592efe25SPierre Pronchery 
380*592efe25SPierre Pronchery 		ok = spdxtool_serialize_object_add_array(object_list, "suppliedBy", supplied_by);
381*592efe25SPierre Pronchery 		supplied_by = NULL;
382*592efe25SPierre Pronchery 		if (!ok)
383*592efe25SPierre Pronchery 			goto err;
384*592efe25SPierre Pronchery 	}
385*592efe25SPierre Pronchery 
386*592efe25SPierre Pronchery 	if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright))
387*592efe25SPierre Pronchery 		goto err;
388*592efe25SPierre Pronchery 
389*592efe25SPierre Pronchery 	if (!spdxtool_serialize_object_add_string(object_list, "software_homePage",
390*592efe25SPierre Pronchery 		pkg->url ? pkg->url : ""))
391*592efe25SPierre Pronchery 	{
392*592efe25SPierre Pronchery 		goto err;
393*592efe25SPierre Pronchery 	}
394*592efe25SPierre Pronchery 
395*592efe25SPierre Pronchery 	if (!spdxtool_serialize_object_add_string(object_list, "software_downloadLocation",
396*592efe25SPierre Pronchery 		pkg->source ? pkg->source : ""))
397*592efe25SPierre Pronchery 	{
398*592efe25SPierre Pronchery 		goto err;
399*592efe25SPierre Pronchery 	}
400*592efe25SPierre Pronchery 
401*592efe25SPierre Pronchery 	if (!spdxtool_serialize_object_add_string(object_list, "software_packageVersion", pkg->version))
402*592efe25SPierre Pronchery 		goto err;
403*592efe25SPierre Pronchery 
404*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, node)
405*592efe25SPierre Pronchery 	{
406*592efe25SPierre Pronchery 		const pkgconf_license_t *license = node->data;
407*592efe25SPierre Pronchery 		if (license->type == PKGCONF_LICENSE_EXPRESSION)
408*592efe25SPierre Pronchery 		{
409*592efe25SPierre Pronchery 			spdx_id_license = spdxtool_util_get_spdx_id_string(client, "simplelicensing_LicenseExpression", license->data);
410*592efe25SPierre Pronchery 			if (!spdx_id_license)
411*592efe25SPierre Pronchery 				goto err;
412*592efe25SPierre Pronchery 
413*592efe25SPierre Pronchery 			pkgconf_license_insert(client, &relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_license);
414*592efe25SPierre Pronchery 			free(spdx_id_license);
415*592efe25SPierre Pronchery 			spdx_id_license = NULL;
416*592efe25SPierre Pronchery 		}
417*592efe25SPierre Pronchery 	}
418*592efe25SPierre Pronchery 
419*592efe25SPierre Pronchery 	char *tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasDeclaredLicense");
420*592efe25SPierre Pronchery 	if (tuple_license)
421*592efe25SPierre Pronchery 	{
422*592efe25SPierre Pronchery 		cpy_relations = calloc(1, sizeof(pkgconf_list_t));
423*592efe25SPierre Pronchery 		if (!cpy_relations)
424*592efe25SPierre Pronchery 		{
425*592efe25SPierre Pronchery 			free(tuple_license);
426*592efe25SPierre Pronchery 			goto err;
427*592efe25SPierre Pronchery 		}
428*592efe25SPierre Pronchery 
429*592efe25SPierre Pronchery 		pkgconf_license_copy_list(client, cpy_relations, &relations);
430*592efe25SPierre Pronchery 		spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasDeclaredLicense");
431*592efe25SPierre Pronchery 		free(tuple_license);
432*592efe25SPierre Pronchery 		if (!relationship)
433*592efe25SPierre Pronchery 			goto err;
434*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
435*592efe25SPierre Pronchery 			goto err;
436*592efe25SPierre Pronchery 		cpy_relations = NULL;
437*592efe25SPierre Pronchery 	}
438*592efe25SPierre Pronchery 
439*592efe25SPierre Pronchery 	tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasConcludedLicense");
440*592efe25SPierre Pronchery 	if (tuple_license)
441*592efe25SPierre Pronchery 	{
442*592efe25SPierre Pronchery 		cpy_relations = calloc(1, sizeof(pkgconf_list_t));
443*592efe25SPierre Pronchery 		if (!cpy_relations)
444*592efe25SPierre Pronchery 		{
445*592efe25SPierre Pronchery 			free(tuple_license);
446*592efe25SPierre Pronchery 			goto err;
447*592efe25SPierre Pronchery 		}
448*592efe25SPierre Pronchery 
449*592efe25SPierre Pronchery 		pkgconf_license_copy_list(client, cpy_relations, &relations);
450*592efe25SPierre Pronchery 		spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasConcludedLicense");
451*592efe25SPierre Pronchery 		free(tuple_license);
452*592efe25SPierre Pronchery 		if (!relationship)
453*592efe25SPierre Pronchery 			goto err;
454*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
455*592efe25SPierre Pronchery 			goto err;
456*592efe25SPierre Pronchery 		cpy_relations = NULL;
457*592efe25SPierre Pronchery 	}
458*592efe25SPierre Pronchery 	pkgconf_license_free(&relations);
459*592efe25SPierre Pronchery 
460*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
461*592efe25SPierre Pronchery 	{
462*592efe25SPierre Pronchery 		pkgconf_dependency_t *dep = node->data;
463*592efe25SPierre Pronchery 		pkgconf_pkg_t *match = dep->match;
464*592efe25SPierre Pronchery 		pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
465*592efe25SPierre Pronchery 
466*592efe25SPierre Pronchery 		/* an unresolved (but tolerated) dependency has no match */
467*592efe25SPierre Pronchery 		if (match == NULL)
468*592efe25SPierre Pronchery 			continue;
469*592efe25SPierre Pronchery 
470*592efe25SPierre Pronchery 		pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id);
471*592efe25SPierre Pronchery 		char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
472*592efe25SPierre Pronchery 		if (!relationship_str)
473*592efe25SPierre Pronchery 			goto err;
474*592efe25SPierre Pronchery 
475*592efe25SPierre Pronchery 		char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
476*592efe25SPierre Pronchery 		free(relationship_str);
477*592efe25SPierre Pronchery 		if (!spdx_id_relation)
478*592efe25SPierre Pronchery 			goto err;
479*592efe25SPierre Pronchery 
480*592efe25SPierre Pronchery 		char *spdx_id_package = spdxtool_util_get_spdx_id_string(client, "Package", match->id);
481*592efe25SPierre Pronchery 		if (!spdx_id_package)
482*592efe25SPierre Pronchery 		{
483*592efe25SPierre Pronchery 			free(spdx_id_relation);
484*592efe25SPierre Pronchery 			goto err;
485*592efe25SPierre Pronchery 		}
486*592efe25SPierre Pronchery 
487*592efe25SPierre Pronchery 		cpy_relations = calloc(1, sizeof(pkgconf_list_t));
488*592efe25SPierre Pronchery 		if (!cpy_relations)
489*592efe25SPierre Pronchery 		{
490*592efe25SPierre Pronchery 			free(spdx_id_relation);
491*592efe25SPierre Pronchery 			free(spdx_id_package);
492*592efe25SPierre Pronchery 			goto err;
493*592efe25SPierre Pronchery 		}
494*592efe25SPierre Pronchery 
495*592efe25SPierre Pronchery 		pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package);
496*592efe25SPierre Pronchery 		spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn");
497*592efe25SPierre Pronchery 		free(spdx_id_relation);
498*592efe25SPierre Pronchery 		free(spdx_id_package);
499*592efe25SPierre Pronchery 		if (!relationship)
500*592efe25SPierre Pronchery 			goto err;
501*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
502*592efe25SPierre Pronchery 			goto err;
503*592efe25SPierre Pronchery 		cpy_relations = NULL;
504*592efe25SPierre Pronchery 	}
505*592efe25SPierre Pronchery 
506*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
507*592efe25SPierre Pronchery 	{
508*592efe25SPierre Pronchery 		pkgconf_dependency_t *dep = node->data;
509*592efe25SPierre Pronchery 		pkgconf_pkg_t *match = dep->match;
510*592efe25SPierre Pronchery 		pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
511*592efe25SPierre Pronchery 
512*592efe25SPierre Pronchery 		/* an unresolved (but tolerated) dependency has no match */
513*592efe25SPierre Pronchery 		if (match == NULL)
514*592efe25SPierre Pronchery 			continue;
515*592efe25SPierre Pronchery 
516*592efe25SPierre Pronchery 		pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id);
517*592efe25SPierre Pronchery 		char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
518*592efe25SPierre Pronchery 		if (!relationship_str)
519*592efe25SPierre Pronchery 			goto err;
520*592efe25SPierre Pronchery 
521*592efe25SPierre Pronchery 		char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
522*592efe25SPierre Pronchery 		free(relationship_str);
523*592efe25SPierre Pronchery 		if (!spdx_id_relation)
524*592efe25SPierre Pronchery 			goto err;
525*592efe25SPierre Pronchery 
526*592efe25SPierre Pronchery 		char *spdx_id_package = spdxtool_util_get_spdx_id_string(client, "Package", match->id);
527*592efe25SPierre Pronchery 		if (!spdx_id_package)
528*592efe25SPierre Pronchery 		{
529*592efe25SPierre Pronchery 			free(spdx_id_relation);
530*592efe25SPierre Pronchery 			goto err;
531*592efe25SPierre Pronchery 		}
532*592efe25SPierre Pronchery 
533*592efe25SPierre Pronchery 		cpy_relations = calloc(1, sizeof(pkgconf_list_t));
534*592efe25SPierre Pronchery 		if (!cpy_relations)
535*592efe25SPierre Pronchery 		{
536*592efe25SPierre Pronchery 			free(spdx_id_relation);
537*592efe25SPierre Pronchery 			free(spdx_id_package);
538*592efe25SPierre Pronchery 			goto err;
539*592efe25SPierre Pronchery 		}
540*592efe25SPierre Pronchery 
541*592efe25SPierre Pronchery 		pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package);
542*592efe25SPierre Pronchery 		spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn");
543*592efe25SPierre Pronchery 		free(spdx_id_relation);
544*592efe25SPierre Pronchery 		free(spdx_id_package);
545*592efe25SPierre Pronchery 		if (!relationship)
546*592efe25SPierre Pronchery 			goto err;
547*592efe25SPierre Pronchery 		cpy_relations = NULL;
548*592efe25SPierre Pronchery 		if (!spdxtool_core_relationship_set_scope(client, relationship, "development"))
549*592efe25SPierre Pronchery 		{
550*592efe25SPierre Pronchery 			spdxtool_core_relationship_free(relationship);
551*592efe25SPierre Pronchery 			goto err;
552*592efe25SPierre Pronchery 		}
553*592efe25SPierre Pronchery 		if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
554*592efe25SPierre Pronchery 		{
555*592efe25SPierre Pronchery 			spdxtool_core_relationship_free(relationship);
556*592efe25SPierre Pronchery 			goto err;
557*592efe25SPierre Pronchery 		}
558*592efe25SPierre Pronchery 	}
559*592efe25SPierre Pronchery 
560*592efe25SPierre Pronchery 	ret = spdxtool_serialize_value_object(object_list);
561*592efe25SPierre Pronchery 	object_list = NULL;
562*592efe25SPierre Pronchery 
563*592efe25SPierre Pronchery err:
564*592efe25SPierre Pronchery 	if (!ret)
565*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_software_package_to_object: out of memory");
566*592efe25SPierre Pronchery 
567*592efe25SPierre Pronchery 	free(creation_info);
568*592efe25SPierre Pronchery 	free(spdx_id);
569*592efe25SPierre Pronchery 	free(agent);
570*592efe25SPierre Pronchery 	free(supplier);
571*592efe25SPierre Pronchery 	free(spdx_id_license);
572*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_free(object_list);
573*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(originated_by);
574*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(supplied_by);
575*592efe25SPierre Pronchery 	return ret;
576*592efe25SPierre Pronchery }
577