1 /*****************************************************************************
2  * desc_4a.h: ETSI EN 300 468 Descriptor 0x4a: Linkage descriptor
3  *****************************************************************************
4  * Copyright (C) 2009-2010 VideoLAN
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
7  *          Georgi Chorbadzhiyski <georgi@unixsol.org>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject
15  * to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  *****************************************************************************/
28 
29 /*
30  * Normative references:
31  *  - ETSI EN 300 468 V1.11.1 (2010-04) (SI in DVB systems)
32  */
33 
34 #ifndef __BITSTREAM_DVB_DESC_4A_H__
35 #define __BITSTREAM_DVB_DESC_4A_H__
36 
37 #include <bitstream/common.h>
38 #include <bitstream/mpeg/psi/descriptors.h>
39 
40 #ifdef __cplusplus
41 extern "C"
42 {
43 #endif
44 
45 /*****************************************************************************
46  * Descriptor 0x4a: Linkage descriptor
47  *****************************************************************************/
48 #define DESC4A_HEADER_SIZE      (DESC_HEADER_SIZE + 7)
49 
50 #define DESC4A_LINKAGE_MOBILE       0x08
51 #define DESC4A_LINKAGE_EVENT        0x0d
52 #define DESC4A_LINKAGE_EXT_EVENT    0x0e
53 
desc4a_init(uint8_t * p_desc)54 static inline void desc4a_init(uint8_t *p_desc)
55 {
56     desc_set_tag(p_desc, 0x4a);
57     desc_set_length(p_desc, DESC4A_HEADER_SIZE - DESC_HEADER_SIZE);
58 }
59 
desc4a_get_tsid(const uint8_t * p_desc)60 static inline uint16_t desc4a_get_tsid(const uint8_t *p_desc)
61 {
62     return (p_desc[2] << 8) | p_desc[3];
63 }
64 
desc4a_set_tsid(uint8_t * p_desc,uint16_t i_tsid)65 static inline void desc4a_set_tsid(uint8_t *p_desc, uint16_t i_tsid)
66 {
67     p_desc[2] = (i_tsid >> 8) & 0xff;
68     p_desc[3] =  i_tsid       & 0xff;
69 }
70 
desc4a_get_onid(const uint8_t * p_desc)71 static inline uint16_t desc4a_get_onid(const uint8_t *p_desc)
72 {
73     return (p_desc[4] << 8) | p_desc[5];
74 }
75 
desc4a_set_onid(uint8_t * p_desc,uint16_t i_onid)76 static inline void desc4a_set_onid(uint8_t *p_desc, uint16_t i_onid)
77 {
78     p_desc[4] = (i_onid >> 8) & 0xff;
79     p_desc[5] =  i_onid       & 0xff;
80 }
81 
desc4a_get_sid(const uint8_t * p_desc)82 static inline uint16_t desc4a_get_sid(const uint8_t *p_desc)
83 {
84     return (p_desc[6] << 8) | p_desc[7];
85 }
86 
desc4a_set_sid(uint8_t * p_desc,uint16_t i_sid)87 static inline void desc4a_set_sid(uint8_t *p_desc, uint16_t i_sid)
88 {
89     p_desc[6] = (i_sid >> 8) & 0xff;
90     p_desc[7] =  i_sid       & 0xff;
91 }
92 
desc4a_get_linkage(const uint8_t * p_desc)93 static inline uint8_t desc4a_get_linkage(const uint8_t *p_desc)
94 {
95     return p_desc[8];
96 }
97 
desc4a_set_linkage(uint8_t * p_desc,uint8_t i_linkage)98 static inline void desc4a_set_linkage(uint8_t *p_desc, uint8_t i_linkage)
99 {
100     p_desc[8] = i_linkage;
101 }
102 
desc4a_get_linkage_txt(uint8_t i_linkage)103 static inline const char *desc4a_get_linkage_txt(uint8_t i_linkage)
104 {
105     return i_linkage == 0x00 ? "reserved" :
106            i_linkage == 0x01 ? "information service" :
107            i_linkage == 0x02 ? "EPG service" :
108            i_linkage == 0x03 ? "CA replacement service" :
109            i_linkage == 0x04 ? "TS containing complete Network/Bouquet SI" :
110            i_linkage == 0x05 ? "service replacement service" :
111            i_linkage == 0x06 ? "data broadcast service" :
112            i_linkage == 0x07 ? "RCS Map" :
113            i_linkage == 0x08 ? "mobile hand-over" :
114            i_linkage == 0x09 ? "System Software Update Service (TS 102 006 [11])" :
115            i_linkage == 0x0a ? "TS containing SSU BAT or NIT (TS 102 006 [11])" :
116            i_linkage == 0x0b ? "IP/MAC Notification Service (EN 301 192 [4])" :
117            i_linkage == 0x0c ? "TS containing INT BAT or NIT (EN 301 192 [4])" :
118            i_linkage == 0x0d ? "event linkage" :
119            i_linkage == 0x0e ? "extended event linkage" :
120            i_linkage >= 0x0f && i_linkage <= 0x7f ? "reserved" :
121            i_linkage >= 0x80 && i_linkage <= 0xfe ? "user defined" : "reserved";
122 }
123 
124 /* MOBILE HANDOVER linkage == 0x08 (DESC4A_LINKAGE_MOBILE) */
125 
desc4a_get_mobile_handover_type(const uint8_t * p_desc)126 static inline uint8_t desc4a_get_mobile_handover_type(const uint8_t *p_desc)
127 {
128     return (p_desc[9] & 0xf0) >> 4;
129 }
130 
desc4a_set_mobile_handover_type(uint8_t * p_desc,uint8_t i_handover_type)131 static inline void desc4a_set_mobile_handover_type(uint8_t *p_desc, uint8_t i_handover_type)
132 {
133     p_desc[9] = ((i_handover_type & 0x0f) << 4) | 0x0e | (p_desc[9] & 0x01);
134 }
135 
desc4a_get_mobile_origin_type(const uint8_t * p_desc)136 static inline bool desc4a_get_mobile_origin_type(const uint8_t *p_desc)
137 {
138     return (p_desc[9] & 0x01) == 0x01;
139 }
140 
desc4a_set_mobile_origin_type(uint8_t * p_desc,bool b_origin_type)141 static inline void desc4a_set_mobile_origin_type(uint8_t *p_desc, bool b_origin_type)
142 {
143     p_desc[9] = b_origin_type ? (p_desc[9] | 0x01) : (p_desc[9] &~ 0x01);
144 }
145 
desc4a_have_mobile_nid(const uint8_t * p_desc)146 static inline bool desc4a_have_mobile_nid(const uint8_t *p_desc)
147 {
148     uint8_t i_handover_type = desc4a_get_mobile_handover_type(p_desc);
149     return (i_handover_type >= 0x01 && i_handover_type <= 0x03);
150 }
151 
desc4a_get_mobile_nid(const uint8_t * p_desc)152 static inline uint16_t desc4a_get_mobile_nid(const uint8_t *p_desc)
153 {
154     if (desc4a_have_mobile_nid(p_desc))
155         return (p_desc[10] << 8) | p_desc[11];
156     else
157         return 0;
158 }
159 
desc4a_set_mobile_nid(uint8_t * p_desc,uint16_t i_nid)160 static inline void desc4a_set_mobile_nid(uint8_t *p_desc, uint16_t i_nid)
161 {
162     if (desc4a_have_mobile_nid(p_desc)) {
163         p_desc[10] = (i_nid >> 8) & 0xff;
164         p_desc[11] =  i_nid       & 0xff;
165     }
166 }
167 
desc4a_get_mobile_initial_sid(const uint8_t * p_desc)168 static inline uint16_t desc4a_get_mobile_initial_sid(const uint8_t *p_desc)
169 {
170     if (!desc4a_get_mobile_origin_type(p_desc)) {
171         uint8_t ofs = 10;
172         if (desc4a_have_mobile_nid(p_desc))
173             ofs += 2;
174         return (p_desc[ofs + 0] << 8) | p_desc[ofs + 1];
175     }
176     return 0;
177 }
178 
desc4a_set_mobile_initial_sid(uint8_t * p_desc,uint16_t i_initial_sid)179 static inline void desc4a_set_mobile_initial_sid(uint8_t *p_desc, uint16_t i_initial_sid)
180 {
181     if (!desc4a_get_mobile_origin_type(p_desc)) {
182         uint8_t ofs = 10;
183         if (desc4a_have_mobile_nid(p_desc))
184             ofs += 2;
185         p_desc[ofs + 0] = (i_initial_sid >> 8) & 0xff;
186         p_desc[ofs + 1] =  i_initial_sid       & 0xff;
187     }
188 }
189 
desc4a_get_mobile_handover_length(const uint8_t * p_desc)190 static inline uint8_t desc4a_get_mobile_handover_length(const uint8_t *p_desc)
191 {
192     uint8_t i_length = 0;
193     if (desc4a_get_linkage(p_desc) == DESC4A_LINKAGE_MOBILE)
194     {
195         i_length += 1;
196         if (desc4a_have_mobile_nid(p_desc))
197             i_length += 2;
198         if (!desc4a_get_mobile_origin_type(p_desc))
199             i_length += 2;
200     }
201     return i_length;
202 }
203 
204 /* EVENT LINKAGE == 0x0d (DESC4A_LINKAGE_EVENT) */
205 
desc4a_get_event_target_event_id(const uint8_t * p_desc)206 static inline uint16_t desc4a_get_event_target_event_id(const uint8_t *p_desc)
207 {
208     return (p_desc[9] << 8) | p_desc[10];
209 }
210 
desc4a_set_event_target_event_id(uint8_t * p_desc,uint16_t i_target_event_id)211 static inline void desc4a_set_event_target_event_id(uint8_t *p_desc, uint16_t i_target_event_id)
212 {
213     p_desc[ 9] = (i_target_event_id >> 8) & 0xff;
214     p_desc[10] =  i_target_event_id       & 0xff;
215 }
216 
desc4a_get_event_target_listed(const uint8_t * p_desc)217 static inline bool desc4a_get_event_target_listed(const uint8_t *p_desc)
218 {
219     return (p_desc[11] & 0x80) == 0x80;
220 }
221 
desc4a_set_event_target_listed(uint8_t * p_desc,bool b_target_listed)222 static inline void desc4a_set_event_target_listed(uint8_t *p_desc, bool b_target_listed)
223 {
224     p_desc[11] |= 0x3f;
225     p_desc[11]  = b_target_listed ? (p_desc[11] | 0x80) : (p_desc[11] &~ 0x80);
226 }
227 
desc4a_get_event_simulcast(const uint8_t * p_desc)228 static inline bool desc4a_get_event_simulcast(const uint8_t *p_desc)
229 {
230     return (p_desc[11] & 0x40) == 0x40;
231 }
232 
desc4a_set_event_simulcast(uint8_t * p_desc,bool b_event_simulcast)233 static inline void desc4a_set_event_simulcast(uint8_t *p_desc, bool b_event_simulcast)
234 {
235     p_desc[11] |= 0x3f;
236     p_desc[11]  = b_event_simulcast ? (p_desc[11] | 0x40) : (p_desc[11] &~ 0x40);
237 }
238 
desc4a_get_event_length(const uint8_t * p_desc)239 static inline uint8_t desc4a_get_event_length(const uint8_t *p_desc)
240 {
241     if (desc4a_get_linkage(p_desc) == DESC4A_LINKAGE_EVENT)
242         return 3;
243     return 0;
244 }
245 
246 /* EXTENDED EVENT LINKAGE == 0x0e (DESC4A_LINKAGE_EXT_EVENT) */
247 
desc4an_get_ext_event_target_event_id(const uint8_t * p_desc_n)248 static inline uint16_t desc4an_get_ext_event_target_event_id(const uint8_t *p_desc_n)
249 {
250     return (p_desc_n[0] << 8) | p_desc_n[1];
251 }
252 
desc4an_set_ext_event_target_event_id(uint8_t * p_desc_n,uint16_t i_target_event_id)253 static inline void desc4an_set_ext_event_target_event_id(uint8_t *p_desc_n, uint16_t i_target_event_id)
254 {
255     p_desc_n[0] = (i_target_event_id >> 8) & 0xff;
256     p_desc_n[1] =  i_target_event_id       & 0xff;
257 }
258 
desc4an_get_ext_event_target_listed(const uint8_t * p_desc_n)259 static inline bool desc4an_get_ext_event_target_listed(const uint8_t *p_desc_n)
260 {
261     return (p_desc_n[2] & 0x80) == 0x80;
262 }
263 
desc4an_set_ext_event_target_listed(uint8_t * p_desc_n,bool b_target_listed)264 static inline void desc4an_set_ext_event_target_listed(uint8_t *p_desc_n, bool b_target_listed)
265 {
266     p_desc_n[2]  = b_target_listed ? (p_desc_n[2] | 0x80) : (p_desc_n[2] &~ 0x80);
267 }
268 
desc4an_get_ext_event_simulcast(const uint8_t * p_desc_n)269 static inline bool desc4an_get_ext_event_simulcast(const uint8_t *p_desc_n)
270 {
271     return (p_desc_n[2] & 0x40) == 0x40;
272 }
273 
desc4an_set_ext_event_simulcast(uint8_t * p_desc_n,bool b_event_simulcast)274 static inline void desc4an_set_ext_event_simulcast(uint8_t *p_desc_n, bool b_event_simulcast)
275 {
276     p_desc_n[2] = b_event_simulcast ? (p_desc_n[2] | 0x40) : (p_desc_n[2] &~ 0x40);
277 }
278 
desc4an_get_ext_event_link_type(const uint8_t * p_desc_n)279 static inline uint8_t desc4an_get_ext_event_link_type(const uint8_t *p_desc_n)
280 {
281     return (p_desc_n[2] & 0x30) >> 4;
282 }
283 
desc4an_set_ext_event_link_type(uint8_t * p_desc_n,uint8_t i_link_type)284 static inline void desc4an_set_ext_event_link_type(uint8_t *p_desc_n, uint8_t i_link_type)
285 {
286     p_desc_n[2] = (p_desc_n[2] & 0xcf) | ((i_link_type & 0x03) << 4);
287 }
288 
desc4a_get_ext_event_link_type_txt(uint8_t i_link_type)289 static inline const char *desc4a_get_ext_event_link_type_txt(uint8_t i_link_type)
290 {
291     return i_link_type == 0 ? "SD" :
292            i_link_type == 1 ? "HD" :
293            i_link_type == 2 ? "3D" : "reserved";
294 }
295 
desc4an_get_ext_event_target_id_type(const uint8_t * p_desc_n)296 static inline uint8_t desc4an_get_ext_event_target_id_type(const uint8_t *p_desc_n)
297 {
298     return (p_desc_n[2] & 0x0c) >> 2;
299 }
300 
desc4an_set_ext_event_target_id_type(uint8_t * p_desc_n,uint8_t i_target_id_type)301 static inline void desc4an_set_ext_event_target_id_type(uint8_t *p_desc_n, uint8_t i_target_id_type)
302 {
303     p_desc_n[2] = (p_desc_n[2] & 0xf3) | ((i_target_id_type & 0x03) << 2);
304 }
305 
desc4a_get_ext_event_target_id_type_txt(uint8_t i_target_id_type)306 static inline const char *desc4a_get_ext_event_target_id_type_txt(uint8_t i_target_id_type)
307 {
308     return i_target_id_type == 0 ? "use tsid" :
309            i_target_id_type == 1 ? "use target_tsid" :
310            i_target_id_type == 2 ? "match any tsid" : "use user_defined_id";
311 }
312 
desc4an_get_ext_event_onid_id_flag(const uint8_t * p_desc_n)313 static inline bool desc4an_get_ext_event_onid_id_flag(const uint8_t *p_desc_n)
314 {
315     return (p_desc_n[2] & 0x02) == 0x02;
316 }
317 
desc4an_set_ext_event_onid_id_flag(uint8_t * p_desc_n,bool b_event_onid_id_flag)318 static inline void desc4an_set_ext_event_onid_id_flag(uint8_t *p_desc_n, bool b_event_onid_id_flag)
319 {
320     p_desc_n[2] = b_event_onid_id_flag ? (p_desc_n[2] | 0x02) : (p_desc_n[2] &~ 0x02);
321 }
322 
desc4an_get_ext_event_service_id_flag(const uint8_t * p_desc_n)323 static inline bool desc4an_get_ext_event_service_id_flag(const uint8_t *p_desc_n)
324 {
325     return (p_desc_n[2] & 0x01) == 0x01;
326 }
327 
desc4an_set_ext_event_service_id_flag(uint8_t * p_desc_n,bool b_event_service_id_flag)328 static inline void desc4an_set_ext_event_service_id_flag(uint8_t *p_desc_n, bool b_event_service_id_flag)
329 {
330     p_desc_n[2] = b_event_service_id_flag ? (p_desc_n[2] | 0x01) : (p_desc_n[2] &~ 0x01);
331 }
332 
333 
desc4an_ext_event_have_user_defined_id(const uint8_t * p_desc_n)334 static inline bool desc4an_ext_event_have_user_defined_id(const uint8_t *p_desc_n)
335 {
336     return desc4an_get_ext_event_target_id_type(p_desc_n) == 3;
337 }
338 
desc4an_ext_event_have_target_tsid(const uint8_t * p_desc_n)339 static inline bool desc4an_ext_event_have_target_tsid(const uint8_t *p_desc_n)
340 {
341     return desc4an_get_ext_event_target_id_type(p_desc_n) == 1;
342 }
343 
344 
desc4an_get_ext_event_user_defined_id(const uint8_t * p_desc_n)345 static inline uint16_t desc4an_get_ext_event_user_defined_id(const uint8_t *p_desc_n)
346 {
347     if (desc4an_ext_event_have_user_defined_id(p_desc_n))
348         return (p_desc_n[3] << 8) | p_desc_n[4];
349     else
350         return 0;
351 }
352 
desc4an_set_ext_event_user_defined_id(uint8_t * p_desc_n,uint16_t i_user_defined_id)353 static inline void desc4an_set_ext_event_user_defined_id(uint8_t *p_desc_n, uint16_t i_user_defined_id)
354 {
355     if (desc4an_ext_event_have_user_defined_id(p_desc_n)) {
356         p_desc_n[3] = (i_user_defined_id >> 8) & 0xff;
357         p_desc_n[4] =  i_user_defined_id       & 0xff;
358     }
359 }
360 
desc4an_get_ext_event_target_tsid(const uint8_t * p_desc_n)361 static inline uint16_t desc4an_get_ext_event_target_tsid(const uint8_t *p_desc_n)
362 {
363     if (desc4an_ext_event_have_target_tsid(p_desc_n))
364         return (p_desc_n[3] << 8) | p_desc_n[4];
365     else
366         return 0;
367 }
368 
desc4an_set_ext_event_target_tsid(uint8_t * p_desc_n,uint16_t i_target_tsid)369 static inline void desc4an_set_ext_event_target_tsid(uint8_t *p_desc_n, uint16_t i_target_tsid)
370 {
371     if (desc4an_ext_event_have_target_tsid(p_desc_n)) {
372         p_desc_n[3] = (i_target_tsid >> 8) & 0xff;
373         p_desc_n[4] =  i_target_tsid       & 0xff;
374     }
375 }
376 
desc4an_get_ext_event_target_onid(const uint8_t * p_desc_n)377 static inline uint16_t desc4an_get_ext_event_target_onid(const uint8_t *p_desc_n)
378 {
379     if (desc4an_ext_event_have_user_defined_id(p_desc_n))
380         return 0;
381     uint8_t ofs = desc4an_ext_event_have_target_tsid(p_desc_n) ? 5 : 3;
382     if (desc4an_get_ext_event_onid_id_flag(p_desc_n))
383         return (p_desc_n[ofs + 0] << 8) | p_desc_n[ofs + 1];
384     else
385         return 0;
386 }
387 
desc4an_set_ext_event_target_onid(uint8_t * p_desc_n,uint16_t i_target_onid)388 static inline void desc4an_set_ext_event_target_onid(uint8_t *p_desc_n, uint16_t i_target_onid)
389 {
390     if (desc4an_ext_event_have_user_defined_id(p_desc_n))
391         return;
392     uint8_t ofs = desc4an_ext_event_have_target_tsid(p_desc_n) ? 5 : 3;
393     if (desc4an_get_ext_event_onid_id_flag(p_desc_n)) {
394         p_desc_n[ofs + 0] = (i_target_onid >> 8) & 0xff;
395         p_desc_n[ofs + 1] =  i_target_onid       & 0xff;
396     }
397 }
398 
desc4an_get_ext_event_service_id(const uint8_t * p_desc_n)399 static inline uint16_t desc4an_get_ext_event_service_id(const uint8_t *p_desc_n)
400 {
401     if (desc4an_ext_event_have_user_defined_id(p_desc_n))
402         return 0;
403     uint8_t ofs = desc4an_ext_event_have_target_tsid(p_desc_n) ? 5 : 3;
404     if (desc4an_get_ext_event_onid_id_flag(p_desc_n))
405         ofs += 2;
406     if (desc4an_get_ext_event_service_id_flag(p_desc_n))
407         return (p_desc_n[ofs + 0] << 8) | p_desc_n[ofs + 1];
408     else
409         return 0;
410 }
411 
desc4an_set_ext_event_service_id(uint8_t * p_desc_n,uint16_t i_service_id)412 static inline void desc4an_set_ext_event_service_id(uint8_t *p_desc_n, uint16_t i_service_id)
413 {
414     if (desc4an_ext_event_have_user_defined_id(p_desc_n))
415         return;
416     uint8_t ofs = desc4an_ext_event_have_target_tsid(p_desc_n) ? 5 : 3;
417     if (desc4an_get_ext_event_onid_id_flag(p_desc_n))
418         ofs += 2;
419     if (desc4an_get_ext_event_service_id_flag(p_desc_n)) {
420         p_desc_n[ofs + 0] = (i_service_id >> 8) & 0xff;
421         p_desc_n[ofs + 1] =  i_service_id       & 0xff;
422     }
423 }
424 
desc4an_get_ext_event_length(const uint8_t * p_desc_n)425 static inline uint8_t desc4an_get_ext_event_length(const uint8_t *p_desc_n)
426 {
427     uint8_t i_len = 3;
428     if (desc4an_ext_event_have_user_defined_id(p_desc_n))
429         return i_len + 2;
430     if (desc4an_ext_event_have_target_tsid(p_desc_n))
431         i_len += 2;
432     if (desc4an_get_ext_event_onid_id_flag(p_desc_n))
433         i_len += 2;
434     if (desc4an_get_ext_event_service_id_flag(p_desc_n))
435         i_len += 2;
436     return i_len;
437 }
438 
desc4a_get_ext_event(const uint8_t * p_desc,uint8_t n)439 static inline uint8_t *desc4a_get_ext_event(const uint8_t *p_desc, uint8_t n)
440 {
441     uint8_t *p     = (uint8_t *)p_desc + DESC4A_HEADER_SIZE;
442     uint8_t *p_end = (uint8_t *)p_desc + DESC_HEADER_SIZE + desc_get_length(p_desc);
443 
444     if (p == p_end)
445         return NULL;
446 
447     if (n == 0)
448         return p;
449 
450     while (p < p_end && n) {
451         p += desc4an_get_ext_event_length(p);
452         if (--n == 0 && p < p_end )
453             return p;
454     }
455 
456     return NULL;
457 }
458 
459 /* Generic desc4a continued... */
460 
desc4a_set_length(uint8_t * p_desc)461 static inline void desc4a_set_length(uint8_t *p_desc)
462 {
463     uint8_t i_length = DESC4A_HEADER_SIZE - DESC_HEADER_SIZE;
464     i_length += desc4a_get_mobile_handover_length(p_desc);
465     i_length += desc4a_get_event_length(p_desc);
466     desc_set_length(p_desc, i_length);
467 }
468 
desc4a_validate(const uint8_t * p_desc)469 static inline bool desc4a_validate(const uint8_t *p_desc)
470 {
471     uint8_t i_length = DESC4A_HEADER_SIZE - DESC_HEADER_SIZE;
472     i_length += desc4a_get_mobile_handover_length(p_desc);
473     i_length += desc4a_get_event_length(p_desc);
474     return desc_get_length(p_desc) >= i_length;
475 }
476 
desc4a_print(const uint8_t * p_desc,f_print pf_print,void * opaque,print_type_t i_print_type)477 static inline void desc4a_print(const uint8_t *p_desc, f_print pf_print,
478                                 void *opaque, print_type_t i_print_type)
479 {
480     uint8_t j;
481     uint8_t *p_desc_n;
482     uint8_t i_linkage = desc4a_get_linkage(p_desc);
483 
484     switch (i_print_type) {
485     case PRINT_XML:
486         pf_print(opaque,
487              "<LINKAGE_DESC tsid=\"%hu\" onid=\"%hu\" sid=\"%hu\" linkage=\"0x%02x\" linkage_txt=\"%s\">",
488              desc4a_get_tsid(p_desc), desc4a_get_onid(p_desc),
489              desc4a_get_sid(p_desc), i_linkage,
490              desc4a_get_linkage_txt(i_linkage)
491              );
492         if (i_linkage == DESC4A_LINKAGE_MOBILE) {
493             pf_print(opaque,
494                  "<MOBILE_HANDOVER_INFO handover_type=\"%u\" origin_type=\"%u\" nid=\"%u\" initial_sid=\"%u\"/>",
495                  desc4a_get_mobile_handover_type(p_desc),
496                  desc4a_get_mobile_origin_type(p_desc),
497                  desc4a_get_mobile_nid(p_desc),
498                  desc4a_get_mobile_initial_sid(p_desc)
499                  );
500         }
501         if (i_linkage == DESC4A_LINKAGE_EVENT) { // event linkage
502             pf_print(opaque,
503                  "<EVENT_LINKAGE target_event_id=\"%u\" target_listed=\"%u\" event_simulcast=\"%u\"/>",
504                  desc4a_get_event_target_event_id(p_desc),
505                  desc4a_get_event_target_listed(p_desc),
506                  desc4a_get_event_simulcast(p_desc)
507                  );
508         }
509         if (i_linkage == DESC4A_LINKAGE_EXT_EVENT) {
510             j = 0;
511             while ((p_desc_n = desc4a_get_ext_event(p_desc, j++)) != NULL) {
512                 pf_print(opaque,
513                      "<EXTENDED_EVENT_LINKAGE target_event_id=\"%u\" target_listed=\"%u\" event_simulcast=\"%u\""
514                      " link_type=\"%u\" link_type_txt=\"%s\""
515                      " target_id_type=\"%u\" target_id_type_txt=\"%s\""
516                      " onid_id_flag=\"%u\" service_id_flag=\"%u\""
517                      " user_defined_id=\"%u\" target_tsid=\"%u\" target_onid=\"%u\" target_service_id=\"%u\"/>",
518                      desc4an_get_ext_event_target_event_id(p_desc_n),
519                      desc4an_get_ext_event_target_listed(p_desc_n),
520                      desc4an_get_ext_event_simulcast(p_desc_n),
521                      desc4an_get_ext_event_link_type(p_desc_n),
522                      desc4a_get_ext_event_link_type_txt(desc4an_get_ext_event_link_type(p_desc_n)),
523                      desc4an_get_ext_event_target_id_type(p_desc_n),
524                      desc4a_get_ext_event_target_id_type_txt(desc4an_get_ext_event_target_id_type(p_desc_n)),
525                      desc4an_get_ext_event_onid_id_flag(p_desc_n),
526                      desc4an_get_ext_event_service_id_flag(p_desc_n),
527                      desc4an_get_ext_event_user_defined_id(p_desc_n),
528                      desc4an_get_ext_event_target_tsid(p_desc_n),
529                      desc4an_get_ext_event_target_onid(p_desc_n),
530                      desc4an_get_ext_event_service_id(p_desc_n)
531                 );
532             }
533         }
534         pf_print(opaque,
535              "</LINKAGE_DESC>");
536         break;
537     default:
538         pf_print(opaque,
539              "    - desc 4a linkage tsid=%hu onid=%hu sid=%hu linkage=0x%02x linkage_txt=\"%s\"",
540              desc4a_get_tsid(p_desc), desc4a_get_onid(p_desc),
541              desc4a_get_sid(p_desc), i_linkage,
542              desc4a_get_linkage_txt(i_linkage)
543              );
544         if (i_linkage == DESC4A_LINKAGE_MOBILE) {
545             pf_print(opaque,
546                  "        - mobile_handover handover_type=%u origin_type=%u nid=%u initial_sid=%u",
547                  desc4a_get_mobile_handover_type(p_desc),
548                  desc4a_get_mobile_origin_type(p_desc),
549                  desc4a_get_mobile_nid(p_desc),
550                  desc4a_get_mobile_initial_sid(p_desc)
551                  );
552         }
553         if (i_linkage == DESC4A_LINKAGE_EVENT) {
554             pf_print(opaque,
555                  "        - event_linkage target_event_id=%u target_listed=%u event_simulcast=%u",
556                  desc4a_get_event_target_event_id(p_desc),
557                  desc4a_get_event_target_listed(p_desc),
558                  desc4a_get_event_simulcast(p_desc)
559                  );
560         }
561         if (i_linkage == DESC4A_LINKAGE_EXT_EVENT) {
562             j = 0;
563             while ((p_desc_n = desc4a_get_ext_event(p_desc, j++)) != NULL) {
564                 pf_print(opaque,
565                      "        - extended_event_linkage target_event_id=%u target_listed=%u event_simulcast=%u"
566                      " link_type=%u link_type_txt=\"%s\""
567                      " target_id_type=%u target_id_type_txt=\"%s\""
568                      " onid_id_flag=%u service_id_flag=%u"
569                      " user_defined_id=%u target_tsid=%u target_onid=%u target_service_id=%u",
570                      desc4an_get_ext_event_target_event_id(p_desc_n),
571                      desc4an_get_ext_event_target_listed(p_desc_n),
572                      desc4an_get_ext_event_simulcast(p_desc_n),
573                      desc4an_get_ext_event_link_type(p_desc_n),
574                      desc4a_get_ext_event_link_type_txt(desc4an_get_ext_event_link_type(p_desc_n)),
575                      desc4an_get_ext_event_target_id_type(p_desc_n),
576                      desc4a_get_ext_event_target_id_type_txt(desc4an_get_ext_event_target_id_type(p_desc_n)),
577                      desc4an_get_ext_event_onid_id_flag(p_desc_n),
578                      desc4an_get_ext_event_service_id_flag(p_desc_n),
579                      desc4an_get_ext_event_user_defined_id(p_desc_n),
580                      desc4an_get_ext_event_target_tsid(p_desc_n),
581                      desc4an_get_ext_event_target_onid(p_desc_n),
582                      desc4an_get_ext_event_service_id(p_desc_n)
583                 );
584             }
585         }
586     }
587 }
588 
589 #ifdef __cplusplus
590 }
591 #endif
592 
593 #endif
594