xref: /illumos-gate/usr/src/lib/libcommputil/common/sdp_parse_helper.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Helper functions to skip white spaces, find tokens, find separators and free
31  * memory.
32  */
33 
34 #include <stdio.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <sdp.h>
41 
42 #include "sdp_parse.h"
43 #include "commp_util.h"
44 
45 void
46 sdp_free_origin(sdp_origin_t *origin)
47 {
48 	if (origin != NULL) {
49 		if (origin->o_username != NULL)
50 			free(origin->o_username);
51 		if (origin->o_nettype != NULL)
52 			free(origin->o_nettype);
53 		if (origin->o_addrtype != NULL)
54 			free(origin->o_addrtype);
55 		if (origin->o_address != NULL)
56 			free(origin->o_address);
57 		free(origin);
58 	}
59 }
60 
61 void
62 sdp_free_key(sdp_key_t *key)
63 {
64 	if (key != NULL) {
65 		if (key->k_method != NULL)
66 			free(key->k_method);
67 		if (key->k_enckey != NULL)
68 			free(key->k_enckey);
69 		free(key);
70 	}
71 }
72 
73 void
74 sdp_free_zone(sdp_zone_t *zone)
75 {
76 	sdp_zone_t	*next_zone;
77 
78 	while (zone != NULL) {
79 		next_zone = zone->z_next;
80 		if (zone->z_offset != NULL)
81 			free(zone->z_offset);
82 		free(zone);
83 		zone = next_zone;
84 	}
85 }
86 
87 void
88 sdp_free_list(sdp_list_t *list)
89 {
90 	sdp_list_t	*next_list;
91 
92 	while (list != NULL) {
93 		next_list = list->next;
94 		if (list->value != NULL)
95 			free(list->value);
96 		free(list);
97 		list = next_list;
98 	}
99 }
100 
101 void
102 sdp_free_media(sdp_media_t *media)
103 {
104 	sdp_media_t	*next_media;
105 
106 	while (media != NULL) {
107 		next_media = media->m_next;
108 		if (media->m_name != NULL)
109 			free(media->m_name);
110 		if (media->m_proto != NULL)
111 			free(media->m_proto);
112 		if (media->m_format != NULL)
113 			sdp_free_list(media->m_format);
114 		if (media->m_info != NULL)
115 			free(media->m_info);
116 		if (media->m_conn != NULL)
117 			sdp_free_connection(media->m_conn);
118 		if (media->m_bw != NULL)
119 			sdp_free_bandwidth(media->m_bw);
120 		if (media->m_key != NULL)
121 			sdp_free_key(media->m_key);
122 		if (media->m_attr != NULL)
123 			sdp_free_attribute(media->m_attr);
124 		free(media);
125 		media = next_media;
126 	}
127 }
128 
129 void
130 sdp_free_attribute(sdp_attr_t *attr)
131 {
132 	sdp_attr_t	*next_attr;
133 
134 	while (attr != NULL) {
135 		next_attr = attr->a_next;
136 		if (attr->a_name != NULL)
137 			free(attr->a_name);
138 		if (attr->a_value != NULL)
139 			free(attr->a_value);
140 		free(attr);
141 		attr = next_attr;
142 	}
143 }
144 
145 void
146 sdp_free_connection(sdp_conn_t *conn)
147 {
148 	sdp_conn_t	*next_conn;
149 
150 	while (conn != NULL) {
151 		next_conn = conn->c_next;
152 		if (conn->c_nettype != NULL)
153 			free(conn->c_nettype);
154 		if (conn->c_addrtype != NULL)
155 			free(conn->c_addrtype);
156 		if (conn->c_address != NULL)
157 			free(conn->c_address);
158 		free(conn);
159 		conn = next_conn;
160 	}
161 }
162 
163 void
164 sdp_free_bandwidth(sdp_bandwidth_t *bw)
165 {
166 	sdp_bandwidth_t		*next_bw;
167 
168 	while (bw != NULL) {
169 		next_bw = bw->b_next;
170 		if (bw->b_type != NULL)
171 			free(bw->b_type);
172 		free(bw);
173 		bw = next_bw;
174 	}
175 }
176 
177 void
178 sdp_free_repeat(sdp_repeat_t *repeat)
179 {
180 	sdp_repeat_t	*next_repeat;
181 
182 	while (repeat != NULL) {
183 		next_repeat = repeat->r_next;
184 		sdp_free_list(repeat->r_offset);
185 		free(repeat);
186 		repeat = next_repeat;
187 	}
188 }
189 
190 void
191 sdp_free_time(sdp_time_t *time)
192 {
193 	sdp_time_t	*next_time;
194 
195 	while (time != NULL) {
196 		next_time = time->t_next;
197 		sdp_free_repeat(time->t_repeat);
198 		free(time);
199 		time = next_time;
200 	}
201 }
202 
203 void
204 sdp_free_session(sdp_session_t *session)
205 {
206 	if (session == NULL)
207 		return;
208 	if (session->s_origin != NULL)
209 		sdp_free_origin(session->s_origin);
210 	if (session->s_name != NULL)
211 		free(session->s_name);
212 	if (session->s_info != NULL)
213 		free(session->s_info);
214 	if (session->s_uri != NULL)
215 		free(session->s_uri);
216 	if (session->s_email != NULL)
217 		sdp_free_list(session->s_email);
218 	if (session->s_phone != NULL)
219 		sdp_free_list(session->s_phone);
220 	if (session->s_conn != NULL)
221 		sdp_free_connection(session->s_conn);
222 	if (session->s_bw != NULL)
223 		sdp_free_bandwidth(session->s_bw);
224 	if (session->s_time != NULL)
225 		sdp_free_time(session->s_time);
226 	if (session->s_zone != NULL)
227 		sdp_free_zone(session->s_zone);
228 	if (session->s_key != NULL)
229 		sdp_free_key(session->s_key);
230 	if (session->s_attr != NULL)
231 		sdp_free_attribute(session->s_attr);
232 	if (session->s_media != NULL)
233 		sdp_free_media(session->s_media);
234 	free(session);
235 }
236 
237 /*
238  * Adds text of a given length to a linked list. If the list is NULL to
239  * start with it builds the new list
240  */
241 int
242 add_value_to_list(sdp_list_t **list, const char *value, int len, boolean_t text)
243 {
244 	sdp_list_t	*new = NULL;
245 	sdp_list_t	*tmp = NULL;
246 
247 	new = malloc(sizeof (sdp_list_t));
248 	if (new == NULL)
249 		return (ENOMEM);
250 	new->next = NULL;
251 	if (text)
252 		new->value = (char *)calloc(1, len + 1);
253 	else
254 		new->value = (uint64_t *)calloc(1, sizeof (uint64_t));
255 	if (new->value == NULL) {
256 		free(new);
257 		return (ENOMEM);
258 	}
259 	if (text) {
260 		(void) strncpy(new->value, value, len);
261 	} else {
262 		if (commp_time_to_secs((char *)value, (char *)(value +
263 		    len), new->value) != 0) {
264 			sdp_free_list(new);
265 			return (EINVAL);
266 		}
267 	}
268 	if (*list == NULL) {
269 		*list = new;
270 	} else {
271 		tmp = *list;
272 		while (tmp->next != NULL)
273 			tmp = tmp->next;
274 		tmp->next = new;
275 	}
276 	return (0);
277 }
278 
279 /*
280  * Given a linked list converts it to space separated string.
281  */
282 int
283 sdp_list_to_str(sdp_list_t *list, char **buf, boolean_t text)
284 {
285 	int 		size = 0;
286 	int 		wrote = 0;
287 	sdp_list_t	*tmp;
288 	char		*ret;
289 	char		c[1];
290 
291 	if (list == NULL) {
292 		*buf = NULL;
293 		return (EINVAL);
294 	}
295 	tmp = list;
296 	while (list != NULL) {
297 		if (text)
298 			size += strlen((char *)list->value);
299 		else
300 			size += snprintf(c, 1, "%lld",
301 			    *(uint64_t *)list->value);
302 		size++;
303 		list = list->next;
304 	}
305 	list = tmp;
306 	if (size > 0) {
307 		*buf = calloc(1, size + 1);
308 		if (*buf == NULL)
309 			return (ENOMEM);
310 		ret = *buf;
311 		while (list != NULL) {
312 			if (text) {
313 				wrote = snprintf(ret, size, "%s ",
314 				    (char *)list->value);
315 			} else {
316 				wrote = snprintf(ret, size, "%lld ",
317 				    *(uint64_t *)list->value);
318 			}
319 			ret = ret + wrote;
320 			size = size - wrote;
321 			list = list->next;
322 		}
323 	} else {
324 		return (EINVAL);
325 	}
326 	return (0);
327 }
328 
329 /*
330  * Given a space separated string, converts it into linked list. SDP field
331  * repeat and media can have undefined number of offsets or formats
332  * respectively. We need to capture it in a linked list.
333  */
334 int
335 sdp_str_to_list(sdp_list_t **list, const char *buf, int len, boolean_t text)
336 {
337 	const char	*begin;
338 	const char	*current;
339 	const char	*end;
340 	int		ret = 0;
341 
342 	if (len == 0)
343 		return (EINVAL);
344 	current = buf;
345 	end = current + len;
346 	/* takes care of strings with just spaces */
347 	if (commp_skip_white_space(&current, end) != 0)
348 		return (EINVAL);
349 	while (current < end) {
350 		(void) commp_skip_white_space(&current, end);
351 		begin = current;
352 		while (current < end) {
353 			if (isspace(*current))
354 				break;
355 			++current;
356 		}
357 		if (current != begin) {
358 			if ((ret = add_value_to_list(list, begin,
359 			    current - begin, text)) != 0) {
360 				sdp_free_list(*list);
361 				*list = NULL;
362 				return (ret);
363 			}
364 		}
365 	}
366 	return (0);
367 }
368