xref: /freebsd/contrib/pkgconf/cli/spdxtool/core.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 "util.h"
14*592efe25SPierre Pronchery #include "serialize.h"
15*592efe25SPierre Pronchery #include "core.h"
16*592efe25SPierre Pronchery #include "software.h"
17*592efe25SPierre Pronchery #include "simplelicensing.h"
18*592efe25SPierre Pronchery 
19*592efe25SPierre Pronchery /*
20*592efe25SPierre Pronchery  * !doc
21*592efe25SPierre Pronchery  *
22*592efe25SPierre Pronchery  * .. c:function:: spdxtool_core_agent_t *spdxtool_core_agent_new(pkgconf_client_t *client, const char *creation_info_id, const char *name)
23*592efe25SPierre Pronchery  *
24*592efe25SPierre Pronchery  *    Create new /Core/Agent struct
25*592efe25SPierre Pronchery  *
26*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
27*592efe25SPierre Pronchery  *    :param char *creation_info_id: CreationInfo spdxId
28*592efe25SPierre Pronchery  *    :param char *name: Name of agent
29*592efe25SPierre Pronchery  *    :return: NULL if some problem occurs and Agent struct if not
30*592efe25SPierre Pronchery  */
31*592efe25SPierre Pronchery spdxtool_core_agent_t *
spdxtool_core_agent_new(pkgconf_client_t * client,const char * creation_info_id,const char * name)32*592efe25SPierre Pronchery spdxtool_core_agent_new(pkgconf_client_t *client, const char *creation_info_id, const char *name)
33*592efe25SPierre Pronchery {
34*592efe25SPierre Pronchery 	if (!client || !creation_info_id || !name)
35*592efe25SPierre Pronchery 		return NULL;
36*592efe25SPierre Pronchery 
37*592efe25SPierre Pronchery 	spdxtool_core_agent_t *agent = calloc(1, sizeof(spdxtool_core_agent_t));
38*592efe25SPierre Pronchery 	if (!agent)
39*592efe25SPierre Pronchery 		goto err;
40*592efe25SPierre Pronchery 
41*592efe25SPierre Pronchery 	agent->type = "Agent";
42*592efe25SPierre Pronchery 
43*592efe25SPierre Pronchery 	char *spdx_id_name = strdup(name);
44*592efe25SPierre Pronchery 	if (!spdx_id_name)
45*592efe25SPierre Pronchery 		goto err;
46*592efe25SPierre Pronchery 
47*592efe25SPierre Pronchery 	spdxtool_util_string_correction(spdx_id_name);
48*592efe25SPierre Pronchery 
49*592efe25SPierre Pronchery 	agent->spdx_id = spdxtool_util_get_spdx_id_string(client, agent->type, spdx_id_name);
50*592efe25SPierre Pronchery 	free(spdx_id_name);
51*592efe25SPierre Pronchery 
52*592efe25SPierre Pronchery 	agent->creation_info = strdup(creation_info_id);
53*592efe25SPierre Pronchery 	agent->name = strdup(name);
54*592efe25SPierre Pronchery 
55*592efe25SPierre Pronchery 	if (!agent->spdx_id || !agent->creation_info || !agent->name)
56*592efe25SPierre Pronchery 		goto err;
57*592efe25SPierre Pronchery 
58*592efe25SPierre Pronchery 	return agent;
59*592efe25SPierre Pronchery 
60*592efe25SPierre Pronchery err:
61*592efe25SPierre Pronchery 	pkgconf_error(client, "spdxtool_core_agent_new: out of memory");
62*592efe25SPierre Pronchery 	spdxtool_core_agent_free(agent);
63*592efe25SPierre Pronchery 	return NULL;
64*592efe25SPierre Pronchery }
65*592efe25SPierre Pronchery 
66*592efe25SPierre Pronchery /*
67*592efe25SPierre Pronchery  * !doc
68*592efe25SPierre Pronchery  *
69*592efe25SPierre Pronchery  * .. c:function:: void spdxtool_core_agent_free(spdxtool_core_agent_t *agent)
70*592efe25SPierre Pronchery  *
71*592efe25SPierre Pronchery  *    Free /Core/Agent struct
72*592efe25SPierre Pronchery  *
73*592efe25SPierre Pronchery  *    :param spdxtool_core_agent_t *agent: Agent struct to be freed.
74*592efe25SPierre Pronchery  *    :return: nothing
75*592efe25SPierre Pronchery  */
76*592efe25SPierre Pronchery void
spdxtool_core_agent_free(spdxtool_core_agent_t * agent)77*592efe25SPierre Pronchery spdxtool_core_agent_free(spdxtool_core_agent_t *agent)
78*592efe25SPierre Pronchery {
79*592efe25SPierre Pronchery 	if (!agent)
80*592efe25SPierre Pronchery 		return;
81*592efe25SPierre Pronchery 
82*592efe25SPierre Pronchery 	free(agent->creation_info);
83*592efe25SPierre Pronchery 	free(agent->spdx_id);
84*592efe25SPierre Pronchery 	free(agent->name);
85*592efe25SPierre Pronchery 
86*592efe25SPierre Pronchery 	free(agent);
87*592efe25SPierre Pronchery }
88*592efe25SPierre Pronchery 
89*592efe25SPierre Pronchery /*
90*592efe25SPierre Pronchery  * !doc
91*592efe25SPierre Pronchery  *
92*592efe25SPierre Pronchery  * .. c:function:: spdxtool_serialize_value_t *spdxtool_core_agent_to_object(pkgconf_client_t *client, const spdxtool_core_agent_t *agent)
93*592efe25SPierre Pronchery  *
94*592efe25SPierre Pronchery  *    Serialize /Core/Agent struct to a JSON value tree.
95*592efe25SPierre Pronchery  *
96*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
97*592efe25SPierre Pronchery  *    :param const spdxtool_core_agent_t *agent: Agent struct to be serialized.
98*592efe25SPierre Pronchery  *    :return: spdxtool_serialize_value_t * representing the Agent object.
99*592efe25SPierre Pronchery  */
100*592efe25SPierre Pronchery spdxtool_serialize_value_t *
spdxtool_core_agent_to_object(pkgconf_client_t * client,const spdxtool_core_agent_t * agent)101*592efe25SPierre Pronchery spdxtool_core_agent_to_object(pkgconf_client_t *client, const spdxtool_core_agent_t *agent)
102*592efe25SPierre Pronchery {
103*592efe25SPierre Pronchery 	spdxtool_serialize_value_t *ret = NULL;
104*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_t *object_list = spdxtool_serialize_object_list_new();
105*592efe25SPierre Pronchery 	if (!object_list)
106*592efe25SPierre Pronchery 		goto err;
107*592efe25SPierre Pronchery 
108*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_string(object_list, "type", agent->type) &&
109*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "creationInfo", agent->creation_info) &&
110*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "spdxId", agent->spdx_id) &&
111*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "name", agent->name)))
112*592efe25SPierre Pronchery 	{
113*592efe25SPierre Pronchery 		goto err;
114*592efe25SPierre Pronchery 	}
115*592efe25SPierre Pronchery 
116*592efe25SPierre Pronchery 	ret = spdxtool_serialize_value_object(object_list);
117*592efe25SPierre Pronchery 	object_list = NULL;
118*592efe25SPierre Pronchery 
119*592efe25SPierre Pronchery err:
120*592efe25SPierre Pronchery 	if (!ret)
121*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_agent_to_object: out of memory");
122*592efe25SPierre Pronchery 
123*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_free(object_list);
124*592efe25SPierre Pronchery 	return ret;
125*592efe25SPierre Pronchery }
126*592efe25SPierre Pronchery 
127*592efe25SPierre Pronchery /*
128*592efe25SPierre Pronchery  * !doc
129*592efe25SPierre Pronchery  *
130*592efe25SPierre Pronchery  * .. c:function:: spdxtool_core_creation_info_t *spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *id, const char *time)
131*592efe25SPierre Pronchery  *
132*592efe25SPierre Pronchery  *    Create new /Core/CreationInfo struct
133*592efe25SPierre Pronchery  *
134*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
135*592efe25SPierre Pronchery  *    :param const char *agent_id: Agent spdxId
136*592efe25SPierre Pronchery  *    :param const char *id: Id for creation info
137*592efe25SPierre Pronchery  *    :param const char *time: If NULL current time is used if not then
138*592efe25SPierre Pronchery  *                             this time string is used. Time string should be
139*592efe25SPierre Pronchery  *                             in ISO8601 format: YYYY-MM-DDTHH:MM:SSZ
140*592efe25SPierre Pronchery  *    :return: NULL if some problem occurs and CreationInfo struct if not
141*592efe25SPierre Pronchery  */
142*592efe25SPierre Pronchery spdxtool_core_creation_info_t *
spdxtool_core_creation_info_new(pkgconf_client_t * client,const char * agent_id,const char * id,const char * time)143*592efe25SPierre Pronchery spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *id, const char *time)
144*592efe25SPierre Pronchery {
145*592efe25SPierre Pronchery 	if (!client || !agent_id || !id)
146*592efe25SPierre Pronchery 		return NULL;
147*592efe25SPierre Pronchery 
148*592efe25SPierre Pronchery 	spdxtool_core_creation_info_t *creation = calloc(1, sizeof(spdxtool_core_creation_info_t));
149*592efe25SPierre Pronchery 	if (!creation)
150*592efe25SPierre Pronchery 		goto err;
151*592efe25SPierre Pronchery 
152*592efe25SPierre Pronchery 	creation->type = "CreationInfo";
153*592efe25SPierre Pronchery 	creation->created_using = "pkgconf spdxtool";
154*592efe25SPierre Pronchery 	creation->id = strdup(id);
155*592efe25SPierre Pronchery 	creation->created = time ? strdup(time) : spdxtool_util_get_current_iso8601_time();
156*592efe25SPierre Pronchery 	creation->created_by = strdup(agent_id);
157*592efe25SPierre Pronchery 	creation->spec_version = strdup(spdxtool_util_get_spdx_version(client));
158*592efe25SPierre Pronchery 
159*592efe25SPierre Pronchery 	if (!creation->id || !creation->created || !creation->created_by || !creation->spec_version)
160*592efe25SPierre Pronchery 		goto err;
161*592efe25SPierre Pronchery 
162*592efe25SPierre Pronchery 	return creation;
163*592efe25SPierre Pronchery 
164*592efe25SPierre Pronchery err:
165*592efe25SPierre Pronchery 	pkgconf_error(client, "spdxtool_core_creation_info_new: out of memory");
166*592efe25SPierre Pronchery 	spdxtool_core_creation_info_free(creation);
167*592efe25SPierre Pronchery 	return NULL;
168*592efe25SPierre Pronchery }
169*592efe25SPierre Pronchery 
170*592efe25SPierre Pronchery /*
171*592efe25SPierre Pronchery  * !doc
172*592efe25SPierre Pronchery  *
173*592efe25SPierre Pronchery  * .. c:function:: void spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation)
174*592efe25SPierre Pronchery  *
175*592efe25SPierre Pronchery  *    Free /Core/CreationInfo struct
176*592efe25SPierre Pronchery  *
177*592efe25SPierre Pronchery  *    :param spdxtool_core_creation_info_t *creation: CreationInfo struct to be freed.
178*592efe25SPierre Pronchery  *    :return: nothing
179*592efe25SPierre Pronchery  */
180*592efe25SPierre Pronchery void
spdxtool_core_creation_info_free(spdxtool_core_creation_info_t * creation)181*592efe25SPierre Pronchery spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation)
182*592efe25SPierre Pronchery {
183*592efe25SPierre Pronchery 	if (!creation)
184*592efe25SPierre Pronchery 		return;
185*592efe25SPierre Pronchery 
186*592efe25SPierre Pronchery 	free(creation->id);
187*592efe25SPierre Pronchery 	free(creation->created);
188*592efe25SPierre Pronchery 	free(creation->created_by);
189*592efe25SPierre Pronchery 	free(creation->spec_version);
190*592efe25SPierre Pronchery 
191*592efe25SPierre Pronchery 	free(creation);
192*592efe25SPierre Pronchery }
193*592efe25SPierre Pronchery 
194*592efe25SPierre Pronchery /*
195*592efe25SPierre Pronchery  * !doc
196*592efe25SPierre Pronchery  *
197*592efe25SPierre Pronchery  * .. c:function:: spdxtool_serialize_value_t *spdxtool_core_creation_info_to_object(pkgconf_client_t *client, const spdxtool_core_creation_info_t *creation)
198*592efe25SPierre Pronchery  *
199*592efe25SPierre Pronchery  *    Serialize /Core/CreationInfo struct to a JSON value tree.
200*592efe25SPierre Pronchery  *
201*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
202*592efe25SPierre Pronchery  *    :param const spdxtool_core_creation_info_t *creation: CreationInfo struct to be serialized.
203*592efe25SPierre Pronchery  *    :return: spdxtool_serialize_value_t * representing the CreationInfo object.
204*592efe25SPierre Pronchery  */
205*592efe25SPierre Pronchery spdxtool_serialize_value_t *
spdxtool_core_creation_info_to_object(pkgconf_client_t * client,const spdxtool_core_creation_info_t * creation)206*592efe25SPierre Pronchery spdxtool_core_creation_info_to_object(pkgconf_client_t *client, const spdxtool_core_creation_info_t *creation)
207*592efe25SPierre Pronchery {
208*592efe25SPierre Pronchery 	spdxtool_serialize_value_t *ret = NULL;
209*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_t *object_list = spdxtool_serialize_object_list_new();
210*592efe25SPierre Pronchery 	if (!object_list)
211*592efe25SPierre Pronchery 		goto err;
212*592efe25SPierre Pronchery 
213*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *created_by = spdxtool_serialize_array_new();
214*592efe25SPierre Pronchery 	if (!created_by)
215*592efe25SPierre Pronchery 		goto err;
216*592efe25SPierre Pronchery 
217*592efe25SPierre Pronchery 	if (!spdxtool_serialize_array_add_string(created_by, creation->created_by))
218*592efe25SPierre Pronchery 	{
219*592efe25SPierre Pronchery 		spdxtool_serialize_array_free(created_by);
220*592efe25SPierre Pronchery 		goto err;
221*592efe25SPierre Pronchery 	}
222*592efe25SPierre Pronchery 
223*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_string(object_list, "type", creation->type) &&
224*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "@id", creation->id) &&
225*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "created", creation->created)))
226*592efe25SPierre Pronchery 	{
227*592efe25SPierre Pronchery 		/* created_by has not been handed to the object list yet */
228*592efe25SPierre Pronchery 		spdxtool_serialize_array_free(created_by);
229*592efe25SPierre Pronchery 		goto err;
230*592efe25SPierre Pronchery 	}
231*592efe25SPierre Pronchery 
232*592efe25SPierre Pronchery 	/* object_add_array takes ownership of created_by, freeing it on failure */
233*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_array(object_list, "createdBy", created_by) &&
234*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "specVersion", creation->spec_version)))
235*592efe25SPierre Pronchery 	{
236*592efe25SPierre Pronchery 		goto err;
237*592efe25SPierre Pronchery 	}
238*592efe25SPierre Pronchery 
239*592efe25SPierre Pronchery 	ret = spdxtool_serialize_value_object(object_list);
240*592efe25SPierre Pronchery 	object_list = NULL;
241*592efe25SPierre Pronchery 
242*592efe25SPierre Pronchery err:
243*592efe25SPierre Pronchery 	if (!ret)
244*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_creation_info_to_object: out of memory");
245*592efe25SPierre Pronchery 
246*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_free(object_list);
247*592efe25SPierre Pronchery 	return ret;
248*592efe25SPierre Pronchery }
249*592efe25SPierre Pronchery 
250*592efe25SPierre Pronchery /*
251*592efe25SPierre Pronchery  * !doc
252*592efe25SPierre Pronchery  *
253*592efe25SPierre Pronchery  * .. c:function:: spdxtool_core_creation_info_t *spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *spdx_id, const char *creation_id, const char *agent)
254*592efe25SPierre Pronchery  *
255*592efe25SPierre Pronchery  *    Create new /Core/SpdxDocument struct
256*592efe25SPierre Pronchery  *    In SPDX Lite SBOM there can be only one SpdxDocument
257*592efe25SPierre Pronchery  *
258*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
259*592efe25SPierre Pronchery  *    :param const char *spdx_id: Id of this SpdxDocument
260*592efe25SPierre Pronchery  *    :param const char *creation_id: Id for creation info
261*592efe25SPierre Pronchery  *    :param const char *agent_id: Agent for this document
262*592efe25SPierre Pronchery  *    :return: NULL if some problem occurs and SpdxDocument struct if not
263*592efe25SPierre Pronchery  */
264*592efe25SPierre Pronchery spdxtool_core_spdx_document_t *
spdxtool_core_spdx_document_new(pkgconf_client_t * client,const char * spdx_id,const char * creation_id,const char * agent_id)265*592efe25SPierre Pronchery spdxtool_core_spdx_document_new(pkgconf_client_t *client, const char *spdx_id, const char *creation_id, const char *agent_id)
266*592efe25SPierre Pronchery {
267*592efe25SPierre Pronchery 	if (!client || !spdx_id || !creation_id || !agent_id)
268*592efe25SPierre Pronchery 		return NULL;
269*592efe25SPierre Pronchery 
270*592efe25SPierre Pronchery 	spdxtool_core_spdx_document_t *spdx = calloc(1, sizeof(spdxtool_core_spdx_document_t));
271*592efe25SPierre Pronchery 	if (!spdx)
272*592efe25SPierre Pronchery 		goto err;
273*592efe25SPierre Pronchery 
274*592efe25SPierre Pronchery 	spdx->type = "SpdxDocument";
275*592efe25SPierre Pronchery 	spdx->spdx_id = strdup(spdx_id);
276*592efe25SPierre Pronchery 	spdx->agent = strdup(agent_id);
277*592efe25SPierre Pronchery 	spdx->creation_info = strdup(creation_id);
278*592efe25SPierre Pronchery 
279*592efe25SPierre Pronchery 	if (!spdx->spdx_id || !spdx->agent || !spdx->creation_info)
280*592efe25SPierre Pronchery 		goto err;
281*592efe25SPierre Pronchery 
282*592efe25SPierre Pronchery 	return spdx;
283*592efe25SPierre Pronchery 
284*592efe25SPierre Pronchery err:
285*592efe25SPierre Pronchery 	pkgconf_error(client, "spdxtool_core_spdx_document_new: out of memory");
286*592efe25SPierre Pronchery 	spdxtool_core_spdx_document_free(spdx);
287*592efe25SPierre Pronchery 	return NULL;
288*592efe25SPierre Pronchery }
289*592efe25SPierre Pronchery 
290*592efe25SPierre Pronchery /*
291*592efe25SPierre Pronchery  * !doc
292*592efe25SPierre Pronchery  *
293*592efe25SPierre Pronchery  * .. c:function:: void spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx)
294*592efe25SPierre Pronchery  *
295*592efe25SPierre Pronchery  *    Free /Core/SpdxDocument struct
296*592efe25SPierre Pronchery  *
297*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct to be freed.
298*592efe25SPierre Pronchery  *    :return: nothing
299*592efe25SPierre Pronchery  */
300*592efe25SPierre Pronchery void
spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t * spdx)301*592efe25SPierre Pronchery spdxtool_core_spdx_document_free(spdxtool_core_spdx_document_t *spdx)
302*592efe25SPierre Pronchery {
303*592efe25SPierre Pronchery 	pkgconf_node_t *iter = NULL, *iter_next = NULL;
304*592efe25SPierre Pronchery 
305*592efe25SPierre Pronchery 	if (!spdx)
306*592efe25SPierre Pronchery 		return;
307*592efe25SPierre Pronchery 
308*592efe25SPierre Pronchery 	free(spdx->spdx_id);
309*592efe25SPierre Pronchery 	free(spdx->creation_info);
310*592efe25SPierre Pronchery 	free(spdx->agent);
311*592efe25SPierre Pronchery 
312*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->rootElement.head, iter_next, iter)
313*592efe25SPierre Pronchery 	{
314*592efe25SPierre Pronchery 		spdxtool_software_sbom_t *sbom = iter->data;
315*592efe25SPierre Pronchery 		spdxtool_software_sbom_free(sbom);
316*592efe25SPierre Pronchery 		free(iter);
317*592efe25SPierre Pronchery 	}
318*592efe25SPierre Pronchery 
319*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->element.head, iter_next, iter)
320*592efe25SPierre Pronchery 	{
321*592efe25SPierre Pronchery 		free(iter->data);
322*592efe25SPierre Pronchery 		free(iter);
323*592efe25SPierre Pronchery 	}
324*592efe25SPierre Pronchery 
325*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->licenses.head, iter_next, iter)
326*592efe25SPierre Pronchery 	{
327*592efe25SPierre Pronchery 		spdxtool_simplelicensing_license_expression_t *expression = iter->data;
328*592efe25SPierre Pronchery 		spdxtool_simplelicensing_licenseExpression_free(expression);
329*592efe25SPierre Pronchery 		free(iter);
330*592efe25SPierre Pronchery 	}
331*592efe25SPierre Pronchery 
332*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->relationships.head, iter_next, iter)
333*592efe25SPierre Pronchery 	{
334*592efe25SPierre Pronchery 		spdxtool_core_relationship_t *relationship = iter->data;
335*592efe25SPierre Pronchery 		spdxtool_core_relationship_free(relationship);
336*592efe25SPierre Pronchery 		free(iter);
337*592efe25SPierre Pronchery 	}
338*592efe25SPierre Pronchery 
339*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->maintainers.head, iter_next, iter)
340*592efe25SPierre Pronchery 	{
341*592efe25SPierre Pronchery 		spdxtool_core_agent_t *maintainer = iter->data;
342*592efe25SPierre Pronchery 		spdxtool_core_agent_free(maintainer);
343*592efe25SPierre Pronchery 		free(iter);
344*592efe25SPierre Pronchery 	}
345*592efe25SPierre Pronchery 
346*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY_SAFE(spdx->packages.head, iter_next, iter)
347*592efe25SPierre Pronchery 	{
348*592efe25SPierre Pronchery 		free(iter);
349*592efe25SPierre Pronchery 	}
350*592efe25SPierre Pronchery 
351*592efe25SPierre Pronchery 	free(spdx);
352*592efe25SPierre Pronchery }
353*592efe25SPierre Pronchery 
354*592efe25SPierre Pronchery /*
355*592efe25SPierre Pronchery  * !doc
356*592efe25SPierre Pronchery  *
357*592efe25SPierre Pronchery  * .. c:function:: spdxtool_serialize_value_t *spdxtool_core_spdx_document_to_object(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx)
358*592efe25SPierre Pronchery  *
359*592efe25SPierre Pronchery  *    Serialize /Core/SpdxDocument struct to a JSON value tree. This function
360*592efe25SPierre Pronchery  *    should be called after all SBOMs and packages have been serialized so that
361*592efe25SPierre Pronchery  *    the document's element and rootElement lists are fully populated.
362*592efe25SPierre Pronchery  *
363*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
364*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct to be serialized.
365*592efe25SPierre Pronchery  *    :return: spdxtool_serialize_value_t * representing the SpdxDocument object.
366*592efe25SPierre Pronchery  */
367*592efe25SPierre Pronchery spdxtool_serialize_value_t *
spdxtool_core_spdx_document_to_object(pkgconf_client_t * client,spdxtool_core_spdx_document_t * spdx)368*592efe25SPierre Pronchery spdxtool_core_spdx_document_to_object(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx)
369*592efe25SPierre Pronchery {
370*592efe25SPierre Pronchery 	spdxtool_serialize_value_t *ret = NULL;
371*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_t *object_list = NULL;
372*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *root_element_array = NULL;
373*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *element_array = NULL;
374*592efe25SPierre Pronchery 
375*592efe25SPierre Pronchery 	object_list = spdxtool_serialize_object_list_new();
376*592efe25SPierre Pronchery 	if (!object_list)
377*592efe25SPierre Pronchery 		goto err;
378*592efe25SPierre Pronchery 
379*592efe25SPierre Pronchery 	root_element_array = spdxtool_serialize_array_new();
380*592efe25SPierre Pronchery 	if (!root_element_array)
381*592efe25SPierre Pronchery 		goto err;
382*592efe25SPierre Pronchery 
383*592efe25SPierre Pronchery 	pkgconf_node_t *iter = NULL;
384*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(spdx->rootElement.head, iter)
385*592efe25SPierre Pronchery 	{
386*592efe25SPierre Pronchery 		spdxtool_software_sbom_t *sbom = iter->data;
387*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(root_element_array, sbom->spdx_id))
388*592efe25SPierre Pronchery 			goto err;
389*592efe25SPierre Pronchery 	}
390*592efe25SPierre Pronchery 
391*592efe25SPierre Pronchery 	element_array = spdxtool_serialize_array_new();
392*592efe25SPierre Pronchery 	if (!element_array)
393*592efe25SPierre Pronchery 		goto err;
394*592efe25SPierre Pronchery 
395*592efe25SPierre Pronchery 	if (!spdxtool_serialize_array_add_string(element_array, spdx->agent))
396*592efe25SPierre Pronchery 		goto err;
397*592efe25SPierre Pronchery 
398*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(spdx->element.head, iter)
399*592efe25SPierre Pronchery 	{
400*592efe25SPierre Pronchery 		char *element_id = iter->data;
401*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(element_array, element_id))
402*592efe25SPierre Pronchery 			goto err;
403*592efe25SPierre Pronchery 	}
404*592efe25SPierre Pronchery 
405*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(spdx->rootElement.head, iter)
406*592efe25SPierre Pronchery 	{
407*592efe25SPierre Pronchery 		spdxtool_software_sbom_t *sbom = iter->data;
408*592efe25SPierre Pronchery 		char *pkg_spdx_id = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "spdxId");
409*592efe25SPierre Pronchery 		if (!pkg_spdx_id)
410*592efe25SPierre Pronchery 			goto err;
411*592efe25SPierre Pronchery 
412*592efe25SPierre Pronchery 		bool ok = spdxtool_serialize_array_add_string(element_array, sbom->spdx_id) &&
413*592efe25SPierre Pronchery 			spdxtool_serialize_array_add_string(element_array, pkg_spdx_id);
414*592efe25SPierre Pronchery 		free(pkg_spdx_id);
415*592efe25SPierre Pronchery 
416*592efe25SPierre Pronchery 		if (!ok)
417*592efe25SPierre Pronchery 			goto err;
418*592efe25SPierre Pronchery 	}
419*592efe25SPierre Pronchery 
420*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_string(object_list, "type", spdx->type) &&
421*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "creationInfo", spdx->creation_info) &&
422*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "spdxId", spdx->spdx_id)))
423*592efe25SPierre Pronchery 	{
424*592efe25SPierre Pronchery 		goto err;
425*592efe25SPierre Pronchery 	}
426*592efe25SPierre Pronchery 
427*592efe25SPierre Pronchery 	/* object_add_array always takes ownership of the array (it is freed even on
428*592efe25SPierre Pronchery 	 * failure), so clear our reference before checking the result to avoid a
429*592efe25SPierre Pronchery 	 * double free at the error label.
430*592efe25SPierre Pronchery 	 */
431*592efe25SPierre Pronchery 	bool ok = spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array);
432*592efe25SPierre Pronchery 	root_element_array = NULL;
433*592efe25SPierre Pronchery 	if (!ok)
434*592efe25SPierre Pronchery 		goto err;
435*592efe25SPierre Pronchery 
436*592efe25SPierre Pronchery 	ok = spdxtool_serialize_object_add_array(object_list, "element", element_array);
437*592efe25SPierre Pronchery 	element_array = NULL;
438*592efe25SPierre Pronchery 	if (!ok)
439*592efe25SPierre Pronchery 		goto err;
440*592efe25SPierre Pronchery 
441*592efe25SPierre Pronchery 	ret = spdxtool_serialize_value_object(object_list);
442*592efe25SPierre Pronchery 	object_list = NULL;
443*592efe25SPierre Pronchery 
444*592efe25SPierre Pronchery err:
445*592efe25SPierre Pronchery 	if (!ret)
446*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_to_object: out of memory");
447*592efe25SPierre Pronchery 
448*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_free(object_list);
449*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(root_element_array);
450*592efe25SPierre Pronchery 	spdxtool_serialize_array_free(element_array);
451*592efe25SPierre Pronchery 	return ret;
452*592efe25SPierre Pronchery }
453*592efe25SPierre Pronchery 
454*592efe25SPierre Pronchery /*
455*592efe25SPierre Pronchery  * !doc
456*592efe25SPierre Pronchery  *
457*592efe25SPierre Pronchery  * .. c:function:: bool spdxtool_core_spdx_document_is_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *license)
458*592efe25SPierre Pronchery  *
459*592efe25SPierre Pronchery  *    Find out if specific license is already there.
460*592efe25SPierre Pronchery  *
461*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
462*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct being used.
463*592efe25SPierre Pronchery  *    :param const char *license: SPDX name of license
464*592efe25SPierre Pronchery  *    :return: true is license is there and false if not
465*592efe25SPierre Pronchery  */
466*592efe25SPierre Pronchery bool
spdxtool_core_spdx_document_is_license(pkgconf_client_t * client,const spdxtool_core_spdx_document_t * spdx,const char * license)467*592efe25SPierre Pronchery spdxtool_core_spdx_document_is_license(pkgconf_client_t *client, const spdxtool_core_spdx_document_t *spdx, const char *license)
468*592efe25SPierre Pronchery {
469*592efe25SPierre Pronchery 	pkgconf_node_t *iter = NULL;
470*592efe25SPierre Pronchery 	spdxtool_simplelicensing_license_expression_t *expression = NULL;
471*592efe25SPierre Pronchery 
472*592efe25SPierre Pronchery 	(void) client;
473*592efe25SPierre Pronchery 
474*592efe25SPierre Pronchery 	if (!license || !spdx)
475*592efe25SPierre Pronchery 	{
476*592efe25SPierre Pronchery 		return false;
477*592efe25SPierre Pronchery 	}
478*592efe25SPierre Pronchery 
479*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(spdx->licenses.head, iter)
480*592efe25SPierre Pronchery 	{
481*592efe25SPierre Pronchery 		expression = iter->data;
482*592efe25SPierre Pronchery 		if (!strcmp(expression->license_expression, license))
483*592efe25SPierre Pronchery 		{
484*592efe25SPierre Pronchery 			return true;
485*592efe25SPierre Pronchery 		}
486*592efe25SPierre Pronchery 	}
487*592efe25SPierre Pronchery 
488*592efe25SPierre Pronchery 	return false;
489*592efe25SPierre Pronchery }
490*592efe25SPierre Pronchery 
491*592efe25SPierre Pronchery /*
492*592efe25SPierre Pronchery  * !doc
493*592efe25SPierre Pronchery  *
494*592efe25SPierre Pronchery  * .. c:function:: bool spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *license)
495*592efe25SPierre Pronchery  *
496*592efe25SPierre Pronchery  *    Add license to SpdxDocument and make sure that specific license is not already there.
497*592efe25SPierre Pronchery  *
498*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
499*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct being used.
500*592efe25SPierre Pronchery  *    :param const char *license: SPDX name of license
501*592efe25SPierre Pronchery  *    :return: true on success, false on failure
502*592efe25SPierre Pronchery  */
503*592efe25SPierre Pronchery bool
spdxtool_core_spdx_document_add_license(pkgconf_client_t * client,spdxtool_core_spdx_document_t * spdx,const char * license)504*592efe25SPierre Pronchery spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *license)
505*592efe25SPierre Pronchery {
506*592efe25SPierre Pronchery 	if (!license || !spdx)
507*592efe25SPierre Pronchery 		return false;
508*592efe25SPierre Pronchery 
509*592efe25SPierre Pronchery 	if (spdxtool_core_spdx_document_is_license(client, spdx, license))
510*592efe25SPierre Pronchery 		return true;
511*592efe25SPierre Pronchery 
512*592efe25SPierre Pronchery 	pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t));
513*592efe25SPierre Pronchery 	if (!node)
514*592efe25SPierre Pronchery 	{
515*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_add_license: out of memory");
516*592efe25SPierre Pronchery 		return false;
517*592efe25SPierre Pronchery 	}
518*592efe25SPierre Pronchery 
519*592efe25SPierre Pronchery 	spdxtool_simplelicensing_license_expression_t *expression = spdxtool_simplelicensing_licenseExpression_new(client, license);
520*592efe25SPierre Pronchery 	if (!expression)
521*592efe25SPierre Pronchery 	{
522*592efe25SPierre Pronchery 		free(node);
523*592efe25SPierre Pronchery 		return false;
524*592efe25SPierre Pronchery 	}
525*592efe25SPierre Pronchery 
526*592efe25SPierre Pronchery 	pkgconf_node_insert_tail(node, expression, &spdx->licenses);
527*592efe25SPierre Pronchery 	if (!spdxtool_core_spdx_document_add_element(client, spdx, expression->spdx_id))
528*592efe25SPierre Pronchery 		return false;
529*592efe25SPierre Pronchery 
530*592efe25SPierre Pronchery 	return true;
531*592efe25SPierre Pronchery }
532*592efe25SPierre Pronchery 
533*592efe25SPierre Pronchery /*
534*592efe25SPierre Pronchery  * !doc
535*592efe25SPierre Pronchery  *
536*592efe25SPierre Pronchery  * .. c:function:: bool spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *element)
537*592efe25SPierre Pronchery  *
538*592efe25SPierre Pronchery  *    Add element spdxId to SpdxDocument
539*592efe25SPierre Pronchery  *
540*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
541*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct being used.
542*592efe25SPierre Pronchery  *    :param char *element: spdxId of element
543*592efe25SPierre Pronchery  *    :return: true on success, false on failure
544*592efe25SPierre Pronchery  */
545*592efe25SPierre Pronchery bool
spdxtool_core_spdx_document_add_element(pkgconf_client_t * client,spdxtool_core_spdx_document_t * spdx,const char * element)546*592efe25SPierre Pronchery spdxtool_core_spdx_document_add_element(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *element)
547*592efe25SPierre Pronchery {
548*592efe25SPierre Pronchery 	if (!element || !spdx)
549*592efe25SPierre Pronchery 		return false;
550*592efe25SPierre Pronchery 
551*592efe25SPierre Pronchery 	pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t));
552*592efe25SPierre Pronchery 	if (!node)
553*592efe25SPierre Pronchery 	{
554*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_add_element: out of memory");
555*592efe25SPierre Pronchery 		return false;
556*592efe25SPierre Pronchery 	}
557*592efe25SPierre Pronchery 
558*592efe25SPierre Pronchery 	char *nelement = strdup(element);
559*592efe25SPierre Pronchery 	if (!nelement)
560*592efe25SPierre Pronchery 	{
561*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_add_element: out of memory");
562*592efe25SPierre Pronchery 		free(node);
563*592efe25SPierre Pronchery 		return false;
564*592efe25SPierre Pronchery 	}
565*592efe25SPierre Pronchery 
566*592efe25SPierre Pronchery 	pkgconf_node_insert_tail(node, nelement, &spdx->element);
567*592efe25SPierre Pronchery 	return true;
568*592efe25SPierre Pronchery }
569*592efe25SPierre Pronchery 
570*592efe25SPierre Pronchery /*
571*592efe25SPierre Pronchery  * !doc
572*592efe25SPierre Pronchery  *
573*592efe25SPierre Pronchery  * .. c:function:: const char *spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *name)
574*592efe25SPierre Pronchery  *
575*592efe25SPierre Pronchery  *    Register a package maintainer as an Agent and add it to the SpdxDocument so that
576*592efe25SPierre Pronchery  *    packages may reference it via their ``suppliedBy`` field.  Maintainers are
577*592efe25SPierre Pronchery  *    deduplicated by their spdxId, so a maintainer shared between packages is only
578*592efe25SPierre Pronchery  *    emitted once.  The first time a maintainer is seen, its spdxId is also added to
579*592efe25SPierre Pronchery  *    the document element list.
580*592efe25SPierre Pronchery  *
581*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
582*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct being used.
583*592efe25SPierre Pronchery  *    :param const char *name: Maintainer name as declared in the package.
584*592efe25SPierre Pronchery  *    :return: the maintainer Agent spdxId (owned by the document) on success, NULL on failure
585*592efe25SPierre Pronchery  */
586*592efe25SPierre Pronchery const char *
spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t * client,spdxtool_core_spdx_document_t * spdx,const char * name)587*592efe25SPierre Pronchery spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, const char *name)
588*592efe25SPierre Pronchery {
589*592efe25SPierre Pronchery 	pkgconf_node_t *iter = NULL;
590*592efe25SPierre Pronchery 
591*592efe25SPierre Pronchery 	if (!client || !spdx || !name)
592*592efe25SPierre Pronchery 		return NULL;
593*592efe25SPierre Pronchery 
594*592efe25SPierre Pronchery 	spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, spdx->creation_info, name);
595*592efe25SPierre Pronchery 	if (!agent)
596*592efe25SPierre Pronchery 		return NULL;
597*592efe25SPierre Pronchery 
598*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(spdx->maintainers.head, iter)
599*592efe25SPierre Pronchery 	{
600*592efe25SPierre Pronchery 		spdxtool_core_agent_t *existing = iter->data;
601*592efe25SPierre Pronchery 		if (!strcmp(existing->spdx_id, agent->spdx_id))
602*592efe25SPierre Pronchery 		{
603*592efe25SPierre Pronchery 			spdxtool_core_agent_free(agent);
604*592efe25SPierre Pronchery 			return existing->spdx_id;
605*592efe25SPierre Pronchery 		}
606*592efe25SPierre Pronchery 	}
607*592efe25SPierre Pronchery 
608*592efe25SPierre Pronchery 	pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t));
609*592efe25SPierre Pronchery 	if (!node)
610*592efe25SPierre Pronchery 	{
611*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_add_maintainer: out of memory");
612*592efe25SPierre Pronchery 		spdxtool_core_agent_free(agent);
613*592efe25SPierre Pronchery 		return NULL;
614*592efe25SPierre Pronchery 	}
615*592efe25SPierre Pronchery 
616*592efe25SPierre Pronchery 	pkgconf_node_insert_tail(node, agent, &spdx->maintainers);
617*592efe25SPierre Pronchery 
618*592efe25SPierre Pronchery 	if (!spdxtool_core_spdx_document_add_element(client, spdx, agent->spdx_id))
619*592efe25SPierre Pronchery 		return NULL;
620*592efe25SPierre Pronchery 
621*592efe25SPierre Pronchery 	return agent->spdx_id;
622*592efe25SPierre Pronchery }
623*592efe25SPierre Pronchery 
624*592efe25SPierre Pronchery /*
625*592efe25SPierre Pronchery  * !doc
626*592efe25SPierre Pronchery  *
627*592efe25SPierre Pronchery  * .. c:function:: bool spdxtool_core_spdx_document_add_relationship(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, spdxtool_core_relationship_t *relationship)
628*592efe25SPierre Pronchery  *
629*592efe25SPierre Pronchery  *    Add relationship rel to SpdxDocument
630*592efe25SPierre Pronchery  *
631*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
632*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct being used.
633*592efe25SPierre Pronchery  *    :param spdxtool_core_relationship_t *relationship: relationship to add.
634*592efe25SPierre Pronchery  *    :return: true on success, false on failure
635*592efe25SPierre Pronchery  */
636*592efe25SPierre Pronchery bool
spdxtool_core_spdx_document_add_relationship(pkgconf_client_t * client,spdxtool_core_spdx_document_t * spdx,spdxtool_core_relationship_t * relationship)637*592efe25SPierre Pronchery spdxtool_core_spdx_document_add_relationship(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, spdxtool_core_relationship_t *relationship)
638*592efe25SPierre Pronchery {
639*592efe25SPierre Pronchery 	if (!client || !spdx || !relationship)
640*592efe25SPierre Pronchery 		return false;
641*592efe25SPierre Pronchery 
642*592efe25SPierre Pronchery 	pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t));
643*592efe25SPierre Pronchery 	if (!node)
644*592efe25SPierre Pronchery 	{
645*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_add_relationship: out of memory");
646*592efe25SPierre Pronchery 		return false;
647*592efe25SPierre Pronchery 	}
648*592efe25SPierre Pronchery 
649*592efe25SPierre Pronchery 	pkgconf_node_insert_tail(node, relationship, &spdx->relationships);
650*592efe25SPierre Pronchery 	return true;
651*592efe25SPierre Pronchery }
652*592efe25SPierre Pronchery 
653*592efe25SPierre Pronchery /*
654*592efe25SPierre Pronchery  * !doc
655*592efe25SPierre Pronchery  *
656*592efe25SPierre Pronchery  * .. c:function:: bool spdxtool_core_spdx_document_add_package(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, pkgconf_pkg_t *pkg)
657*592efe25SPierre Pronchery  *
658*592efe25SPierre Pronchery  *    Register a package with the SpdxDocument for later serialization. The document
659*592efe25SPierre Pronchery  *    does not take ownership of the package pointer; the package must outlive the
660*592efe25SPierre Pronchery  *    document and will not be freed by spdxtool_core_spdx_document_free.
661*592efe25SPierre Pronchery  *
662*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
663*592efe25SPierre Pronchery  *    :param spdxtool_core_spdx_document_t *spdx: SpdxDocument struct to register the package with.
664*592efe25SPierre Pronchery  *    :param pkgconf_pkg_t *pkg: Package to register. Ownership is NOT transferred.
665*592efe25SPierre Pronchery  *    :return: true on success, false on failure
666*592efe25SPierre Pronchery  */
667*592efe25SPierre Pronchery bool
spdxtool_core_spdx_document_add_package(pkgconf_client_t * client,spdxtool_core_spdx_document_t * spdx,pkgconf_pkg_t * pkg)668*592efe25SPierre Pronchery spdxtool_core_spdx_document_add_package(pkgconf_client_t *client, spdxtool_core_spdx_document_t *spdx, pkgconf_pkg_t *pkg)
669*592efe25SPierre Pronchery {
670*592efe25SPierre Pronchery 	if (!client || !spdx || !pkg)
671*592efe25SPierre Pronchery 		return false;
672*592efe25SPierre Pronchery 
673*592efe25SPierre Pronchery 	pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t));
674*592efe25SPierre Pronchery 	if (!node)
675*592efe25SPierre Pronchery 	{
676*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_spdx_document_add_package: out of memory");
677*592efe25SPierre Pronchery 		return false;
678*592efe25SPierre Pronchery 	}
679*592efe25SPierre Pronchery 
680*592efe25SPierre Pronchery 	pkgconf_node_insert_tail(node, pkg, &spdx->packages);
681*592efe25SPierre Pronchery 	return true;
682*592efe25SPierre Pronchery }
683*592efe25SPierre Pronchery 
684*592efe25SPierre Pronchery /*
685*592efe25SPierre Pronchery  * !doc
686*592efe25SPierre Pronchery  *
687*592efe25SPierre Pronchery  * .. c:function:: spdxtool_core_relationship_t *spdxtool_core_relationship_new(pkgconf_client_t *client, const char *creation_info_id, const char *spdx_id, const char *from, const char *to, const char *relationship_type)
688*592efe25SPierre Pronchery  *
689*592efe25SPierre Pronchery  *    Create new /Core/Relationship struct
690*592efe25SPierre Pronchery  *
691*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
692*592efe25SPierre Pronchery  *    :param const char *creation_id: Id for creation info
693*592efe25SPierre Pronchery  *    :param const char *spdx_id: Id of this SpdxDocument
694*592efe25SPierre Pronchery  *    :param const char *from: from spdxId
695*592efe25SPierre Pronchery  *    :param const char *to: to spdxId
696*592efe25SPierre Pronchery  *    :param const char *relationship_type: These can be found on SPDX documentation
697*592efe25SPierre Pronchery  *    :return: NULL if some problem occurs and SpdxDocument struct if not
698*592efe25SPierre Pronchery  */
699*592efe25SPierre Pronchery spdxtool_core_relationship_t *
spdxtool_core_relationship_new(pkgconf_client_t * client,const char * creation_info_id,const char * spdx_id,const char * from,pkgconf_list_t * to,const char * relationship_type)700*592efe25SPierre Pronchery spdxtool_core_relationship_new(pkgconf_client_t *client, const char *creation_info_id, const char *spdx_id, const char *from, pkgconf_list_t *to, const char *relationship_type)
701*592efe25SPierre Pronchery {
702*592efe25SPierre Pronchery 	if (!client || !creation_info_id || !spdx_id || !from || !to || !relationship_type)
703*592efe25SPierre Pronchery 		return NULL;
704*592efe25SPierre Pronchery 
705*592efe25SPierre Pronchery 	spdxtool_core_relationship_t *relationship = calloc(1, sizeof(spdxtool_core_relationship_t));
706*592efe25SPierre Pronchery 	if (!relationship)
707*592efe25SPierre Pronchery 		goto err;
708*592efe25SPierre Pronchery 
709*592efe25SPierre Pronchery 	relationship->type = "Relationship";
710*592efe25SPierre Pronchery 	relationship->creation_info = strdup(creation_info_id);
711*592efe25SPierre Pronchery 	relationship->spdx_id = strdup(spdx_id);
712*592efe25SPierre Pronchery 	relationship->from = strdup(from);
713*592efe25SPierre Pronchery 	relationship->to = to;
714*592efe25SPierre Pronchery 	relationship->relationship_type = strdup(relationship_type);
715*592efe25SPierre Pronchery 
716*592efe25SPierre Pronchery 	if (!relationship->creation_info || !relationship->spdx_id || !relationship->from || !relationship->relationship_type)
717*592efe25SPierre Pronchery 		goto err;
718*592efe25SPierre Pronchery 
719*592efe25SPierre Pronchery 	return relationship;
720*592efe25SPierre Pronchery 
721*592efe25SPierre Pronchery err:
722*592efe25SPierre Pronchery 	pkgconf_error(client, "spdxtool_core_relationship_new: out of memory");
723*592efe25SPierre Pronchery 	spdxtool_core_relationship_free(relationship);
724*592efe25SPierre Pronchery 	return NULL;
725*592efe25SPierre Pronchery }
726*592efe25SPierre Pronchery 
727*592efe25SPierre Pronchery /*
728*592efe25SPierre Pronchery  * !doc
729*592efe25SPierre Pronchery  *
730*592efe25SPierre Pronchery  * .. c:function:: bool spdxtool_core_relationship_set_scope(pkgconf_client_t *client, spdxtool_core_relationship_t *relationship, const char *scope)
731*592efe25SPierre Pronchery  *
732*592efe25SPierre Pronchery  *    Promote a relationship to a /Core/LifecycleScopedRelationship by attaching a lifecycle
733*592efe25SPierre Pronchery  *    scope (for example, ``development`` for a private build dependency).  This is the SPDX 3.0
734*592efe25SPierre Pronchery  *    representation of SPDX 2.x's ``*_DEPENDENCY_OF`` relationship variants.
735*592efe25SPierre Pronchery  *
736*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
737*592efe25SPierre Pronchery  *    :param spdxtool_core_relationship_t *relationship: Relationship struct to scope.
738*592efe25SPierre Pronchery  *    :param const char *scope: LifecycleScopeType value, e.g. "development".
739*592efe25SPierre Pronchery  *    :return: true on success, false on failure
740*592efe25SPierre Pronchery  */
741*592efe25SPierre Pronchery bool
spdxtool_core_relationship_set_scope(pkgconf_client_t * client,spdxtool_core_relationship_t * relationship,const char * scope)742*592efe25SPierre Pronchery spdxtool_core_relationship_set_scope(pkgconf_client_t *client, spdxtool_core_relationship_t *relationship, const char *scope)
743*592efe25SPierre Pronchery {
744*592efe25SPierre Pronchery 	if (!relationship || !scope)
745*592efe25SPierre Pronchery 		return false;
746*592efe25SPierre Pronchery 
747*592efe25SPierre Pronchery 	char *scope_copy = strdup(scope);
748*592efe25SPierre Pronchery 	if (!scope_copy)
749*592efe25SPierre Pronchery 	{
750*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_relationship_set_scope: out of memory");
751*592efe25SPierre Pronchery 		return false;
752*592efe25SPierre Pronchery 	}
753*592efe25SPierre Pronchery 
754*592efe25SPierre Pronchery 	free(relationship->scope);
755*592efe25SPierre Pronchery 	relationship->scope = scope_copy;
756*592efe25SPierre Pronchery 	relationship->type = "LifecycleScopedRelationship";
757*592efe25SPierre Pronchery 
758*592efe25SPierre Pronchery 	return true;
759*592efe25SPierre Pronchery }
760*592efe25SPierre Pronchery 
761*592efe25SPierre Pronchery /*
762*592efe25SPierre Pronchery  * !doc
763*592efe25SPierre Pronchery  *
764*592efe25SPierre Pronchery  * .. c:function:: void spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship)
765*592efe25SPierre Pronchery  *
766*592efe25SPierre Pronchery  *    Free /Core/Relationship struct
767*592efe25SPierre Pronchery  *
768*592efe25SPierre Pronchery  *    :param spdxtool_core_relationship_t *relationship: Relationship struct to be freed.
769*592efe25SPierre Pronchery  *    :return: nothing
770*592efe25SPierre Pronchery  */
771*592efe25SPierre Pronchery void
spdxtool_core_relationship_free(spdxtool_core_relationship_t * relationship)772*592efe25SPierre Pronchery spdxtool_core_relationship_free(spdxtool_core_relationship_t *relationship)
773*592efe25SPierre Pronchery {
774*592efe25SPierre Pronchery 	if (!relationship)
775*592efe25SPierre Pronchery 		return;
776*592efe25SPierre Pronchery 
777*592efe25SPierre Pronchery 	free(relationship->spdx_id);
778*592efe25SPierre Pronchery 	free(relationship->creation_info);
779*592efe25SPierre Pronchery 	free(relationship->from);
780*592efe25SPierre Pronchery 	pkgconf_license_free(relationship->to);
781*592efe25SPierre Pronchery 	free(relationship->to);
782*592efe25SPierre Pronchery 	free(relationship->relationship_type);
783*592efe25SPierre Pronchery 	free(relationship->scope);
784*592efe25SPierre Pronchery 
785*592efe25SPierre Pronchery 	free(relationship);
786*592efe25SPierre Pronchery }
787*592efe25SPierre Pronchery 
788*592efe25SPierre Pronchery /*
789*592efe25SPierre Pronchery  * !doc
790*592efe25SPierre Pronchery  *
791*592efe25SPierre Pronchery  * .. c:function:: spdxtool_serialize_value_t *spdxtool_core_relationship_to_object(pkgconf_client_t *client, const spdxtool_core_relationship_t *relationship)
792*592efe25SPierre Pronchery  *
793*592efe25SPierre Pronchery  *    Serialize /Core/Relationship struct to a JSON value tree.
794*592efe25SPierre Pronchery  *
795*592efe25SPierre Pronchery  *    :param pkgconf_client_t *client: The pkgconf client being accessed.
796*592efe25SPierre Pronchery  *    :param const spdxtool_core_relationship_t *relationship: Relationship struct to be serialized.
797*592efe25SPierre Pronchery  *    :return: spdxtool_serialize_value_t * representing the Relationship object.
798*592efe25SPierre Pronchery  */
799*592efe25SPierre Pronchery spdxtool_serialize_value_t *
spdxtool_core_relationship_to_object(pkgconf_client_t * client,const spdxtool_core_relationship_t * relationship)800*592efe25SPierre Pronchery spdxtool_core_relationship_to_object(pkgconf_client_t *client, const spdxtool_core_relationship_t *relationship)
801*592efe25SPierre Pronchery {
802*592efe25SPierre Pronchery 	spdxtool_serialize_value_t *ret = NULL;
803*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_t *object_list = spdxtool_serialize_object_list_new();
804*592efe25SPierre Pronchery 	if (!object_list)
805*592efe25SPierre Pronchery 		goto err;
806*592efe25SPierre Pronchery 
807*592efe25SPierre Pronchery 	spdxtool_serialize_array_t *to = spdxtool_serialize_array_new();
808*592efe25SPierre Pronchery 	if (!to)
809*592efe25SPierre Pronchery 		goto err;
810*592efe25SPierre Pronchery 
811*592efe25SPierre Pronchery 	pkgconf_node_t *node = NULL;
812*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(relationship->to->head, node)
813*592efe25SPierre Pronchery 	{
814*592efe25SPierre Pronchery 		const pkgconf_license_t *license = node->data;
815*592efe25SPierre Pronchery 		if (!spdxtool_serialize_array_add_string(to, license->data))
816*592efe25SPierre Pronchery 		{
817*592efe25SPierre Pronchery 			spdxtool_serialize_array_free(to);
818*592efe25SPierre Pronchery 			goto err;
819*592efe25SPierre Pronchery 		}
820*592efe25SPierre Pronchery 	}
821*592efe25SPierre Pronchery 
822*592efe25SPierre Pronchery 	if (!(spdxtool_serialize_object_add_string(object_list, "type", relationship->type) &&
823*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "creationInfo", relationship->creation_info) &&
824*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "spdxId", relationship->spdx_id) &&
825*592efe25SPierre Pronchery 		spdxtool_serialize_object_add_string(object_list, "from", relationship->from)))
826*592efe25SPierre Pronchery 	{
827*592efe25SPierre Pronchery 		/* none of the above transfers ownership of `to` */
828*592efe25SPierre Pronchery 		spdxtool_serialize_array_free(to);
829*592efe25SPierre Pronchery 		goto err;
830*592efe25SPierre Pronchery 	}
831*592efe25SPierre Pronchery 
832*592efe25SPierre Pronchery 	/* object_add_array always takes ownership of `to` (it is freed even on failure) */
833*592efe25SPierre Pronchery 	if (!spdxtool_serialize_object_add_array(object_list, "to", to))
834*592efe25SPierre Pronchery 		goto err;
835*592efe25SPierre Pronchery 
836*592efe25SPierre Pronchery 	if (!spdxtool_serialize_object_add_string(object_list, "relationshipType", relationship->relationship_type))
837*592efe25SPierre Pronchery 		goto err;
838*592efe25SPierre Pronchery 
839*592efe25SPierre Pronchery 	if (relationship->scope != NULL &&
840*592efe25SPierre Pronchery 		!spdxtool_serialize_object_add_string(object_list, "scope", relationship->scope))
841*592efe25SPierre Pronchery 	{
842*592efe25SPierre Pronchery 		goto err;
843*592efe25SPierre Pronchery 	}
844*592efe25SPierre Pronchery 
845*592efe25SPierre Pronchery 	ret = spdxtool_serialize_value_object(object_list);
846*592efe25SPierre Pronchery 	object_list = NULL;
847*592efe25SPierre Pronchery 
848*592efe25SPierre Pronchery err:
849*592efe25SPierre Pronchery 	if (!ret)
850*592efe25SPierre Pronchery 		pkgconf_error(client, "spdxtool_core_relationship_to_object: out of memory");
851*592efe25SPierre Pronchery 
852*592efe25SPierre Pronchery 	spdxtool_serialize_object_list_free(object_list);
853*592efe25SPierre Pronchery 	return ret;
854*592efe25SPierre Pronchery }
855