1 /*****************************************************************************
2  * psi.h: ISO/IEC 13818-1 Program Specific Information (sections)
3  *****************************************************************************
4  * Copyright (C) 2009-2010 VideoLAN
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
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  *  - ISO/IEC 13818-1:2007(E) (MPEG-2 Systems)
31  */
32 
33 #ifndef __BITSTREAM_MPEG_SECTIONS_H__
34 #define __BITSTREAM_MPEG_SECTIONS_H__
35 
36 #include <bitstream/common.h>
37 #include <bitstream/mpeg/ts.h>
38 
39 #ifdef __cplusplus
40 extern "C"
41 {
42 #endif
43 
44 /*****************************************************************************
45  * p_psi_crc_table
46  *****************************************************************************
47  * This table is used to compute a PSI CRC byte per byte instead of bit per
48  * bit. It's been generated by 'gen_crc' in the 'misc' directory:
49  *
50  *   uint32_t table[256];
51  *   uint32_t i, j, k;
52  *
53  *   for(i = 0; i < 256; i++)
54  *   {
55  *     k = 0;
56  *     for (j = (i << 24) | 0x800000; j != 0x80000000; j <<= 1)
57  *       k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
58  *     table[i] = k;
59  *   }
60  *
61  * A CRC is computed like this:
62  *
63  *   initialization
64  *   --------------
65  *   uint32_t i_crc = 0xffffffff;
66  *
67  *   for each data byte do
68  *   ---------------------
69  *   i_crc = (i_crc << 8) ^ s_crc32_table[(i_crc >> 24) ^ (data_byte)];
70  *****************************************************************************/
71 static const uint32_t p_psi_crc_table[256] = {
72     0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
73     0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
74     0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
75     0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
76     0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
77     0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
78     0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
79     0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
80     0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
81     0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
82     0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
83     0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
84     0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
85     0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
86     0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
87     0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
88     0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
89     0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
90     0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
91     0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
92     0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
93     0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
94     0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
95     0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
96     0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
97     0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
98     0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
99     0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
100     0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
101     0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
102     0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
103     0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
104     0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
105     0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
106     0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
107     0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
108     0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
109     0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
110     0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
111     0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
112     0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
113     0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
114     0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
115     0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
116     0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
117     0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
118     0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
119     0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
120     0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
121     0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
122     0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
123     0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
124     0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
125     0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
126     0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
127     0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
128     0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
129     0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
130     0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
131     0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
132     0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
133     0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
134     0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
135     0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
136 };
137 
138 /*****************************************************************************
139  * PSI section
140  *****************************************************************************/
141 #define PSI_HEADER_SIZE         3
142 #define PSI_HEADER_SIZE_SYNTAX1 8
143 #define PSI_CRC_SIZE            4
144 #define PSI_MAX_SIZE            1021
145 #define PSI_PRIVATE_MAX_SIZE    4093
146 
147 #define PSI_DECLARE(p_table)            \
148     uint8_t p_table[PSI_MAX_SIZE + PSI_HEADER_SIZE]
149 #define PSI_PRIVATE_DECLARE(p_table)    \
150     uint8_t p_table[PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE]
151 
psi_allocate(void)152 static inline uint8_t *psi_allocate(void)
153 {
154     return (uint8_t *)malloc((PSI_MAX_SIZE + PSI_HEADER_SIZE) * sizeof(uint8_t));
155 }
156 
psi_private_allocate(void)157 static inline uint8_t *psi_private_allocate(void)
158 {
159     return (uint8_t *)malloc((PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE) * sizeof(uint8_t));
160 }
161 
psi_set_tableid(uint8_t * p_section,uint8_t i_table_id)162 static inline void psi_set_tableid(uint8_t *p_section, uint8_t i_table_id)
163 {
164     p_section[0] = i_table_id;
165 }
166 
psi_get_tableid(const uint8_t * p_section)167 static inline uint8_t psi_get_tableid(const uint8_t *p_section)
168 {
169     return p_section[0];
170 }
171 
psi_set_syntax(uint8_t * p_section)172 static inline void psi_set_syntax(uint8_t *p_section)
173 {
174     p_section[1] |= 0x80;
175 }
176 
psi_get_syntax(const uint8_t * p_section)177 static inline bool psi_get_syntax(const uint8_t *p_section)
178 {
179     return !!(p_section[1] & 0x80);
180 }
181 
psi_init(uint8_t * p_section,bool b_syntax)182 static inline void psi_init(uint8_t *p_section, bool b_syntax)
183 {
184     /* set reserved bits */
185     p_section[1] = 0x70;
186     if (b_syntax) {
187         psi_set_syntax(p_section);
188         p_section[5] = 0xc0;
189     }
190 }
191 
psi_set_length(uint8_t * p_section,uint16_t i_length)192 static inline void psi_set_length(uint8_t *p_section, uint16_t i_length)
193 {
194     p_section[1] &= ~0xf;
195     p_section[1] |= (i_length >> 8) & 0xf;
196     p_section[2] = i_length & 0xff;
197 }
198 
psi_get_length(const uint8_t * p_section)199 static inline uint16_t psi_get_length(const uint8_t *p_section)
200 {
201     return ((p_section[1] & 0xf) << 8) | p_section[2];
202 }
203 
psi_set_tableidext(uint8_t * p_section,uint16_t i_table_id_ext)204 static inline void psi_set_tableidext(uint8_t *p_section,
205                                       uint16_t i_table_id_ext)
206 {
207     p_section[3] = i_table_id_ext >> 8;
208     p_section[4] = i_table_id_ext & 0xff;
209 }
210 
psi_get_tableidext(const uint8_t * p_section)211 static inline uint16_t psi_get_tableidext(const uint8_t *p_section)
212 {
213     return (p_section[3] << 8) | p_section[4];
214 }
215 
psi_set_version(uint8_t * p_section,uint8_t i_version)216 static inline void psi_set_version(uint8_t *p_section, uint8_t i_version)
217 {
218     p_section[5] = (i_version << 1) | 0xc0;
219 }
220 
psi_get_version(const uint8_t * p_section)221 static inline uint8_t psi_get_version(const uint8_t *p_section)
222 {
223     return (p_section[5] & 0x3e) >> 1;
224 }
225 
psi_set_current(uint8_t * p_section)226 static inline void psi_set_current(uint8_t *p_section)
227 {
228     p_section[5] |= 0x1;
229 }
230 
psi_get_current(const uint8_t * p_section)231 static inline bool psi_get_current(const uint8_t *p_section)
232 {
233     return !!(p_section[5] & 0x1);
234 }
235 
psi_set_section(uint8_t * p_section,uint8_t i_section)236 static inline void psi_set_section(uint8_t *p_section, uint8_t i_section)
237 {
238     p_section[6] = i_section;
239 }
240 
psi_get_section(const uint8_t * p_section)241 static inline uint8_t psi_get_section(const uint8_t *p_section)
242 {
243     return p_section[6];
244 }
245 
psi_set_lastsection(uint8_t * p_section,uint8_t i_last_section)246 static inline void psi_set_lastsection(uint8_t *p_section,
247                                        uint8_t i_last_section)
248 {
249     p_section[7] = i_last_section;
250 }
251 
psi_get_lastsection(const uint8_t * p_section)252 static inline uint8_t psi_get_lastsection(const uint8_t *p_section)
253 {
254     return p_section[7];
255 }
256 
257 /*****************************************************************************
258  * PSI validation
259  *****************************************************************************/
psi_set_crc(uint8_t * p_section)260 static inline void psi_set_crc(uint8_t *p_section)
261 {
262     uint32_t i_crc = 0xffffffff;
263     uint16_t i_end = (((p_section[1] & 0xf) << 8) | p_section[2])
264                       + PSI_HEADER_SIZE - PSI_CRC_SIZE;
265     uint16_t i;
266 
267     for (i = 0; i < i_end; i++)
268         i_crc = (i_crc << 8) ^ p_psi_crc_table[(i_crc >> 24) ^ (p_section[i])];
269 
270     p_section[i_end] = i_crc >> 24;
271     p_section[i_end + 1] = (i_crc >> 16) & 0xff;
272     p_section[i_end + 2] = (i_crc >> 8) & 0xff;
273     p_section[i_end + 3] = i_crc & 0xff;
274 }
275 
psi_check_crc(const uint8_t * p_section)276 static inline bool psi_check_crc(const uint8_t *p_section)
277 {
278     uint32_t i_crc = 0xffffffff;
279     uint16_t i_end = (((p_section[1] & 0xf) << 8) | p_section[2])
280                       + PSI_HEADER_SIZE - PSI_CRC_SIZE;
281     uint16_t i;
282 
283     for (i = 0; i < i_end; i++)
284         i_crc = (i_crc << 8) ^ p_psi_crc_table[(i_crc >> 24) ^ (p_section[i])];
285 
286     return p_section[i_end] == (i_crc >> 24)
287             && p_section[i_end + 1] == ((i_crc >> 16) & 0xff)
288             && p_section[i_end + 2] == ((i_crc >> 8) & 0xff)
289             && p_section[i_end + 3] == (i_crc & 0xff);
290 }
291 
psi_validate(const uint8_t * p_section)292 static inline bool psi_validate(const uint8_t *p_section)
293 {
294     if (psi_get_syntax(p_section)
295          && (psi_get_length(p_section) < PSI_HEADER_SIZE_SYNTAX1
296                                             - PSI_HEADER_SIZE + PSI_CRC_SIZE))
297         return false;
298 
299     /* only do the CRC check when it is strictly necessary */
300 
301     return true;
302 }
303 
psi_compare(const uint8_t * p_section1,const uint8_t * p_section2)304 static inline bool psi_compare(const uint8_t *p_section1,
305                                const uint8_t *p_section2)
306 {
307     return psi_get_version(p_section1) == psi_get_version(p_section2)
308         && psi_get_length(p_section1) == psi_get_length(p_section2)
309         && !memcmp(p_section1, p_section2,
310                    psi_get_length(p_section1) + PSI_HEADER_SIZE);
311 }
312 
313 /*****************************************************************************
314  * PSI section gathering
315  *****************************************************************************/
psi_assemble_init(uint8_t ** pp_psi_buffer,uint16_t * pi_psi_buffer_used)316 static inline void psi_assemble_init(uint8_t **pp_psi_buffer,
317                                      uint16_t *pi_psi_buffer_used)
318 {
319     *pp_psi_buffer = NULL;
320     *pi_psi_buffer_used = 0;
321 }
322 
psi_assemble_reset(uint8_t ** pp_psi_buffer,uint16_t * pi_psi_buffer_used)323 static inline void psi_assemble_reset(uint8_t **pp_psi_buffer,
324                                       uint16_t *pi_psi_buffer_used)
325 {
326     free(*pp_psi_buffer);
327     psi_assemble_init(pp_psi_buffer, pi_psi_buffer_used);
328 }
329 
psi_assemble_empty(uint8_t ** pp_psi_buffer,uint16_t * pi_psi_buffer_used)330 static inline bool psi_assemble_empty(uint8_t **pp_psi_buffer,
331                                       uint16_t *pi_psi_buffer_used)
332 {
333     (void) pi_psi_buffer_used;
334 
335     return *pp_psi_buffer == NULL;
336 }
337 
psi_assemble_payload(uint8_t ** pp_psi_buffer,uint16_t * pi_psi_buffer_used,const uint8_t ** pp_payload,uint8_t * pi_length)338 static inline uint8_t *psi_assemble_payload(uint8_t **pp_psi_buffer,
339                                             uint16_t *pi_psi_buffer_used,
340                                             const uint8_t **pp_payload,
341                                             uint8_t *pi_length)
342 {
343     uint16_t i_remaining_size = PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE
344                                  - *pi_psi_buffer_used;
345     uint16_t i_copy_size = *pi_length < i_remaining_size ? *pi_length :
346                            i_remaining_size;
347     uint8_t *p_section = NULL;
348 
349     if (*pp_psi_buffer == NULL) {
350         if (**pp_payload == 0xff) {
351             /* padding table to the end of buffer */
352             *pi_length = 0;
353             return NULL;
354         }
355         *pp_psi_buffer = psi_private_allocate();
356     }
357 
358     memcpy(*pp_psi_buffer + *pi_psi_buffer_used, *pp_payload, i_copy_size);
359     *pi_psi_buffer_used += i_copy_size;
360 
361     if (*pi_psi_buffer_used >= PSI_HEADER_SIZE) {
362         uint16_t i_section_size = psi_get_length(*pp_psi_buffer)
363                                    + PSI_HEADER_SIZE;
364 
365         if (i_section_size > PSI_PRIVATE_MAX_SIZE) {
366             /* invalid section */
367             psi_assemble_reset(pp_psi_buffer, pi_psi_buffer_used);
368             *pi_length = 0;
369             return NULL;
370         }
371         if (i_section_size <= *pi_psi_buffer_used) {
372             p_section = *pp_psi_buffer;
373             i_copy_size -= (*pi_psi_buffer_used - i_section_size);
374             *pp_psi_buffer = NULL;
375             *pi_psi_buffer_used = 0;
376         }
377     }
378 
379     *pp_payload += i_copy_size;
380     *pi_length -= i_copy_size;
381     return p_section;
382 }
383 
384 /*****************************************************************************
385  * PSI section splitting
386  *****************************************************************************/
psi_split_end(uint8_t * p_ts,uint8_t * pi_ts_offset)387 static inline void psi_split_end(uint8_t *p_ts, uint8_t *pi_ts_offset)
388 {
389     if (*pi_ts_offset != TS_SIZE) {
390         memset(p_ts + *pi_ts_offset, 0xff, TS_SIZE - *pi_ts_offset);
391         *pi_ts_offset = TS_SIZE;
392     }
393 }
394 
psi_split_section(uint8_t * p_ts,uint8_t * pi_ts_offset,const uint8_t * p_section,uint16_t * pi_section_offset)395 static inline void psi_split_section(uint8_t *p_ts, uint8_t *pi_ts_offset,
396                                      const uint8_t *p_section,
397                                      uint16_t *pi_section_offset)
398 {
399     uint16_t i_section_length = psi_get_length(p_section) + PSI_HEADER_SIZE
400                                  - *pi_section_offset;
401     uint8_t i_ts_length, i_copy;
402 
403     if (!*pi_ts_offset) {
404         ts_init(p_ts);
405         ts_set_payload(p_ts);
406         *pi_ts_offset = ts_payload(p_ts) - p_ts;
407     }
408 
409     if (!*pi_section_offset) {
410         if (TS_SIZE - *pi_ts_offset < 2) {
411             psi_split_end(p_ts, pi_ts_offset);
412             return;
413         }
414         if (!ts_get_unitstart(p_ts)) {
415             uint8_t *p_payload = ts_payload(p_ts);
416             uint8_t i_payload_length = *pi_ts_offset - (p_payload - p_ts);
417             if (i_payload_length)
418                 memmove(p_payload + 1, p_payload, i_payload_length);
419             (*pi_ts_offset)++;
420             *p_payload = i_payload_length; /* pointer_field */
421             ts_set_unitstart(p_ts);
422         }
423     }
424     i_ts_length = TS_SIZE - *pi_ts_offset;
425 
426     i_copy = i_ts_length < i_section_length ?
427              i_ts_length : i_section_length;
428     memcpy(p_ts + *pi_ts_offset, p_section + *pi_section_offset, i_copy);
429     *pi_ts_offset += i_copy;
430     *pi_section_offset += i_copy;
431 }
432 
433 /*****************************************************************************
434  * PSI table gathering
435  *****************************************************************************/
436 #define PSI_TABLE_MAX_SECTIONS         256
437 
438 #define PSI_TABLE_DECLARE(pp_table)    \
439     uint8_t *pp_table[PSI_TABLE_MAX_SECTIONS]
440 
psi_table_allocate(void)441 static inline uint8_t **psi_table_allocate(void)
442 {
443     return (uint8_t **)malloc(PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
444 }
445 
psi_table_init(uint8_t ** pp_sections)446 static inline void psi_table_init(uint8_t **pp_sections)
447 {
448     int i;
449     for (i = 0; i < PSI_TABLE_MAX_SECTIONS; i++)
450         pp_sections[i] = NULL;
451 }
452 
psi_table_free(uint8_t ** pp_sections)453 static inline void psi_table_free(uint8_t **pp_sections)
454 {
455     int i;
456     for (i = 0; i < PSI_TABLE_MAX_SECTIONS; i++)
457         free(pp_sections[i]);
458 }
459 
psi_table_validate(uint8_t * const * pp_sections)460 static inline bool psi_table_validate(uint8_t * const *pp_sections)
461 {
462     return pp_sections[0] != NULL;
463 }
464 
psi_table_copy(uint8_t ** pp_dest,uint8_t ** pp_src)465 static inline void psi_table_copy(uint8_t **pp_dest, uint8_t **pp_src)
466 {
467     memcpy(pp_dest, pp_src, PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
468 }
469 
470 #define psi_table_get_tableid(pp_sections)      \
471     psi_get_tableid(pp_sections[0])
472 #define psi_table_get_version(pp_sections)      \
473     psi_get_version(pp_sections[0])
474 #define psi_table_get_current(pp_sections)      \
475     psi_get_current(pp_sections[0])
476 #define psi_table_get_lastsection(pp_sections)  \
477     psi_get_lastsection(pp_sections[0])
478 #define psi_table_get_tableidext(pp_sections)   \
479     psi_get_tableidext(pp_sections[0])
480 
psi_table_section(uint8_t ** pp_sections,uint8_t * p_section)481 static inline bool psi_table_section(uint8_t **pp_sections, uint8_t *p_section)
482 {
483     uint8_t i_section = psi_get_section( p_section );
484     uint8_t i_last_section = psi_get_lastsection( p_section );
485     uint8_t i_version = psi_get_version( p_section );
486     uint16_t i_tableidext = psi_get_tableidext( p_section );
487     int i;
488 
489     free(pp_sections[i_section]);
490     pp_sections[i_section] = p_section;
491 
492     for (i = 0; i <= i_last_section; i++) {
493         uint8_t *p = pp_sections[i];
494         if (p == NULL)
495             return false;
496         if (psi_get_lastsection(p) != i_last_section
497              || psi_get_version(p) != i_version
498              || psi_get_tableidext(p) != i_tableidext)
499             return false;
500     }
501 
502     /* free spurious, invalid sections */
503     for (; i < PSI_TABLE_MAX_SECTIONS; i++) {
504         free(pp_sections[i]);
505         pp_sections[i] = NULL;
506     }
507 
508     /* a new, full table is available */
509     return true;
510 }
511 
psi_table_get_section(uint8_t ** pp_sections,uint8_t n)512 static inline uint8_t *psi_table_get_section(uint8_t **pp_sections, uint8_t n)
513 {
514     return pp_sections[n];
515 }
516 
psi_table_compare(uint8_t ** pp_sections1,uint8_t ** pp_sections2)517 static inline bool psi_table_compare(uint8_t **pp_sections1,
518                                      uint8_t **pp_sections2)
519 {
520     uint8_t i_last_section = psi_table_get_lastsection(pp_sections1);
521     uint8_t i;
522 
523     if (i_last_section != psi_table_get_lastsection(pp_sections2))
524         return false;
525 
526     for (i = 0; i <= i_last_section; i++) {
527         const uint8_t *p_section1 = psi_table_get_section(pp_sections1, i);
528         const uint8_t *p_section2 = psi_table_get_section(pp_sections2, i);
529         if (!psi_compare(p_section1, p_section2))
530             return false;
531     }
532 
533     return true;
534 }
535 
536 #ifdef __cplusplus
537 }
538 #endif
539 
540 #endif
541