Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c
Location:line 275, column 19
Description:Access to field 'sdp_origin' results in a dereference of a null pointer (loaded from variable 'sdp')

Annotated Source Code

1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@ingroup sdp_printer
26 *
27 * @CFILE sdp_print.c Simple SDP printer interface.
28 *
29 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
30 *
31 * @date Created: Fri Feb 18 10:25:08 2000 ppessi
32 */
33
34#include "config.h"
35
36#include <sofia-sip/su_alloc.h>
37#include <sofia-sip/su_string.h>
38
39#include "sofia-sip/sdp.h"
40
41#include <stddef.h>
42#include <stdlib.h>
43#include <string.h>
44#include <stdarg.h>
45#include <stdio.h>
46#include <assert.h>
47
48/* ========================================================================= */
49/* Printing API */
50/* */
51
52#define SDP_BLOCK(512) (512)
53
54#define CRLF"\015\012" "\015\012"
55
56typedef unsigned longlonglong long ull;
57
58/** @typedef struct sdp_printer_s sdp_printer_t
59 *
60 * SDP printer handle.
61 *
62 * @sa #sdp_session_t, sdp_print(), sdp_printing_error(),
63 * sdp_message(), sdp_message_size(), sdp_printer_free()
64 */
65
66struct sdp_printer_s {
67 int pr_size;
68 su_home_t *pr_home;
69 char *pr_buffer;
70 size_t pr_bsiz;
71 size_t pr_used;
72 /* various flags */
73 unsigned pr_ok : 1;
74 unsigned pr_strict : 1;
75 unsigned pr_owns_buffer:1;
76 unsigned pr_may_realloc:1;
77 unsigned pr_all_rtpmaps:1;
78 unsigned pr_mode_manual:1;
79 unsigned pr_mode_always:1;
80};
81
82static struct sdp_printer_s printer_memory_error = {
83 sizeof(printer_memory_error),
84 NULL((void*)0),
85 "memory exhausted",
86 sizeof(printer_memory_error.pr_buffer),
87 sizeof(printer_memory_error.pr_buffer)
88};
89
90static void print_session(sdp_printer_t *p, sdp_session_t const *session);
91static void printing_error(sdp_printer_t *p, const char *fmt, ...);
92
93/** Print a SDP description.
94 *
95 * Encode the contents of the SDP session structure #sdp_session_t
96 * to the @a msgbuf. The @a msgbuf has size @a msgsize
97 * bytes. If @a msgbuf is @c NULL, the sdp_print() function allocates the
98 * required buffer from the @a home heap.
99 *
100 * @param home Memory home (may be NULL).
101 * @param session SDP session description structure to be encoded.
102 * @param msgbuf Buffer to which encoding is stored (may be NULL).
103 * @param msgsize Size of @a msgbuf.
104 * @param flags Flags specifying the encoding options.
105 *
106 * The @a flags specify encoding options as follows:
107 *
108 * @li #sdp_f_strict - Printer should only emit messages conforming strictly
109 * to the * specification.
110 *
111 * @li #sdp_f_realloc - If this flag is specified, and @a msgbuf is too
112 * small for the resulting SDP message, @c sdp_print() may allocate a new
113 * buffer for it from the heap.
114 *
115 * @li #sdp_f_print_prefix - The buffer provided by caller already contains
116 * valid data. The result will concatenated to the string in the buffer.
117 *
118 * @li #sdp_f_mode_always - Always add mode attributes to media
119 *
120 * @li #sdp_f_mode_manual - Do not generate mode attributes
121 *
122 * @return
123 * Always return a handle to an #sdp_printer_t object.
124 *
125 * @sa #sdp_printer_t, #sdp_session_t, sdp_printing_error(),
126 * sdp_message(), sdp_message_size(), sdp_printer_free(),
127 * sdp_parse().
128 */
129sdp_printer_t *sdp_print(su_home_t *home,
130 sdp_session_t const *session,
131 char msgbuf[],
132 isize_t msgsize,
133 int flags)
134{
135 sdp_printer_t *p = su_salloc(home, sizeof(*p));
136
137 if (p) {
138 p->pr_size = sizeof(p);
139 p->pr_home = home;
140 p->pr_used = 0;
141 if (msgbuf) {
142 p->pr_may_realloc = (flags & sdp_f_realloc) != 0;
143 p->pr_buffer = msgbuf;
144 p->pr_bsiz = msgsize;
145 if (flags & sdp_f_print_prefix)
146 p->pr_used = strlen(msgbuf);
147 }
148 else {
149 p->pr_owns_buffer = 1;
150 p->pr_buffer = su_alloc(home, SDP_BLOCK(512));
151 p->pr_bsiz = SDP_BLOCK(512);
152 }
153 p->pr_strict = (flags & sdp_f_strict) != 0;
154 p->pr_all_rtpmaps = (flags & sdp_f_all_rtpmaps) != 0;
155 p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
156 p->pr_mode_always = (flags & sdp_f_mode_always) != 0;
157
158 if (session)
159 print_session(p, session);
160 else
161 printing_error(p, "NULL session description");
162
163 return p;
164 }
165 else {
166 return &printer_memory_error;
167 }
168}
169
170/** @brief Get encoding error.
171 *
172 * Return a message describing the encoding error.
173 *
174 * @param p Pointer to an #sdp_printer_t object.
175 *
176 * @return
177 * Return a pointer to C string describing printing errors, or NULL if no
178 * error was encountered.
179 */
180char const *sdp_printing_error(sdp_printer_t *p)
181{
182 if (p)
183 if (!p->pr_ok)
184 return p->pr_buffer;
185 else
186 return NULL((void*)0);
187 else
188 return "null sdp_printer_t*";
189}
190
191/** @brief Get encoded SDP message.
192 *
193 * Return a pointer to a C string containing the SDP message.
194 *
195 * @param p Pointer to an #sdp_printer_t object.
196 *
197 * @return
198 * Return a pointer to a C string containing the encoded SDP message, or
199 * NULL upon an error.
200 */
201char const *sdp_message(sdp_printer_t *p)
202{
203 if (p && p->pr_ok)
204 return p->pr_buffer;
205 else
206 return NULL((void*)0);
207}
208
209/** @brief Get size of encoded SDP message.
210 *
211 * Return the size of the encoded SDP message.
212 *
213 * @param p Pointer to an #sdp_printer_t object.
214 *
215 * @return
216 * Number of bytes in SDP message excluding final NUL or 0 upon an error.
217 */
218isize_t sdp_message_size(sdp_printer_t *p)
219{
220 if (p && p->pr_ok)
221 return p->pr_used;
222 else
223 return 0;
224}
225
226/** Free a SDP printer.
227 *
228 * Free the printer object @a p and the message buffer possibly associated
229 * with it.
230 *
231 * @param p Pointer to an #sdp_printer_t object.
232 */
233void sdp_printer_free(sdp_printer_t *p)
234{
235 if (p && p != &printer_memory_error) {
236 if (p->pr_owns_buffer && p->pr_buffer)
237 su_free(p->pr_home, p->pr_buffer), p->pr_buffer = NULL((void*)0);
238 su_free(p->pr_home, p);
239 }
240}
241
242/* ========================================================================= */
243static void print_version(sdp_printer_t *p, sdp_version_t const *v);
244static void print_origin(sdp_printer_t *p, sdp_origin_t const *o);
245static void print_subject(sdp_printer_t *p, sdp_text_t *s);
246static void print_information(sdp_printer_t *p, sdp_text_t *i);
247static void print_uri(sdp_printer_t *p, sdp_text_t *u);
248static void print_emails(sdp_printer_t *p, sdp_list_t const *e);
249static void print_phones(sdp_printer_t *p, sdp_list_t const *ph);
250static void print_connection(sdp_printer_t *p, sdp_connection_t const *c);
251static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c);
252static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c);
253static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b);
254static void print_time(sdp_printer_t *p, sdp_time_t const *t);
255static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r);
256static void print_zone(sdp_printer_t *p, sdp_zone_t const *z);
257static void print_typed_time(sdp_printer_t *p, unsigned long t);
258static void print_key(sdp_printer_t *p, sdp_key_t const *k);
259static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a);
260static void print_charset(sdp_printer_t *p, sdp_text_t *charset);
261static void print_media(sdp_printer_t *p, sdp_session_t const *,
262 sdp_media_t const *m);
263
264static void print_text_list(sdp_printer_t*,
265 const char *, sdp_list_t const *l);
266
267static void sdp_printf(sdp_printer_t *p, const char *fmt, ...);
268
269static void print_session(sdp_printer_t *p, sdp_session_t const *sdp)
270{
271 p->pr_ok = 1;
272
273 if (p->pr_ok && sdp->sdp_version)
1
Assuming pointer value is null
2
Taking false branch
274 print_version(p, sdp->sdp_version);
275 if (p->pr_ok && sdp->sdp_origin)
3
Access to field 'sdp_origin' results in a dereference of a null pointer (loaded from variable 'sdp')
276 print_origin(p, sdp->sdp_origin);
277 if (p->pr_ok && sdp->sdp_subject)
278 print_subject(p, sdp->sdp_subject);
279 if (p->pr_ok && sdp->sdp_information)
280 print_information(p, sdp->sdp_information);
281 if (p->pr_ok && sdp->sdp_uri)
282 print_uri(p, sdp->sdp_uri);
283 if (p->pr_ok && sdp->sdp_emails)
284 print_emails(p, sdp->sdp_emails);
285 if (p->pr_ok && sdp->sdp_phones)
286 print_phones(p, sdp->sdp_phones);
287 if (p->pr_ok && sdp->sdp_connection)
288 print_connection(p, sdp->sdp_connection);
289 if (p->pr_ok && sdp->sdp_bandwidths)
290 print_bandwidths(p, sdp->sdp_bandwidths);
291 if (p->pr_ok)
292 print_time(p, sdp->sdp_time);
293 if (p->pr_ok && sdp->sdp_time) {
294 if (p->pr_ok && sdp->sdp_time->t_repeat)
295 print_repeat(p, sdp->sdp_time->t_repeat);
296 if (p->pr_ok && sdp->sdp_time->t_zone)
297 print_zone(p, sdp->sdp_time->t_zone);
298 }
299 if (p->pr_ok && sdp->sdp_key)
300 print_key(p, sdp->sdp_key);
301 if (p->pr_ok && sdp->sdp_charset)
302 print_charset(p, sdp->sdp_charset);
303 if (p->pr_ok && sdp->sdp_attributes)
304 print_attributes(p, sdp->sdp_attributes);
305 if (p->pr_ok && sdp->sdp_media)
306 print_media(p, sdp, sdp->sdp_media);
307}
308
309static void print_version(sdp_printer_t *p, sdp_version_t const *v)
310{
311 sdp_printf(p, "v=%lu" CRLF"\015\012", *v);
312}
313
314static void print_origin(sdp_printer_t *p, sdp_origin_t const *o)
315{
316 if (!o->o_address ||
317 !o->o_address->c_address ||
318 o->o_address->c_ttl != 0 ||
319 o->o_address->c_groups > 1) {
320 printing_error(p, "o= address malformed");
321 return;
322 }
323
324 sdp_printf(p, "o=%s "LLU"%llu"" "LLU"%llu"" ",
325 o->o_username,
326 (ull)o->o_id,
327 (ull)o->o_version);
328
329 print_connection2(p, o->o_address);
330}
331
332static void print_subject(sdp_printer_t *p, sdp_text_t *subject)
333{
334 sdp_printf(p, "s=%s" CRLF"\015\012", subject);
335}
336
337static void print_information(sdp_printer_t *p, sdp_text_t *information)
338{
339 sdp_printf(p, "i=%s" CRLF"\015\012", information);
340}
341
342static void print_uri(sdp_printer_t *p, sdp_text_t *uri)
343{
344 sdp_printf(p, "u=%s" CRLF"\015\012", uri);
345}
346
347static void print_emails(sdp_printer_t *p, sdp_list_t const *emails)
348{
349 print_text_list(p, "e=%s" CRLF"\015\012", emails);
350}
351
352static void print_phones(sdp_printer_t *p, sdp_list_t const *phones)
353{
354 print_text_list(p, "p=%s" CRLF"\015\012", phones);
355}
356
357static void print_connection(sdp_printer_t *p, sdp_connection_t const *c)
358{
359 sdp_printf(p, "c=");
360 print_connection2(p, c);
361}
362
363static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c)
364{
365 for (; c ; c = c->c_next) {
366 sdp_printf(p, "c=");
367 print_connection2(p, c);
368 }
369}
370
371static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c)
372{
373 const char *nettype;
374 const char *addrtype;
375
376 switch (c->c_nettype) {
377 case sdp_net_x:
378 nettype = NULL((void*)0);
379 break;
380 case sdp_net_in:
381 nettype = "IN ";
382 break;
383 default:
384 printing_error(p, "unknown nettype %u", c->c_nettype);
385 return;
386 }
387
388 switch (c->c_addrtype) {
389 case sdp_addr_x:
390 addrtype = NULL((void*)0);
391 break;
392 case sdp_addr_ip4:
393 nettype = "IN ";
394 addrtype = "IP4 ";
395 break;
396 case sdp_addr_ip6:
397 nettype = "IN ";
398 addrtype = "IP6 ";
399 break;
400 default:
401 printing_error(p, "unknown address type %u", c->c_addrtype);
402 return;
403 }
404
405 if (c->c_address == NULL((void*)0)) {
406 printing_error(p, "missing address");
407 return;
408 }
409
410 if (nettype && addrtype)
411 sdp_printf(p, "%s%s%s", nettype, addrtype, c->c_address);
412 else if (nettype)
413 sdp_printf(p, "%s%s%s", nettype, c->c_address);
414 else
415 sdp_printf(p, "%s", c->c_address);
416
417 if (c->c_mcast || c->c_ttl) {
418 sdp_printf(p, "/%u", c->c_ttl);
419 if (c->c_groups > 1)
420 sdp_printf(p, "/%u", c->c_groups);
421 }
422 sdp_printf(p, CRLF"\015\012");
423}
424
425static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b)
426{
427 for (; b ; b = b->b_next) {
428 char const *name;
429
430 switch (b->b_modifier) {
431 case sdp_bw_ct: name = "CT"; break;
432 case sdp_bw_as: name = "AS"; break;
433 default: name = b->b_modifier_name; break;
434 }
435
436 sdp_printf(p, "b=%s:%lu" CRLF"\015\012", name, b->b_value);
437 }
438}
439
440static void print_time(sdp_printer_t *p, sdp_time_t const *t)
441{
442 if (t || p->pr_strict)
443 sdp_printf(p, "t=%lu %lu" CRLF"\015\012", t ? t->t_start : 0L, t ? t->t_stop : 0L);
444}
445
446static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r)
447{
448 int i;
449
450 sdp_printf(p, "r=");
451 print_typed_time(p, r->r_interval);
452 sdp_printf(p, " ");
453 print_typed_time(p, r->r_duration);
454 for (i = 0; i < r->r_number_of_offsets; i++) {
455 sdp_printf(p, " ");
456 print_typed_time(p, r->r_offsets[i]);
457 }
458 sdp_printf(p, CRLF"\015\012");
459}
460
461static void print_zone(sdp_printer_t *p, sdp_zone_t const *z)
462{
463 int i;
464 sdp_printf(p, "z=");
465
466 for (i = 0; i < z->z_number_of_adjustments; i++) {
467 int negative = z->z_adjustments[i].z_offset < 0L;
468 sdp_printf(p, "%s%lu %s",
469 i > 0 ? " " : "",
470 z->z_adjustments[i].z_at,
471 negative ? "-" : "");
472 if (negative)
473 print_typed_time(p, -z->z_adjustments[i].z_offset);
474 else
475 print_typed_time(p, z->z_adjustments[i].z_offset);
476 }
477
478 sdp_printf(p, CRLF"\015\012");
479}
480
481static void print_typed_time(sdp_printer_t *p, unsigned long t)
482{
483 if (t % 60 || t == 0) {
484 sdp_printf(p, "%lu", t);
485 }
486 else {
487 t /= 60;
488
489 if (t % 60) {
490 sdp_printf(p, "%lum", t); /* minutes */
491 }
492 else {
493 t /= 60;
494
495 if (t % 24) {
496 sdp_printf(p, "%luh", t); /* hours */
497 }
498 else {
499 t /= 24;
500
501 sdp_printf(p, "%lud", t); /* days */
502 }
503 }
504 }
505}
506
507static void print_key(sdp_printer_t *p, sdp_key_t const *k)
508{
509 const char *method;
510 int have_material = k->k_material != NULL((void*)0);
511
512 switch (k->k_method) {
513 case sdp_key_x:
514 method = k->k_method_name; break;
515 case sdp_key_clear:
516 method = "clear"; break;
517 case sdp_key_base64:
518 method = "base64"; break;
519 case sdp_key_uri:
520 method = "uri"; break;
521 case sdp_key_prompt:
522 method = "prompt"; break;
523 default:
524 printing_error(p, "unknown key method (%d)", k->k_method);
525 return;
526 }
527
528 sdp_printf(p, "k=%s%s%s" CRLF"\015\012", method,
529 have_material ? ":" : "",
530 have_material ? k->k_material : "");
531}
532
533static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a)
534{
535 for (;a; a = a->a_next) {
536 char const *name = a->a_name;
537 char const *value = a->a_value;
538 sdp_printf(p, "a=%s%s%s" CRLF"\015\012", name, value ? ":" : "", value ? value : "");
539 }
540}
541
542static void
543print_attributes_without_mode(sdp_printer_t *p, sdp_attribute_t const *a)
544{
545 for (;a; a = a->a_next) {
546 char const *name = a->a_name;
547 char const *value = a->a_value;
548
549 if (su_casematch(name, "inactive") ||
550 su_casematch(name, "sendonly") ||
551 su_casematch(name, "recvonly") ||
552 su_casematch(name, "sendrecv"))
553 continue;
554
555 sdp_printf(p, "a=%s%s%s" CRLF"\015\012", name, value ? ":" : "", value ? value : "");
556 }
557}
558
559static void print_charset(sdp_printer_t *p, sdp_text_t *charset)
560{
561 sdp_printf(p, "a=charset%s%s" CRLF"\015\012", charset ? ":" : "", charset ? charset : "");
562}
563
564static void print_media(sdp_printer_t *p,
565 sdp_session_t const *sdp,
566 sdp_media_t const *m)
567{
568 char const *media, *proto;
569 sdp_rtpmap_t *rm;
570
571 sdp_mode_t session_mode = sdp_sendrecv;
572
573 if (!p->pr_mode_manual)
574 session_mode = sdp_attribute_mode(sdp->sdp_attributes, sdp_sendrecv);
575
576 for (;m ; m = m->m_next) {
577 switch (m->m_type) {
578 case sdp_media_audio: media = "audio"; break;
579 case sdp_media_video: media = "video"; break;
580 case sdp_media_application: media = "application"; break;
581 case sdp_media_data: media = "data"; break;
582 case sdp_media_control: media = "control"; break;
583 case sdp_media_message: media = "message"; break;
584 case sdp_media_image : media = "image"; break;
585 default: media = m->m_type_name;
586 }
587
588 switch (m->m_proto) {
589 case sdp_proto_tcp: proto = "tcp"; break;
590 case sdp_proto_udp: proto = "udp"; break;
591 case sdp_proto_rtp: proto = "RTP/AVP"; break;
592 case sdp_proto_srtp: proto = "RTP/SAVP"; break;
593 //case sdp_proto_extended_srtp: proto = "RTP/SAVPF"; break;
594 case sdp_proto_udptl: proto = "udptl"; break;
595 case sdp_proto_msrp: proto = "TCP/MSRP"; break;
596 case sdp_proto_msrps: proto = "TCP/TLS/MSRP"; break;
597 case sdp_proto_tls: proto = "tls"; break;
598 default: proto = m->m_proto_name; break;
599 }
600
601 if (m->m_number_of_ports <= 1)
602 sdp_printf(p, "m=%s %u %s", media, m->m_port, proto);
603 else
604 sdp_printf(p, "m=%s %u/%u %s",
605 media, m->m_port, m->m_number_of_ports, proto);
606
607 if (m->m_rtpmaps) {
608 for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
609 if (rm->rm_any)
610 sdp_printf(p, " *");
611 else
612 sdp_printf(p, " %u", (unsigned)rm->rm_pt);
613 }
614 }
615 else if (m->m_format) {
616 sdp_list_t *l = m->m_format;
617 for (; l; l = l->l_next)
618 sdp_printf(p, " %s", l->l_text);
619 }
620 else {
621 /* SDP syntax requires at least one format. */
622 /* defaults to "19", or "t38" for image */
623 if (m->m_type == sdp_media_image) sdp_printf(p, " t38");
624 else sdp_printf(p, " 19");
625 }
626
627
628 sdp_printf(p, CRLF"\015\012");
629
630 if (m->m_information)
631 print_information(p, m->m_information);
632 if (m->m_connections)
633#ifdef nomore
634 if (m->m_connections != sdp->sdp_connection)
635#endif
636 print_connection_list(p, m->m_connections);
637 if (m->m_bandwidths)
638 print_bandwidths(p, m->m_bandwidths);
639 if (m->m_key)
640 print_key(p, m->m_key);
641
642 for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
643 if (rm->rm_encoding && *rm->rm_encoding && (!rm->rm_predef || p->pr_all_rtpmaps)) {
644 sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF"\015\012",
645 rm->rm_pt, rm->rm_encoding, rm->rm_rate,
646 rm->rm_params ? "/" : "",
647 rm->rm_params ? rm->rm_params : "");
648 }
649 if (rm->rm_fmtp) {
650 sdp_printf(p, "a=fmtp:%u %s" CRLF"\015\012",
651 rm->rm_pt, rm->rm_fmtp);
652 }
653 }
654
655 if (!p->pr_mode_manual && !m->m_rejected &&
656 (m->m_mode != (unsigned int)session_mode || p->pr_mode_always)) {
657 switch (m->m_mode) {
658 case sdp_inactive:
659 sdp_printf(p, "a=inactive" CRLF"\015\012");
660 break;
661 case sdp_sendonly:
662 sdp_printf(p, "a=sendonly" CRLF"\015\012");
663 break;
664 case sdp_recvonly:
665 sdp_printf(p, "a=recvonly" CRLF"\015\012");
666 break;
667 case sdp_sendrecv:
668 sdp_printf(p, "a=sendrecv" CRLF"\015\012");
669 break;
670 default:
671 break;
672 }
673 }
674
675 if (p->pr_mode_manual)
676 print_attributes(p, m->m_attributes);
677 else
678 print_attributes_without_mode(p, m->m_attributes);
679 }
680}
681
682static void print_text_list(sdp_printer_t *p,
683 const char *fmt, sdp_list_t const *l)
684{
685 for (;l; l = l->l_next) {
686 sdp_printf(p, fmt, l->l_text);
687 }
688}
689
690static void printing_error(sdp_printer_t *p, const char *fmt, ...)
691{
692 va_list ap;
693
694 if (p->pr_ok) {
695 va_start(ap, fmt)__builtin_va_start(ap, fmt);
696 vsnprintf(p->pr_buffer, p->pr_bsiz, fmt, ap);
697 va_end(ap)__builtin_va_end(ap);
698 }
699
700 p->pr_ok = 0;
701}
702
703static void sdp_printf(sdp_printer_t *p, const char *fmt, ...)
704{
705 va_list ap;
706
707 while (p->pr_ok) {
708 int n;
709
710 va_start(ap, fmt)__builtin_va_start(ap, fmt);
711 n = vsnprintf(p->pr_buffer + p->pr_used, p->pr_bsiz - p->pr_used, fmt, ap);
712 va_end(ap)__builtin_va_end(ap);
713
714 if (n > -1 && (size_t)n < p->pr_bsiz - p->pr_used) {
715 p->pr_used += n;
716 break;
717 }
718 else {
719 if (p->pr_owns_buffer) {
720 p->pr_buffer = su_realloc(p->pr_home, p->pr_buffer, 2 * p->pr_bsiz);
721 if (p->pr_buffer) {
722 p->pr_bsiz = 2 * p->pr_bsiz;
723 continue;
724 }
725 p->pr_owns_buffer = 0;
726 }
727 else if (p->pr_may_realloc) {
728 char *buffer;
729 size_t size;
730 if (p->pr_bsiz < SDP_BLOCK(512))
731 size = SDP_BLOCK(512);
732 else
733 size = 2 * p->pr_bsiz;
734 buffer = su_alloc(p->pr_home, size);
735 if (buffer) {
736 p->pr_owns_buffer = 1;
737 p->pr_buffer = memcpy(buffer, p->pr_buffer, p->pr_bsiz);
738 p->pr_bsiz = size;
739 continue;
740 }
741 }
742 p->pr_ok = 0;
743 p->pr_buffer = "Memory exhausted";
744 }
745 }
746}