dvb_print_si.c 30.7 KB
Newer Older
1 2 3 4 5 6 7
/*****************************************************************************
 * dvb_print_si.c: Prints tables from a TS file
 *****************************************************************************
 * Copyright (C) 2010 VideoLAN
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 27 28 29 30
 *****************************************************************************/

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
31
#include <inttypes.h>
32 33 34
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
35
#include <iconv.h>
36 37 38 39

#include <bitstream/mpeg/ts.h>
#include <bitstream/mpeg/psi.h>
#include <bitstream/dvb/si.h>
40
#include <bitstream/dvb/si_print.h>
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
#include <bitstream/mpeg/psi_print.h>

/*****************************************************************************
 * Local declarations
 *****************************************************************************/
#define MAX_PIDS    8192
#define READ_ONCE   7

typedef struct ts_pid_t {
    int i_psi_refcount;
    int8_t i_last_cc;

    /* biTStream PSI section gathering */
    uint8_t *p_psi_buffer;
    uint16_t i_psi_buffer_used;
} ts_pid_t;

typedef struct sid_t {
    uint16_t i_sid, i_pmt_pid;
    uint8_t *p_current_pmt;
} sid_t;

ts_pid_t p_pids[MAX_PIDS];
static sid_t **pp_sids = NULL;
static int i_nb_sids = 0;

static PSI_TABLE_DECLARE(pp_current_pat_sections);
static PSI_TABLE_DECLARE(pp_next_pat_sections);
69 70
static PSI_TABLE_DECLARE(pp_current_cat_sections);
static PSI_TABLE_DECLARE(pp_next_cat_sections);
71 72
static PSI_TABLE_DECLARE(pp_current_tsdt_sections);
static PSI_TABLE_DECLARE(pp_next_tsdt_sections);
73 74
static PSI_TABLE_DECLARE(pp_current_nit_sections);
static PSI_TABLE_DECLARE(pp_next_nit_sections);
75 76
static PSI_TABLE_DECLARE(pp_current_bat_sections);
static PSI_TABLE_DECLARE(pp_next_bat_sections);
77 78 79
static PSI_TABLE_DECLARE(pp_current_sdt_sections);
static PSI_TABLE_DECLARE(pp_next_sdt_sections);

80 81 82
static const char *psz_native_encoding = "UTF-8";
static const char *psz_current_encoding = "";
static iconv_t iconv_handle = (iconv_t)-1;
83
static print_type_t i_print_type = PRINT_TEXT;
84

85
/*****************************************************************************
86
 * print_wrapper
87
 *****************************************************************************/
88
static void print_wrapper(void *_unused, const char *psz_format, ...)
89 90 91 92 93 94 95 96 97
{
    char psz_fmt[strlen(psz_format) + 2];
    va_list args;
    va_start(args, psz_format);
    strcpy(psz_fmt, psz_format);
    strcat(psz_fmt, "\n");
    vprintf(psz_fmt, args);
}

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
/*****************************************************************************
 * iconv_wrapper
 *****************************************************************************/
static char *iconv_append_null(const char *p_string, size_t i_length)
{
    char *psz_string = malloc(i_length + 1);
    memcpy(psz_string, p_string, i_length);
    psz_string[i_length] = '\0';
    return psz_string;
}

static char *iconv_wrapper(void *_unused, const char *psz_encoding,
                           char *p_string, size_t i_length)
{
    char *psz_string, *p;
    size_t i_out_length;

    if (!strcmp(psz_encoding, psz_native_encoding))
        return iconv_append_null(p_string, i_length);

    if (iconv_handle != (iconv_t)-1 &&
        strcmp(psz_encoding, psz_current_encoding)) {
        iconv_close(iconv_handle);
        iconv_handle = (iconv_t)-1;
    }

    if (iconv_handle == (iconv_t)-1)
        iconv_handle = iconv_open(psz_native_encoding, psz_encoding);
    if (iconv_handle == (iconv_t)-1) {
127
        fprintf(stderr, "couldn't convert from %s to %s (%m)\n", psz_encoding,
128 129 130 131 132 133 134 135
                psz_native_encoding);
        return iconv_append_null(p_string, i_length);
    }

    /* converted strings can be up to six times larger */
    i_out_length = i_length * 6;
    p = psz_string = malloc(i_out_length);
    if (iconv(iconv_handle, &p_string, &i_length, &p, &i_out_length) == -1) {
136
        fprintf(stderr, "couldn't convert from %s to %s (%m)\n", psz_encoding,
137 138 139 140 141
                psz_native_encoding);
        free(psz_string);
        return iconv_append_null(p_string, i_length);
    }
    if (i_length)
142
        fprintf(stderr, "partial conversion from %s to %s\n", psz_encoding,
143 144 145 146 147 148
                psz_native_encoding);

    *p = '\0';
    return psz_string;
}

149 150 151 152 153 154 155 156 157 158
/*****************************************************************************
 * handle_pat
 *****************************************************************************/
static void handle_pat(void)
{
    PSI_TABLE_DECLARE(pp_old_pat_sections);
    uint8_t i_last_section = psi_table_get_lastsection(pp_next_pat_sections);
    uint8_t i;

    if (psi_table_validate(pp_current_pat_sections) &&
159 160
        psi_table_compare(pp_current_pat_sections, pp_next_pat_sections)) {
        /* Identical PAT. Shortcut. */
161 162 163 164 165 166
        psi_table_free(pp_next_pat_sections);
        psi_table_init(pp_next_pat_sections);
        return;
    }

    if (!pat_table_validate(pp_next_pat_sections)) {
167 168 169 170 171 172 173
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_pat\"/>\n");
            break;
        default:
            printf("invalid PAT received\n");
        }
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
        psi_table_free(pp_next_pat_sections);
        psi_table_init(pp_next_pat_sections);
        return;
    }

    /* Switch tables. */
    psi_table_copy(pp_old_pat_sections, pp_current_pat_sections);
    psi_table_copy(pp_current_pat_sections, pp_next_pat_sections);
    psi_table_init(pp_next_pat_sections);

    for (i = 0; i <= i_last_section; i++) {
        uint8_t *p_section = psi_table_get_section(pp_current_pat_sections, i);
        const uint8_t *p_program;
        int j = 0;

        while ((p_program = pat_get_program(p_section, j)) != NULL) {
            const uint8_t *p_old_program = NULL;
            uint16_t i_sid = patn_get_program(p_program);
            uint16_t i_pid = patn_get_pid(p_program);
            j++;

            if (i_sid == 0) {
                if (i_pid != NIT_PID)
197
                    fprintf(stderr,
198
                        "NIT is carried on PID %hu which isn't DVB compliant\n",
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
                        i_pid);
                continue; /* NIT */
            }

            if (!psi_table_validate(pp_old_pat_sections)
                  || (p_old_program =
                      pat_table_find_program(pp_old_pat_sections, i_sid))
                       == NULL
                  || patn_get_pid(p_old_program) != i_pid) {
                sid_t *p_sid;
                int i_pmt;
                if (p_old_program != NULL)
                    p_pids[patn_get_pid(p_old_program)].i_psi_refcount--;
                p_pids[i_pid].i_psi_refcount++;

                for (i_pmt = 0; i_pmt < i_nb_sids; i_pmt++)
                    if (pp_sids[i_pmt]->i_sid == i_sid ||
                        pp_sids[i_pmt]->i_sid == 0)
                        break;

                if (i_pmt == i_nb_sids) {
                    p_sid = malloc(sizeof(sid_t));
                    pp_sids = realloc(pp_sids, ++i_nb_sids * sizeof(sid_t *));
                    pp_sids[i_pmt] = p_sid;
                    p_sid->p_current_pmt = NULL;
                }
                else
                    p_sid = pp_sids[i_pmt];

                p_sid->i_sid = i_sid;
                p_sid->i_pmt_pid = i_pid;
            }
        }
    }

    if (psi_table_validate(pp_old_pat_sections)) {
        i_last_section = psi_table_get_lastsection( pp_old_pat_sections );
        for (i = 0; i <= i_last_section; i++) {
            uint8_t *p_section = psi_table_get_section(pp_old_pat_sections, i);
            const uint8_t *p_program;
            int j = 0;

            while ((p_program = pat_get_program(p_section, j)) != NULL) {
                uint16_t i_sid = patn_get_program(p_program);
                j++;

                if (i_sid == 0)
                    continue; /* NIT */

                if (pat_table_find_program(pp_current_pat_sections, i_sid)
                      == NULL) {
                    int i_pmt;
                    for (i_pmt = 0; i_pmt < i_nb_sids; i_pmt++)
                        if (pp_sids[i_pmt]->i_sid == i_sid) {
                            pp_sids[i_pmt]->i_sid = 0;
                            free(pp_sids[i_pmt]->p_current_pmt);
255
                            pp_sids[i_pmt]->p_current_pmt = NULL;
256 257 258 259 260 261 262 263 264
                            break;
                        }
                }
            }
        }

        psi_table_free(pp_old_pat_sections);
    }

265
    pat_table_print(pp_current_pat_sections, print_wrapper, NULL, i_print_type);
266 267 268 269 270
}

static void handle_pat_section(uint16_t i_pid, uint8_t *p_section)
{
    if (i_pid != PAT_PID || !pat_validate(p_section)) {
271 272 273 274 275 276 277
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_pat_section\"/>\n");
            break;
        default:
            printf("invalid PAT section received on PID %hu\n", i_pid);
        }
278 279 280 281 282 283 284 285 286 287
        free(p_section);
        return;
    }

    if (!psi_table_section(pp_next_pat_sections, p_section))
        return;

    handle_pat();
}

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
/*****************************************************************************
 * handle_cat
 *****************************************************************************/
static void handle_cat(void)
{
    PSI_TABLE_DECLARE(pp_old_cat_sections);

    if (psi_table_validate(pp_current_cat_sections) &&
        psi_table_compare(pp_current_cat_sections, pp_next_cat_sections)) {
        /* Identical CAT. Shortcut. */
        psi_table_free(pp_next_cat_sections);
        psi_table_init(pp_next_cat_sections);
        return;
    }

    if (!cat_table_validate(pp_next_cat_sections)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_cat\"/>\n");
            break;
        default:
            printf("invalid CAT received\n");
        }
        psi_table_free(pp_next_cat_sections);
        psi_table_init(pp_next_cat_sections);
        return;
    }

    /* Switch tables. */
    psi_table_copy(pp_old_cat_sections, pp_current_cat_sections);
    psi_table_copy(pp_current_cat_sections, pp_next_cat_sections);
    psi_table_init(pp_next_cat_sections);

    if (psi_table_validate(pp_old_cat_sections))
        psi_table_free(pp_old_cat_sections);

    cat_table_print(pp_current_cat_sections, print_wrapper, NULL, i_print_type);
}

static void handle_cat_section(uint16_t i_pid, uint8_t *p_section)
{
    if (i_pid != CAT_PID || !cat_validate(p_section)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_cat_section\"/>\n");
            break;
        default:
            printf("invalid CAT section received on PID %hu\n", i_pid);
        }
        free(p_section);
        return;
    }

    if (!psi_table_section(pp_next_cat_sections, p_section))
        return;

    handle_cat();
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
/*****************************************************************************
 * handle_tsdt
 *****************************************************************************/
static void handle_tsdt(void)
{
    PSI_TABLE_DECLARE(pp_old_tsdt_sections);

    if (psi_table_validate(pp_current_tsdt_sections) &&
        psi_table_compare(pp_current_tsdt_sections, pp_next_tsdt_sections)) {
        /* Identical TSDT. Shortcut. */
        psi_table_free(pp_next_tsdt_sections);
        psi_table_init(pp_next_tsdt_sections);
        return;
    }

    if (!tsdt_table_validate(pp_next_tsdt_sections)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_tsdt\"/>\n");
            break;
        default:
            printf("invalid TSDT received\n");
        }
        psi_table_free(pp_next_tsdt_sections);
        psi_table_init(pp_next_tsdt_sections);
        return;
    }

    /* Switch tables. */
    psi_table_copy(pp_old_tsdt_sections, pp_current_tsdt_sections);
    psi_table_copy(pp_current_tsdt_sections, pp_next_tsdt_sections);
    psi_table_init(pp_next_tsdt_sections);

    if (psi_table_validate(pp_old_tsdt_sections))
        psi_table_free(pp_old_tsdt_sections);

    tsdt_table_print(pp_current_tsdt_sections, print_wrapper, NULL, i_print_type);
}

static void handle_tsdt_section(uint16_t i_pid, uint8_t *p_section)
{
    if (i_pid != TSDT_PID || !tsdt_validate(p_section)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_tsdt_section\"/>\n");
            break;
        default:
            printf("invalid TSDT section received on PID %hu\n", i_pid);
        }
        free(p_section);
        return;
    }

    if (!psi_table_section(pp_next_tsdt_sections, p_section))
        return;

    handle_tsdt();
}

406 407 408 409 410 411 412 413 414 415 416
/*****************************************************************************
 * handle_pmt
 *****************************************************************************/
static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
{
    uint16_t i_sid = pmt_get_program(p_pmt);
    sid_t *p_sid;
    int i;

    /* we do this before checking the service ID */
    if (!pmt_validate(p_pmt)) {
417 418 419 420 421 422 423 424
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_pmt_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid PMT section received on PID %hu\n", i_pid);
        }
425 426 427 428 429 430 431 432 433
        free(p_pmt);
        return;
    }

    for (i = 0; i < i_nb_sids; i++)
        if (pp_sids[i]->i_sid && pp_sids[i]->i_sid == i_sid)
            break;

    if (i == i_nb_sids) {
434 435
        switch (i_print_type) {
        case PRINT_XML:
436
            printf("<ERROR type=\"ghost_pmt\" program=\"%hu\" pid=\"%hu\"/>\n",
437 438 439 440 441 442
                   i_sid, i_pid);
            break;
        default:
            printf("ghost PMT for service %hu carried on PID %hu\n", i_sid,
                   i_pid);
        }
443 444 445 446 447 448 449 450
        p_sid = malloc(sizeof(sid_t));
        pp_sids = realloc(pp_sids, ++i_nb_sids * sizeof(sid_t *));
        pp_sids[i] = p_sid;
        p_sid->i_sid = i_sid;
        p_sid->i_pmt_pid = i_pid;
        p_sid->p_current_pmt = NULL;
    } else {
        p_sid = pp_sids[i];
451 452 453
        if (i_pid != p_sid->i_pmt_pid) {
            switch (i_print_type) {
            case PRINT_XML:
454
                printf("<ERROR type=\"ghost_pmt\" program=\"%hu\" pid=\"%hu\"/>\n",
455 456 457 458 459 460 461
                       i_sid, i_pid);
                break;
            default:
                printf("ghost PMT for service %hu carried on PID %hu\n", i_sid,
                       i_pid);
            }
        }
462 463 464
    }

    if (p_sid->p_current_pmt != NULL &&
465 466
        psi_compare(p_sid->p_current_pmt, p_pmt)) {
        /* Identical PMT. Shortcut. */
467 468 469 470 471 472 473
        free(p_pmt);
        return;
    }

    free(p_sid->p_current_pmt);
    p_sid->p_current_pmt = p_pmt;

474
    pmt_print(p_pmt, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);
475 476 477 478 479 480 481 482
}

/*****************************************************************************
 * handle_nit
 *****************************************************************************/
static void handle_nit(void)
{
    if (psi_table_validate(pp_current_nit_sections) &&
483
        psi_table_compare(pp_current_nit_sections, pp_next_nit_sections)) {
484 485 486 487 488 489 490
        /* Same version NIT. Shortcut. */
        psi_table_free(pp_next_nit_sections);
        psi_table_init(pp_next_nit_sections);
        return;
    }

    if (!nit_table_validate(pp_next_nit_sections)) {
491 492 493 494 495 496 497
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_nit\"/>\n");
            break;
        default:
            printf("invalid NIT received\n");
        }
498 499 500 501 502 503 504 505 506 507
        psi_table_free( pp_next_nit_sections );
        psi_table_init( pp_next_nit_sections );
        return;
    }

    /* Switch tables. */
    psi_table_free(pp_current_nit_sections);
    psi_table_copy(pp_current_nit_sections, pp_next_nit_sections);
    psi_table_init(pp_next_nit_sections);

508
    nit_table_print(pp_current_nit_sections, print_wrapper, NULL,
509
                    iconv_wrapper, NULL, i_print_type);
510 511 512 513 514
}

static void handle_nit_section(uint16_t i_pid, uint8_t *p_section)
{
    if (i_pid != NIT_PID || !nit_validate(p_section)) {
515 516 517 518 519 520 521 522
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_nit_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid NIT section received on PID %hu\n", i_pid);
        }
523 524 525 526 527 528 529 530 531 532
        free(p_section);
        return;
    }

    if (!psi_table_section(pp_next_nit_sections, p_section))
        return;

    handle_nit();
}

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
/*****************************************************************************
 * handle_bat
 *****************************************************************************/
static void handle_bat(void)
{
    if (psi_table_validate(pp_current_bat_sections) &&
        psi_table_compare(pp_current_bat_sections, pp_next_bat_sections)) {
        /* Same version BAT. Shortcut. */
        psi_table_free(pp_next_bat_sections);
        psi_table_init(pp_next_bat_sections);
        return;
    }

    if (!bat_table_validate(pp_next_bat_sections)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_bat\"/>\n");
            break;
        default:
            printf("invalid BAT received\n");
        }
        psi_table_free( pp_next_bat_sections );
        psi_table_init( pp_next_bat_sections );
        return;
    }

    /* Switch tables. */
    psi_table_free(pp_current_bat_sections);
    psi_table_copy(pp_current_bat_sections, pp_next_bat_sections);
    psi_table_init(pp_next_bat_sections);

    bat_table_print(pp_current_bat_sections, print_wrapper, NULL,
                    iconv_wrapper, NULL, i_print_type);
}

static void handle_bat_section(uint16_t i_pid, uint8_t *p_section)
{
    if (i_pid != BAT_PID || !bat_validate(p_section)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_bat_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid BAT section received on PID %hu\n", i_pid);
        }
        free(p_section);
        return;
    }

    if (!psi_table_section(pp_next_bat_sections, p_section))
        return;

    handle_bat();
}

589 590 591 592 593 594
/*****************************************************************************
 * handle_sdt
 *****************************************************************************/
static void handle_sdt(void)
{
    if (psi_table_validate(pp_current_sdt_sections) &&
595 596
        psi_table_compare(pp_current_sdt_sections, pp_next_sdt_sections)) {
        /* Identical SDT. Shortcut. */
597 598 599 600 601 602
        psi_table_free(pp_next_sdt_sections);
        psi_table_init(pp_next_sdt_sections);
        return;
    }

    if (!sdt_table_validate(pp_next_sdt_sections)) {
603 604 605 606 607 608 609
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_sdt\"/>\n");
            break;
        default:
            printf("invalid SDT received\n");
        }
610 611 612 613 614 615 616 617 618 619
        psi_table_free(pp_next_sdt_sections);
        psi_table_init(pp_next_sdt_sections);
        return;
    }

    /* Switch tables. */
    psi_table_free(pp_current_sdt_sections);
    psi_table_copy(pp_current_sdt_sections, pp_next_sdt_sections);
    psi_table_init(pp_next_sdt_sections);

620
    sdt_table_print(pp_current_sdt_sections, print_wrapper, NULL,
621
                    iconv_wrapper, NULL, i_print_type);
622 623 624 625 626
}

static void handle_sdt_section(uint16_t i_pid, uint8_t *p_section)
{
    if (i_pid != SDT_PID || !sdt_validate(p_section)) {
627 628 629 630 631 632 633 634
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_sdt_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid SDT section received on PID %hu\n", i_pid);
        }
635 636 637 638 639 640 641 642 643 644
        free(p_section);
        return;
    }

    if (!psi_table_section(pp_next_sdt_sections, p_section))
        return;

    handle_sdt();
}

645 646 647 648 649 650
/*****************************************************************************
 * handle_eit
 *****************************************************************************/
static void handle_eit_section(uint16_t i_pid, uint8_t *p_eit)
{
    if (i_pid != EIT_PID || !eit_validate(p_eit)) {
651 652 653 654 655 656 657 658
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_eit_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid EIT section received on PID %hu\n", i_pid);
        }
659 660 661 662
        free(p_eit);
        return;
    }

663 664
    eit_print(p_eit, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);

665 666 667
    free(p_eit);
}

668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
/*****************************************************************************
 * handle_tdt
 *****************************************************************************/
static void handle_tdt_section(uint16_t i_pid, uint8_t *p_tdt)
{
    if (i_pid != TDT_PID || !tdt_validate(p_tdt)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_tdt_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid TDT section received on PID %hu\n", i_pid);
        }
        free(p_tdt);
        return;
    }

    tdt_print(p_tdt, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);

    free(p_tdt);
}

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
/*****************************************************************************
 * handle_tot
 *****************************************************************************/
static void handle_tot_section(uint16_t i_pid, uint8_t *p_tot)
{
    if (i_pid != TOT_PID || !tot_validate(p_tot)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_tot_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid TOT section received on PID %hu\n", i_pid);
        }
        free(p_tot);
        return;
    }

    tot_print(p_tot, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);

    free(p_tot);
}

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
/*****************************************************************************
 * handle_dit
 *****************************************************************************/
static void handle_dit_section(uint16_t i_pid, uint8_t *p_dit)
{
    if (i_pid != DIT_PID || !dit_validate(p_dit)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_dit_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid DIT section received on PID %hu\n", i_pid);
        }
        free(p_dit);
        return;
    }

    dit_print(p_dit, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);

    free(p_dit);
}

737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
/*****************************************************************************
 * handle_rst
 *****************************************************************************/
static void handle_rst_section(uint16_t i_pid, uint8_t *p_rst)
{
    if (i_pid != RST_PID || !rst_validate(p_rst)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_rst_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid RST section received on PID %hu\n", i_pid);
        }
        free(p_rst);
        return;
    }

    rst_print(p_rst, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);

    free(p_rst);
}

760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
/*****************************************************************************
 * handle_sit
 *****************************************************************************/
static void handle_sit_section(uint16_t i_pid, uint8_t *p_sit)
{
    if (i_pid != SIT_PID || !sit_validate(p_sit)) {
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_sit_section\" pid=\"%hu\"/>\n",
                   i_pid);
            break;
        default:
            printf("invalid SIT section received on PID %hu\n", i_pid);
        }
        free(p_sit);
        return;
    }

    sit_print(p_sit, print_wrapper, NULL, iconv_wrapper, NULL, i_print_type);

    free(p_sit);
}

783 784 785 786 787 788 789 790
/*****************************************************************************
 * handle_section
 *****************************************************************************/
static void handle_section(uint16_t i_pid, uint8_t *p_section)
{
    uint8_t i_table_id = psi_get_tableid(p_section);

    if (!psi_validate(p_section)) {
791 792 793 794 795 796 797
        switch (i_print_type) {
        case PRINT_XML:
            printf("<ERROR type=\"invalid_section\" pid=\"%hu\"/>\n", i_pid);
            break;
        default:
            printf("invalid section on PID %hu\n", i_pid);
        }
798 799 800 801 802 803 804 805 806
        free(p_section);
        return;
    }

    switch (i_table_id) {
    case PAT_TABLE_ID:
        handle_pat_section(i_pid, p_section);
        break;

807 808 809 810
    case CAT_TABLE_ID:
        handle_cat_section(i_pid, p_section);
        break;

811 812 813 814
    case TSDT_TABLE_ID:
        handle_tsdt_section(i_pid, p_section);
        break;

815 816 817 818 819 820 821 822
    case PMT_TABLE_ID:
        handle_pmt(i_pid, p_section);
        break;

    case NIT_TABLE_ID_ACTUAL:
        handle_nit_section(i_pid, p_section);
        break;

823 824 825 826
    case BAT_TABLE_ID:
        handle_bat_section(i_pid, p_section);
        break;

827 828 829 830
    case SDT_TABLE_ID_ACTUAL:
        handle_sdt_section(i_pid, p_section);
        break;

831 832 833 834
    case TDT_TABLE_ID:
        handle_tdt_section(i_pid, p_section);
        break;

835 836 837 838
    case TOT_TABLE_ID:
        handle_tot_section(i_pid, p_section);
        break;

839 840 841 842
    case RST_TABLE_ID:
        handle_rst_section(i_pid, p_section);
        break;

843 844 845 846
    case DIT_TABLE_ID:
        handle_dit_section(i_pid, p_section);
        break;

847 848 849 850
    case SIT_TABLE_ID:
        handle_sit_section(i_pid, p_section);
        break;

851
    default:
852 853 854 855 856 857 858
        if (i_table_id == EIT_TABLE_ID_PF_ACTUAL ||
           (i_table_id >= EIT_TABLE_ID_SCHED_ACTUAL_FIRST &&
            i_table_id <= EIT_TABLE_ID_SCHED_ACTUAL_LAST)) {
            handle_eit_section(i_pid, p_section);
            break;
        }

859 860 861 862 863 864 865 866 867 868 869 870 871
        free( p_section );
        break;
    }
}

/*****************************************************************************
 * handle_psi_packet
 *****************************************************************************/
static void handle_psi_packet(uint8_t *p_ts)
{
    uint16_t i_pid = ts_get_pid(p_ts);
    ts_pid_t *p_pid = &p_pids[i_pid];
    uint8_t i_cc = ts_get_cc(p_ts);
872
    const uint8_t *p_payload;
873 874 875 876 877 878 879 880 881
    uint8_t i_length;

    if (ts_check_duplicate(i_cc, p_pid->i_last_cc) || !ts_has_payload(p_ts))
        return;

    if (p_pid->i_last_cc != -1
          && ts_check_discontinuity(i_cc, p_pid->i_last_cc))
        psi_assemble_reset(&p_pid->p_psi_buffer, &p_pid->i_psi_buffer_used);

882 883 884 885 886 887 888 889 890 891
    p_payload = ts_section(p_ts);
    i_length = p_ts + TS_SIZE - p_payload;

    if (!psi_assemble_empty(&p_pid->p_psi_buffer, &p_pid->i_psi_buffer_used)) {
        uint8_t *p_section = psi_assemble_payload(&p_pid->p_psi_buffer,
                                                  &p_pid->i_psi_buffer_used,
                                                  &p_payload, &i_length);
        if (p_section != NULL)
            handle_section(i_pid, p_section);
    }
892

893
    p_payload = ts_next_section( p_ts );
894 895 896 897 898 899 900 901 902 903 904 905 906 907
    i_length = p_ts + TS_SIZE - p_payload;

    while (i_length) {
        uint8_t *p_section = psi_assemble_payload(&p_pid->p_psi_buffer,
                                                  &p_pid->i_psi_buffer_used,
                                                  &p_payload, &i_length);
        if (p_section != NULL)
            handle_section(i_pid, p_section);
    }
}

/*****************************************************************************
 * Main loop
 *****************************************************************************/
908 909 910 911 912 913
static void usage(const char *psz)
{
    fprintf(stderr, "usage: %s [-x xml] < <input file> [> <output>]\n", psz);
    exit(EXIT_FAILURE);
}

914 915 916 917 918
int main(int i_argc, char **ppsz_argv)
{
    int i;

    if (ppsz_argv[1] != NULL &&
919 920 921 922 923 924 925 926 927 928 929 930 931
        (!strcmp(ppsz_argv[1], "-h") || !strcmp(ppsz_argv[1], "--help")))
        usage(ppsz_argv[0]);

    if (ppsz_argv[1] != NULL &&
        (!strcmp(ppsz_argv[1], "-x") || !strcmp(ppsz_argv[1], "--print"))) {
        if (ppsz_argv[2] == NULL)
            usage(ppsz_argv[0]);
        if (!strcmp(ppsz_argv[2], "text"))
            i_print_type = PRINT_TEXT;
        else if (!strcmp(ppsz_argv[2], "xml"))
            i_print_type = PRINT_XML;
        else
            usage(ppsz_argv[0]);
932 933
    }

934 935
    setvbuf(stdout, NULL, _IOLBF, 0);

936 937 938 939 940 941 942 943 944
    memset(p_pids, 0, sizeof(p_pids));

    for (i = 0; i < 8192; i++) {
        p_pids[i].i_last_cc = -1;
        psi_assemble_init( &p_pids[i].p_psi_buffer,
                           &p_pids[i].i_psi_buffer_used );
    }

    p_pids[PAT_PID].i_psi_refcount++;
945
    p_pids[CAT_PID].i_psi_refcount++;
946
    p_pids[TSDT_PID].i_psi_refcount++;
947
    p_pids[NIT_PID].i_psi_refcount++;
948
    p_pids[BAT_PID].i_psi_refcount++;
949
    p_pids[SDT_PID].i_psi_refcount++;
950
    p_pids[EIT_PID].i_psi_refcount++;
951
    p_pids[TDT_PID].i_psi_refcount++;
952
    p_pids[RST_PID].i_psi_refcount++;
953
    p_pids[DIT_PID].i_psi_refcount++;
954
    p_pids[SIT_PID].i_psi_refcount++;
955

956 957 958 959 960 961 962 963 964
    switch (i_print_type) {
    case PRINT_XML:
        printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        printf("<TS>\n");
        break;
    default:
        break;
    }

965 966 967 968
    while (!feof(stdin) && !ferror(stdin)) {
        uint8_t p_ts[TS_SIZE];
        size_t i_ret = fread(p_ts, sizeof(p_ts), 1, stdin);
        if (i_ret != 1) continue;
969 970 971 972 973 974 975 976 977
        if (!ts_validate(p_ts)) {
            switch (i_print_type) {
            case PRINT_XML:
                printf("<ERROR type=\"invalid_ts\"/>\n");
                break;
            default:
                printf("invalid TS packet\n");
            }
        } else {
978 979 980 981 982 983 984 985
            uint16_t i_pid = ts_get_pid(p_ts);
            ts_pid_t *p_pid = &p_pids[i_pid];
            if (p_pid->i_psi_refcount)
                handle_psi_packet(p_ts);
            p_pid->i_last_cc = ts_get_cc(p_ts);
        }
    }

986 987 988 989 990 991 992 993
    switch (i_print_type) {
    case PRINT_XML:
        printf("</TS>\n");
        break;
    default:
        break;
    }

994
    return EXIT_SUCCESS;
995
}