view libmpdemux/realrtsp/asmrp.c @ 13738:39004f891def

seeking based on the largest timestamp in an mpeg stream It is often more accurate than the current seeking and it has the additional benefit of giving the (almost) precise total time of the movie. patch by Michael Behrisch < behrisch at informatik.hu-berlin.de >
author aurel
date Sat, 23 Oct 2004 00:05:38 +0000
parents 0d38a501c6a5
children f580a7755ac5
line wrap: on
line source

/*
 * This file was ported to MPlayer from xine CVS asmrp.c,v 1.2 2002/12/17 16:49:48
 */

/*
 * Copyright (C) 2002 the xine project
 *
 * This file is part of xine, a free video player.
 * 
 * xine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * xine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 *
 * a parser for real's asm rules
 *
 * grammar for these rules:
 *

   rule_book  = { rule }
   rule       = ( '#' condition { ',' assignment } | [ assignment {',' assignment} ]) ';'
   assignment = id '=' const
   const      = ( number | string )
   condition  = comp_expr { ( '&&' | '||' ) comp_expr }
   comp_expr  = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand }
   operand    = ( '$' id | num | '(' condition ')' )

 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
#define LOG
*/

#define ASMRP_SYM_NONE         0
#define ASMRP_SYM_EOF          1

#define ASMRP_SYM_NUM          2
#define ASMRP_SYM_ID           3
#define ASMRP_SYM_STRING       4

#define ASMRP_SYM_HASH         10
#define ASMRP_SYM_SEMICOLON    11
#define ASMRP_SYM_COMMA        12
#define ASMRP_SYM_EQUALS       13
#define ASMRP_SYM_AND          14
#define ASMRP_SYM_OR           15
#define ASMRP_SYM_LESS         16
#define ASMRP_SYM_LEQ          17
#define ASMRP_SYM_GEQ          18
#define ASMRP_SYM_GREATER      19
#define ASMRP_SYM_DOLLAR       20
#define ASMRP_SYM_LPAREN       21
#define ASMRP_SYM_RPAREN       22

#define ASMRP_MAX_ID         1024

#define ASMRP_MAX_SYMTAB       10

typedef struct {
  char *id;
  int   v;
} asmrp_sym_t;

typedef struct {

  /* public part */

  int         sym;
  int         num;
  
  char        str[ASMRP_MAX_ID];

  /* private part */

  char       *buf;
  int         pos;
  char        ch;

  asmrp_sym_t sym_tab[ASMRP_MAX_SYMTAB];
  int         sym_tab_num;

} asmrp_t;

static asmrp_t *asmrp_new () {

  asmrp_t *p;

  p = malloc (sizeof (asmrp_t));

  p->sym_tab_num = 0;
  p->sym         = ASMRP_SYM_NONE;

  return p;
}

static void asmrp_dispose (asmrp_t *p) {

  int i;

  for (i=0; i<p->sym_tab_num; i++) 
    free (p->sym_tab[i].id);

  free (p);
}

static void asmrp_getch (asmrp_t *p) {
  p->ch = p->buf[p->pos];
  p->pos++;

#ifdef LOG
  printf ("%c\n", p->ch);
#endif

}

static void asmrp_init (asmrp_t *p, const char *str) {

  p->buf = strdup (str);
  p->pos = 0;
  
  asmrp_getch (p);
}

static void asmrp_number (asmrp_t *p) {

  int num;

  num = 0;
  while ( (p->ch>='0') && (p->ch<='9') ) {

    num = num*10 + (p->ch - '0');

    asmrp_getch (p);
  }

  p->sym = ASMRP_SYM_NUM;
  p->num = num;
}

static void asmrp_string (asmrp_t *p) {

  int l;

  l = 0;

  while ( (p->ch!='"') && (p->ch>=32) ) {

    p->str[l] = p->ch;

    l++;
    asmrp_getch (p);
  }
  p->str[l]=0;
  
  if (p->ch=='"')
    asmrp_getch (p);
  
  p->sym = ASMRP_SYM_STRING;
}

static void asmrp_identifier (asmrp_t *p) {

  int l;

  l = 0;

  while ( ((p->ch>='A') && (p->ch<='z'))
	  || ((p->ch>='0') && (p->ch<='9'))) {

    p->str[l] = p->ch;

    l++;
    asmrp_getch (p);
  }
  p->str[l]=0;
  
  p->sym = ASMRP_SYM_ID;
}

#ifdef LOG
static void asmrp_print_sym (asmrp_t *p) {

  printf ("symbol: ");

  switch (p->sym) {

  case ASMRP_SYM_NONE:
    printf ("NONE\n");
    break;

  case ASMRP_SYM_EOF:
    printf ("EOF\n");
    break;

  case ASMRP_SYM_NUM:
    printf ("NUM %d\n", p->num);
    break;

  case ASMRP_SYM_ID:
    printf ("ID '%s'\n", p->str);
    break;

  case ASMRP_SYM_STRING:
    printf ("STRING \"%s\"\n", p->str);
    break;

  case ASMRP_SYM_HASH:
    printf ("#\n");
    break;

  case ASMRP_SYM_SEMICOLON:
    printf (";\n");
    break;
  case ASMRP_SYM_COMMA:
    printf (",\n");
    break;
  case ASMRP_SYM_EQUALS:
    printf ("==\n");
    break;
  case ASMRP_SYM_AND:
    printf ("&&\n");
    break;
  case ASMRP_SYM_OR:
    printf ("||\n");
    break;
  case ASMRP_SYM_LESS:
    printf ("<\n");
    break;
  case ASMRP_SYM_LEQ:
    printf ("<=\n");
    break;
  case ASMRP_SYM_GEQ:
    printf (">=\n");
    break;
  case ASMRP_SYM_GREATER:
    printf (">\n");
    break;
  case ASMRP_SYM_DOLLAR:
    printf ("$\n");
    break;
  case ASMRP_SYM_LPAREN:
    printf ("(\n");
    break;
  case ASMRP_SYM_RPAREN:
    printf (")\n");
    break;

  default:
    printf ("unknown symbol %d\n", p->sym);
  }
}
#endif

static void asmrp_get_sym (asmrp_t *p) {

  while (p->ch <= 32) {
    if (p->ch == 0) {
      p->sym = ASMRP_SYM_EOF;
      return;
    }

    asmrp_getch (p);
  }

  if (p->ch == '\\')
    asmrp_getch (p);

  switch (p->ch) {

  case '#':
    p->sym = ASMRP_SYM_HASH;
    asmrp_getch (p);
    break;
  case ';':
    p->sym = ASMRP_SYM_SEMICOLON;
    asmrp_getch (p);
    break;
  case ',':
    p->sym = ASMRP_SYM_COMMA;
    asmrp_getch (p);
    break;
  case '=':
    p->sym = ASMRP_SYM_EQUALS;
    asmrp_getch (p);
    if (p->ch=='=')
      asmrp_getch (p);
    break;
  case '&':
    p->sym = ASMRP_SYM_AND;
    asmrp_getch (p);
    if (p->ch=='&')
      asmrp_getch (p);
    break;
  case '|':
    p->sym = ASMRP_SYM_OR;
    asmrp_getch (p);
    if (p->ch=='|')
      asmrp_getch (p);
    break;
  case '<':
    p->sym = ASMRP_SYM_LESS;
    asmrp_getch (p);
    if (p->ch=='=') {
      p->sym = ASMRP_SYM_LEQ;
      asmrp_getch (p);
    }
    break;
  case '>':
    p->sym = ASMRP_SYM_GREATER;
    asmrp_getch (p);
    if (p->ch=='=') {
      p->sym = ASMRP_SYM_GEQ;
      asmrp_getch (p);
    }
    break;
  case '$':
    p->sym = ASMRP_SYM_DOLLAR;
    asmrp_getch (p);
    break;
  case '(':
    p->sym = ASMRP_SYM_LPAREN;
    asmrp_getch (p);
    break;
  case ')':
    p->sym = ASMRP_SYM_RPAREN;
    asmrp_getch (p);
    break;

  case '"':
    asmrp_getch (p);
    asmrp_string (p);
    break;

  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
    asmrp_number (p);
    break;

  default:
    asmrp_identifier (p);
  }

#ifdef LOG
  asmrp_print_sym (p);
#endif

}

static int asmrp_find_id (asmrp_t *p, char *s) {

  int i;

  for (i=0; i<p->sym_tab_num; i++) {
    if (!strcmp (s, p->sym_tab[i].id))
      return i;
  }

  return -1;
}

static int asmrp_set_id (asmrp_t *p, char *s, int v) {

  int i;

  i = asmrp_find_id (p, s);

  if (i<0) {
    i = p->sym_tab_num;
    p->sym_tab_num++;
    p->sym_tab[i].id = strdup (s);

#ifdef LOG
    printf ("new symbol '%s'\n", s);
#endif

  }    

  p->sym_tab[i].v = v;
 
#ifdef LOG
  printf ("symbol '%s' assigned %d\n", s, v);
#endif

  return i;
}

static int asmrp_condition (asmrp_t *p) ;

static int asmrp_operand (asmrp_t *p) {

  int i, ret;
  
#ifdef LOG
  printf ("operand\n");
#endif

  ret = 0;

  switch (p->sym) {

  case ASMRP_SYM_DOLLAR:

    asmrp_get_sym (p);
    
    if (p->sym != ASMRP_SYM_ID) {
      printf ("error: identifier expected.\n");
      abort();
    }

    i = asmrp_find_id (p, p->str);
    if (i<0) {
      printf ("error: unknown identifier %s\n", p->str);
    }
    ret = p->sym_tab[i].v;

    asmrp_get_sym (p);
    break;

  case ASMRP_SYM_NUM:
    ret = p->num;

    asmrp_get_sym (p);
    break;

  case ASMRP_SYM_LPAREN:
    asmrp_get_sym (p);

    ret = asmrp_condition (p);

    if (p->sym != ASMRP_SYM_RPAREN) {
      printf ("error: ) expected.\n");
      abort();
    }

    asmrp_get_sym (p);
    break;

  default:
    printf ("syntax error, $ number or ( expected\n");
    abort();
  }

#ifdef LOG
  printf ("operand done, =%d\n", ret);
#endif
  
  return ret;
}

static int asmrp_comp_expression (asmrp_t *p) {

  int a;

#ifdef LOG
  printf ("comp_expression\n");
#endif

  a = asmrp_operand (p);

  while ( (p->sym == ASMRP_SYM_LESS)
	  || (p->sym == ASMRP_SYM_LEQ)
	  || (p->sym == ASMRP_SYM_EQUALS)
	  || (p->sym == ASMRP_SYM_GEQ)
	  || (p->sym == ASMRP_SYM_GREATER) ) {
    int op = p->sym;
    int b;

    asmrp_get_sym (p);

    b = asmrp_operand (p);

    switch (op) {
    case ASMRP_SYM_LESS:
      a = a<b;
      break;
    case ASMRP_SYM_LEQ:
      a = a<=b;
      break;
    case ASMRP_SYM_EQUALS:
      a = a==b;
      break;
    case ASMRP_SYM_GEQ:
      a = a>=b;
      break;
    case ASMRP_SYM_GREATER:
      a = a>b;
      break;
    }

  }

#ifdef LOG
  printf ("comp_expression done = %d\n", a);
#endif
  return a;
}

static int asmrp_condition (asmrp_t *p) {
  
  int a;

#ifdef LOG
  printf ("condition\n");
#endif

  a = asmrp_comp_expression (p);

  while ( (p->sym == ASMRP_SYM_AND) || (p->sym == ASMRP_SYM_OR) ) {
    int op, b;

    op = p->sym;

    asmrp_get_sym (p);

    b = asmrp_comp_expression (p);

    switch (op) {
    case ASMRP_SYM_AND:
      a = a & b;
      break;
    case ASMRP_SYM_OR:
      a = a | b;
      break;
    }
  }

#ifdef LOG
  printf ("condition done = %d\n", a);
#endif
  return a;
}

static void asmrp_assignment (asmrp_t *p) {

#ifdef LOG
  printf ("assignment\n");
#endif

  if (p->sym == ASMRP_SYM_COMMA || p->sym == ASMRP_SYM_SEMICOLON) {
#ifdef LOG
    printf ("empty assignment\n");
#endif
    return;
  }

  if (p->sym != ASMRP_SYM_ID) {
    printf ("error: identifier expected\n");
    abort ();
  }
  asmrp_get_sym (p);

  if (p->sym != ASMRP_SYM_EQUALS) {
    printf ("error: = expected\n");
    abort ();
  }
  asmrp_get_sym (p);

  if ( (p->sym != ASMRP_SYM_NUM) && (p->sym != ASMRP_SYM_STRING) 
       && (p->sym != ASMRP_SYM_ID)) {
    printf ("error: number or string expected\n");
    abort ();
  }
  asmrp_get_sym (p);

#ifdef LOG
  printf ("assignment done\n");
#endif
}

static int asmrp_rule (asmrp_t *p) {
  
  int ret;

#ifdef LOG
  printf ("rule\n");
#endif

  ret = 1;
  
  if (p->sym == ASMRP_SYM_HASH) {

    asmrp_get_sym (p);
    ret = asmrp_condition (p);

    while (p->sym == ASMRP_SYM_COMMA) {
      
      asmrp_get_sym (p);
      
      asmrp_assignment (p);
    }

  } else if (p->sym != ASMRP_SYM_SEMICOLON) {

    asmrp_assignment (p);

    while (p->sym == ASMRP_SYM_COMMA) {

      asmrp_get_sym (p);
      asmrp_assignment (p);
    }
  }

#ifdef LOG
  printf ("rule done = %d\n", ret);
#endif

  if (p->sym != ASMRP_SYM_SEMICOLON) {
    printf ("semicolon expected.\n");
    abort ();
  }

  asmrp_get_sym (p);

  return ret;
}

static int asmrp_eval (asmrp_t *p, int *matches) {

  int rule_num, num_matches;

#ifdef LOG
  printf ("eval\n");
#endif

  asmrp_get_sym (p);

  rule_num = 0; num_matches = 0;
  while (p->sym != ASMRP_SYM_EOF) {

    if (asmrp_rule (p)) {
#ifdef LOG
      printf ("rule #%d is true\n", rule_num);
#endif
      matches[num_matches] = rule_num;
      num_matches++;
    }

    rule_num++;
  }

  matches[num_matches] = -1;
  return num_matches;
}

int asmrp_match (const char *rules, int bandwidth, int *matches) {

  asmrp_t *p;
  int      num_matches;

  p = asmrp_new ();

  asmrp_init (p, rules);

  asmrp_set_id (p, "Bandwidth", bandwidth);
  asmrp_set_id (p, "OldPNMPlayer", 0);

  num_matches = asmrp_eval (p, matches);

  asmrp_dispose (p);

  return num_matches;
}