1 /*****************************************************************************
2  * desc_57.h: ETSI EN 300 468 Descriptor 0x57: Telephone descriptor
3  *****************************************************************************
4  * Copyright (C) 2011 Unix Solutions Ltd.
5  *
6  * Authors: Georgi Chorbadzhiyski <georgi@unixsol.org>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject
14  * to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *****************************************************************************/
27 
28 /*
29  * Normative references:
30  *  - ETSI EN 300 468 V1.11.1 (2010-04) (SI in DVB systems)
31  */
32 
33 #ifndef __BITSTREAM_DVB_DESC_57_H__
34 #define __BITSTREAM_DVB_DESC_57_H__
35 
36 #include <bitstream/common.h>
37 #include <bitstream/mpeg/psi/descriptors.h>
38 
39 #ifdef __cplusplus
40 extern "C"
41 {
42 #endif
43 
44 /*****************************************************************************
45  * Descriptor 0x57: Telephone descriptor
46  *****************************************************************************/
47 #define DESC57_HEADER_SIZE      (DESC_HEADER_SIZE + 3)
48 
desc57_init(uint8_t * p_desc)49 static inline void desc57_init(uint8_t *p_desc)
50 {
51     desc_set_tag(p_desc, 0x57);
52     desc_set_length(p_desc, DESC57_HEADER_SIZE - DESC_HEADER_SIZE);
53     p_desc[2] = 0xc0;
54     p_desc[3] = 0x80;
55     p_desc[4] = 0x80;
56 }
57 
desc57_get_foreign_availability(const uint8_t * p_desc)58 static inline bool desc57_get_foreign_availability(const uint8_t *p_desc)
59 {
60     return (p_desc[2] & 0x20) == 0x20;
61 }
62 
63 
desc57_set_foreign_availability(uint8_t * p_desc,bool b_foreign_availability)64 static inline void desc57_set_foreign_availability(uint8_t *p_desc, bool b_foreign_availability)
65 {
66     p_desc[2] = b_foreign_availability ? (p_desc[2] | 0x20) : (p_desc[2] &~ 0x20);
67 }
68 
desc57_get_connection_type(const uint8_t * p_desc)69 static inline uint8_t desc57_get_connection_type(const uint8_t *p_desc)
70 {
71     return p_desc[2] & 0x1f;
72 }
73 
desc57_set_connection_type(uint8_t * p_desc,uint8_t i_connection_type)74 static inline void desc57_set_connection_type(uint8_t *p_desc, uint8_t i_connection_type)
75 {
76     p_desc[2] = (p_desc[2] & 0xe0) | (i_connection_type & 0x1f);
77 }
78 
79 
desc57_get_country_prefix_length(const uint8_t * p_desc)80 static inline uint8_t desc57_get_country_prefix_length(const uint8_t *p_desc)
81 {
82     return (p_desc[3] & 0x60) >> 5; // x11xxxxx
83 }
84 
desc57_get_country_prefix(const uint8_t * p_desc,uint8_t * i_length)85 static inline const char *desc57_get_country_prefix(const uint8_t *p_desc, uint8_t *i_length)
86 {
87     *i_length = desc57_get_country_prefix_length(p_desc);
88     if (*i_length == 0) return NULL;
89     return (const char *)p_desc + DESC57_HEADER_SIZE;
90 }
91 
desc57_set_country_prefix(uint8_t * p_desc,const char * p_country_prefix,uint8_t i_length)92 static inline void desc57_set_country_prefix(uint8_t *p_desc, const char *p_country_prefix, uint8_t i_length)
93 {
94     p_desc[3] = (p_desc[3] &~ 0x60) | ((i_length & 0x03) << 5); // x11xxxxx
95     memcpy(p_desc + DESC57_HEADER_SIZE, p_country_prefix, i_length);
96 }
97 
98 
desc57_get_international_area_code_length(const uint8_t * p_desc)99 static inline uint8_t desc57_get_international_area_code_length(const uint8_t *p_desc)
100 {
101     return (p_desc[3] & 0x1c) >> 2; // xxx111xx
102 }
103 
desc57_get_international_area_code(const uint8_t * p_desc,uint8_t * i_length)104 static inline const char *desc57_get_international_area_code(const uint8_t *p_desc, uint8_t *i_length)
105 {
106     *i_length = desc57_get_international_area_code_length(p_desc);
107     if (*i_length == 0) return NULL;
108     return (const char *)p_desc + DESC57_HEADER_SIZE
109             + desc57_get_country_prefix_length(p_desc);
110 }
111 
desc57_set_international_area_code(uint8_t * p_desc,const char * p_international_area_code,uint8_t i_length)112 static inline void desc57_set_international_area_code(uint8_t *p_desc, const char *p_international_area_code, uint8_t i_length)
113 {
114     p_desc[3] = (p_desc[3] &~ 0x1c) | ((i_length & 0x07) << 2); // xxx111xx
115     memcpy(p_desc + DESC57_HEADER_SIZE
116             + desc57_get_country_prefix_length(p_desc),
117            p_international_area_code, i_length);
118 }
119 
120 
desc57_get_operator_code_length(const uint8_t * p_desc)121 static inline uint8_t desc57_get_operator_code_length(const uint8_t *p_desc)
122 {
123     return (p_desc[3] & 0x03); // xxxxxx11
124 }
125 
desc57_get_operator_code(const uint8_t * p_desc,uint8_t * i_length)126 static inline const char *desc57_get_operator_code(const uint8_t *p_desc, uint8_t *i_length)
127 {
128     *i_length = desc57_get_operator_code_length(p_desc);
129     if (*i_length == 0) return NULL;
130     return (const char *)p_desc + DESC57_HEADER_SIZE
131             + desc57_get_country_prefix_length(p_desc)
132             + desc57_get_international_area_code_length(p_desc);
133 }
134 
desc57_set_operator_code(uint8_t * p_desc,const char * p_operator_code,uint8_t i_length)135 static inline void desc57_set_operator_code(uint8_t *p_desc, const char *p_operator_code, uint8_t i_length)
136 {
137     p_desc[3] = (p_desc[3] &~ 0x03) | (i_length & 0x03); // xxxxxx11
138     memcpy(p_desc + DESC57_HEADER_SIZE
139             + desc57_get_country_prefix_length(p_desc)
140             + desc57_get_international_area_code_length(p_desc),
141            p_operator_code, i_length);
142 }
143 
144 
desc57_get_national_area_code_length(const uint8_t * p_desc)145 static inline uint8_t desc57_get_national_area_code_length(const uint8_t *p_desc)
146 {
147     return (p_desc[4] & 0x70) >> 4; // x111xxxx
148 }
149 
desc57_get_national_area_code(const uint8_t * p_desc,uint8_t * i_length)150 static inline const char *desc57_get_national_area_code(const uint8_t *p_desc, uint8_t *i_length)
151 {
152     *i_length = desc57_get_national_area_code_length(p_desc);
153     if (*i_length == 0) return NULL;
154     return (const char *)p_desc + DESC57_HEADER_SIZE
155             + desc57_get_country_prefix_length(p_desc)
156             + desc57_get_international_area_code_length(p_desc)
157             + desc57_get_operator_code_length(p_desc);
158 }
159 
desc57_set_national_area_code(uint8_t * p_desc,const char * p_national_area_code,uint8_t i_length)160 static inline void desc57_set_national_area_code(uint8_t *p_desc, const char *p_national_area_code, uint8_t i_length)
161 {
162     p_desc[4] = (p_desc[4] &~ 0x70) | ((i_length & 0x07) << 4); // x111xxxx
163     memcpy(p_desc + DESC57_HEADER_SIZE
164             + desc57_get_country_prefix_length(p_desc)
165             + desc57_get_international_area_code_length(p_desc)
166             + desc57_get_operator_code_length(p_desc),
167            p_national_area_code, i_length);
168 }
169 
170 
desc57_get_core_number_length(const uint8_t * p_desc)171 static inline uint8_t desc57_get_core_number_length(const uint8_t *p_desc)
172 {
173     return (p_desc[4] & 0x0f); // xxxx1111
174 }
175 
desc57_get_core_number(const uint8_t * p_desc,uint8_t * i_length)176 static inline const char *desc57_get_core_number(const uint8_t *p_desc, uint8_t *i_length)
177 {
178     *i_length = desc57_get_core_number_length(p_desc);
179     if (*i_length == 0) return NULL;
180     return (const char *)p_desc + DESC57_HEADER_SIZE
181             + desc57_get_country_prefix_length(p_desc)
182             + desc57_get_international_area_code_length(p_desc)
183             + desc57_get_operator_code_length(p_desc)
184             + desc57_get_national_area_code_length(p_desc);
185 }
186 
desc57_set_core_number(uint8_t * p_desc,const char * p_core_number,uint8_t i_length)187 static inline void desc57_set_core_number(uint8_t *p_desc, const char *p_core_number, uint8_t i_length)
188 {
189     p_desc[4] = (p_desc[4] &~ 0x0f) | (i_length & 0x0f);
190     memcpy(p_desc + DESC57_HEADER_SIZE
191             + desc57_get_country_prefix_length(p_desc)
192             + desc57_get_international_area_code_length(p_desc)
193             + desc57_get_operator_code_length(p_desc)
194             + desc57_get_national_area_code_length(p_desc),
195            p_core_number, i_length);
196 }
197 
198 
desc57_get_phone_length(const uint8_t * p_desc)199 static inline uint8_t desc57_get_phone_length(const uint8_t *p_desc)
200 {
201     return desc_get_length(p_desc) - (DESC57_HEADER_SIZE - DESC_HEADER_SIZE);
202 }
203 
desc57_get_phone(const uint8_t * p_desc,uint8_t * i_length)204 static inline const char *desc57_get_phone(const uint8_t *p_desc, uint8_t *i_length)
205 {
206     *i_length = desc57_get_phone_length(p_desc);
207     if (*i_length == 0) return NULL;
208     return (const char *)p_desc + DESC57_HEADER_SIZE;
209 }
210 
211 
desc57_set_length(uint8_t * p_desc)212 static inline void desc57_set_length(uint8_t *p_desc)
213 {
214     desc_set_length(p_desc, DESC57_HEADER_SIZE - DESC_HEADER_SIZE +
215                             + desc57_get_country_prefix_length(p_desc)
216                             + desc57_get_international_area_code_length(p_desc)
217                             + desc57_get_operator_code_length(p_desc)
218                             + desc57_get_national_area_code_length(p_desc)
219                             + desc57_get_core_number_length(p_desc));
220 }
221 
desc57_validate(const uint8_t * p_desc)222 static inline bool desc57_validate(const uint8_t *p_desc)
223 {
224     return (p_desc + DESC57_HEADER_SIZE
225                    + desc57_get_country_prefix_length(p_desc)
226                    + desc57_get_international_area_code_length(p_desc)
227                    + desc57_get_operator_code_length(p_desc)
228                    + desc57_get_national_area_code_length(p_desc)
229                    + desc57_get_core_number_length(p_desc))
230            == (p_desc + DESC_HEADER_SIZE + desc_get_length(p_desc));
231 }
232 
desc57_print(uint8_t * p_desc,f_print pf_print,void * opaque,print_type_t i_print_type)233 static inline void desc57_print(uint8_t *p_desc, f_print pf_print,
234                                 void *opaque, print_type_t i_print_type)
235 {
236     uint8_t i_country_prefix_len, i_international_area_code_len, i_operator_code_len;
237     uint8_t i_national_area_code_len, i_core_number_len, i_phone;
238     const char *empty = "";
239     const char *p_country_prefix     = desc57_get_country_prefix(p_desc, &i_country_prefix_len);
240     const char *p_international_area_code = desc57_get_international_area_code(p_desc, &i_international_area_code_len);
241     const char *p_operator_code      = desc57_get_operator_code(p_desc, &i_operator_code_len);
242     const char *p_national_area_code = desc57_get_national_area_code(p_desc, &i_national_area_code_len);
243     const char *p_core_number        = desc57_get_core_number(p_desc, &i_core_number_len);
244     const char *p_phone              = desc57_get_phone(p_desc, &i_phone);
245 
246     if (!p_country_prefix) p_country_prefix = empty;
247     if (!p_international_area_code) p_international_area_code = empty;
248     if (!p_operator_code) p_operator_code = empty;
249     if (!p_national_area_code) p_national_area_code = empty;
250     if (!p_core_number) p_core_number = empty;
251     if (!p_phone) p_phone = empty;
252 
253     switch (i_print_type) {
254     case PRINT_XML:
255         pf_print(opaque,
256                  "<TELEPHONE_DESC foreign_availability=\"%u\" connection_type=\"%u\""
257                  " country_prefix=\"%.*s\" international_area_code=\"%.*s\""
258                  " operator_code=\"%.*s\" national_area_code=\"%.*s\""
259                  " core_number=\"%.*s\" full_telephone=\"%.*s\"/>",
260                  desc57_get_foreign_availability(p_desc),
261                  desc57_get_connection_type(p_desc),
262                  i_country_prefix_len, p_country_prefix,
263                  i_international_area_code_len, p_international_area_code,
264                  i_operator_code_len, p_operator_code,
265                  i_national_area_code_len, p_national_area_code,
266                  i_core_number_len, p_core_number,
267                  i_phone, p_phone
268                 );
269         break;
270     default:
271         pf_print(opaque,
272                  "    - desc 57 telephone foreign_availability=%u connection_type=%u"
273                  " country_prefix=%.*s international_area_code=%.*s"
274                  " operator_code=%.*s national_area_code=%.*s"
275                  " core_number=%.*s phone=%.*s",
276                  desc57_get_foreign_availability(p_desc),
277                  desc57_get_connection_type(p_desc),
278                  i_country_prefix_len, p_country_prefix,
279                  i_international_area_code_len, p_international_area_code,
280                  i_operator_code_len, p_operator_code,
281                  i_national_area_code_len, p_national_area_code,
282                  i_core_number_len, p_core_number,
283                  i_phone, p_phone
284                 );
285     }
286 }
287 
288 #ifdef __cplusplus
289 }
290 #endif
291 
292 #endif
293