1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
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 | |
50 | |
51 | |
52 | #define SDP_BLOCK(512) (512) |
53 | |
54 | #define CRLF"\015\012" "\015\012" |
55 | |
56 | typedef unsigned longlonglong long ull; |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | struct 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 | |
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 | |
82 | static 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 | |
90 | static void print_session(sdp_printer_t *p, sdp_session_t const *session); |
91 | static void printing_error(sdp_printer_t *p, const char *fmt, ...); |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
129 | sdp_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 | |
171 | |
172 | |
173 | |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | char 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 | |
192 | |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | char 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 | |
210 | |
211 | |
212 | |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | isize_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 | |
227 | |
228 | |
229 | |
230 | |
231 | |
232 | |
233 | void 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 | |
243 | static void print_version(sdp_printer_t *p, sdp_version_t const *v); |
244 | static void print_origin(sdp_printer_t *p, sdp_origin_t const *o); |
245 | static void print_subject(sdp_printer_t *p, sdp_text_t *s); |
246 | static void print_information(sdp_printer_t *p, sdp_text_t *i); |
247 | static void print_uri(sdp_printer_t *p, sdp_text_t *u); |
248 | static void print_emails(sdp_printer_t *p, sdp_list_t const *e); |
249 | static void print_phones(sdp_printer_t *p, sdp_list_t const *ph); |
250 | static void print_connection(sdp_printer_t *p, sdp_connection_t const *c); |
251 | static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c); |
252 | static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c); |
253 | static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b); |
254 | static void print_time(sdp_printer_t *p, sdp_time_t const *t); |
255 | static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r); |
256 | static void print_zone(sdp_printer_t *p, sdp_zone_t const *z); |
257 | static void print_typed_time(sdp_printer_t *p, unsigned long t); |
258 | static void print_key(sdp_printer_t *p, sdp_key_t const *k); |
259 | static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a); |
260 | static void print_charset(sdp_printer_t *p, sdp_text_t *charset); |
261 | static void print_media(sdp_printer_t *p, sdp_session_t const *, |
262 | sdp_media_t const *m); |
263 | |
264 | static void print_text_list(sdp_printer_t*, |
265 | const char *, sdp_list_t const *l); |
266 | |
267 | static void sdp_printf(sdp_printer_t *p, const char *fmt, ...); |
268 | |
269 | static 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 | |
|
| |
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 | |
309 | static 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 | |
314 | static 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 | |
332 | static void print_subject(sdp_printer_t *p, sdp_text_t *subject) |
333 | { |
334 | sdp_printf(p, "s=%s" CRLF"\015\012", subject); |
335 | } |
336 | |
337 | static void print_information(sdp_printer_t *p, sdp_text_t *information) |
338 | { |
339 | sdp_printf(p, "i=%s" CRLF"\015\012", information); |
340 | } |
341 | |
342 | static void print_uri(sdp_printer_t *p, sdp_text_t *uri) |
343 | { |
344 | sdp_printf(p, "u=%s" CRLF"\015\012", uri); |
345 | } |
346 | |
347 | static 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 | |
352 | static 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 | |
357 | static 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 | |
363 | static 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 | |
371 | static 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 | |
425 | static 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 | |
440 | static 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 | |
446 | static 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 | |
461 | static 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 | |
481 | static 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); |
491 | } |
492 | else { |
493 | t /= 60; |
494 | |
495 | if (t % 24) { |
496 | sdp_printf(p, "%luh", t); |
497 | } |
498 | else { |
499 | t /= 24; |
500 | |
501 | sdp_printf(p, "%lud", t); |
502 | } |
503 | } |
504 | } |
505 | } |
506 | |
507 | static 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 | |
533 | static 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 | |
542 | static void |
543 | print_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 | |
559 | static 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 | |
564 | static 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 | |
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 | |
622 | |
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 | |
682 | static 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 | |
690 | static 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 | |
703 | static 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 | } |