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