/*
 * Author:    Joerg Weule -- weule@7b5.de
 *            http://www.eulesoft.de       
 *            http://www.7b5.de
 *
 * Copyright: GNU Pubilc Licence (GPL)
 *
 * This program can print the content of 'crid'-files.
 * 'crid'-files are written by >> Siemens Gigaset M740AV << for
 * each recording.
 *
 * Usage: m740av_crid2txt [-l] [-l] [-v] file.crid
 *
 * Comile with 'cc m740av_crid2txt.c -O -o m740av_crid2txt'
 *
 */

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

unsigned long long vl;        /* "l" 64 bit */
unsigned int       vi;        /* "i" 32 bit */
unsigned short     vs;        /* "s" 16 bit */
unsigned char      vc;        /* "c"  8 bit */
         char      vb[10240]; /* "b" string */
struct tm          vt;        /* "t" time   */

/*
 * description of the fields
 * format / name / verboselevel
 *
 * Verbose: 1: print more information [-l]
 * Verbose: 2: print more information [-l -l]
 * Verbose: 9: print attribute names and information [-v]
 *
 */
char*d_crid[][3] = {
	{"i", "                           CRID-Version","9"},
	{"l", "                                crid-id","9"},
	{"i", "                        Recording-State","9"},
	{"t", "                         epg-start-time","1"},
	{"t", "                           epg-end-time","2"},
	{"i", "                       user-access-data","9"},
	{"i", "                   recording-pre-offset","9"},
	{"i", "                  recording-prot-offset","9"},
	{"i", "                         recording type","9"},
	{"i", "                              Series-ID","9"},
	{"s", "                        protection flag","9"},
	{"i", "                        length-of-title","9"},
	{"b", "                                  title","0"},
	{"i", "                number-of-record-pieces","9"},
	{"i", "      length-of-recordingl-control-file","9"},
	{"b", "         name-of-recording-control-file","0"},
	{"i", "       absolute-start-time-of-recording","9"},
	{"l", " start-timestamp-on-recording-in-90-KHz","9"},
	{"l", "   end-timestamp-on-recording-in-90-KHz","9"},
	{"i", "               length-of-epg-short-text","9"},
	{"b", "                         epg-short-text","1"},
	{"i", "                length-of-epg-long-text","9"},
	{"b", "                          epg-long-text","1"},
	{"i", "                     playback-timestamp","9"},
	{"i", "                                unknown","9"},
	{NULL,NULL,NULL}
} ;

char*d_fmpg[][3] = {
	{"l", "                              TimeStamp","0"},
	{"s", "                                    PCR","0"},
	{"s", "                                  VIDEO","0"},
	{"s", "                                    PMT","0"},
	{"s", "                                  AUDIO","0"},
	{"n", "                               FILENAME","0"},
	{NULL,NULL,NULL}
} ;

char*d_idx[][3] = {
	{"l", "                              TimeStamp","0"},
	{"l", "                                 offset","0"},
	{"i", "                                   size","0"},
	{"i", "                                  flags","0"},
	{NULL,NULL,NULL}
} ;

char*d_midx[][3] = {
	{"l", "                              TimeStamp","0"},
	{"l", "                                 offset","0"},
	{"i", "                                ioffset","0"},
	{"i", "                                    pad","0"},
	{NULL,NULL,NULL}
} ;

/*
 * change endian -- fast implementation
 */
void x(void*x,int n){
	char*p = x ;
	char*q = p+n ;
	switch ( n ) {
		case 16:
			{ char h = *p ; *p++ = *--q ; *q = h; }
			{ char h = *p ; *p++ = *--q ; *q = h; }
			{ char h = *p ; *p++ = *--q ; *q = h; }
			{ char h = *p ; *p++ = *--q ; *q = h; }
		case 8:
			{ char h = *p ; *p++ = *--q ; *q = h; }
			{ char h = *p ; *p++ = *--q ; *q = h; }
		case 4:
			{ char h = *p ; *p++ = *--q ; *q = h; }
		case 2:
			{ char h = *p ; *p++ = *--q ; *q = h; }
		case 1: ;
	}
}

/*
 * print the file
 */

void p(FILE*f,char*(*d)[3],int v) {
	int n = 0 ;
	int i = 0 ;
	int e = 'x' ;
	e = *((char*)&e) == 'x' ; /* endian check */

	while ( d[n][0] != NULL ) {
		switch (d[n][0][0]) {

		case 'c':
			i=fread(&vc,1,sizeof(vc),f);
			if ( i == 0 ) return ;
			if ( atoi(d[n][2]) > v ) break ;

			if(e) x(&vi,sizeof(vi));

			if(v>8) printf("%02d-c:%s: %u\n",n,d[n][1],vc);
			else    printf("%u\n",n,d[n][1],vc);

			break;

		case 's':
			i=fread(&vs,1,sizeof(vs),f);
			if ( i == 0 ) return ;
			if ( atoi(d[n][2]) > v ) break ;

			if(e) x(&vi,sizeof(vi));

			if(v>8) printf("%02d-s:%s: %u\n",n,d[n][1],vs);
			else    printf("%u\n",n,d[n][1],vs);

			break;

		case 'i':
			i=fread(&vi,1,sizeof(vi),f);
			if ( i == 0 ) return ;
			//if ( n == 0 ) e = vi > 10 ; // check the endian
			if(e) x(&vi,sizeof(vi)); // needed here for 'b'
			if ( atoi(d[n][2]) > v ) break ;

			if(v>8) printf("%02d-i:%s: %u\n",n,d[n][1],vi);
			else    printf("%u\n",vi);

			break;

		case 't':
			i=fread(&vi,1,sizeof(vi),f);
			if ( i == 0 ) return ;
			if ( atoi(d[n][2]) > v ) break ;

			if(e) x(&vi,sizeof(vi));
			time_t t = vi ;
			localtime_r(&t,&vt);
			asctime_r(&vt,vb);

			if(v>8) printf("%02d-i:%s: %s",n,d[n][1],vb);
			else    printf("%s",vb);

			break;

		case 'l':
			i=fread(&vl,1,sizeof(vl),f);
			if ( i == 0 ) return ;
			if ( atoi(d[n][2]) > v ) break ;

			if(e) x(&vl,sizeof(vl));

			if(v>8) printf("%02d-L:%s: %llu\n",n,d[n][1],vl);
			else    printf("%llu\n",vl);

			break;

		case 'n':
			vi = 256 - 16 ;
		case 'b':
			i=fread(vb,1,vi,f);
			if ( i < vi ) return ;
			if ( atoi(d[n][2]) > v ) break ;

			vb[vi]='\0';
			if(v>8) {
				printf("%02d-L:%s: '%s'\n",n,d[n][1],vb);
			} else {
				int do_print = 0 ;
				if (vi) {
					if ( v == 0 ) do_print = 1 ;
					else printf("%s\n",vb);
				} else printf("...\n");

				if (vi && v == 0 ) {
					char*p = vb ;
					do {
						if (
							*p & 0x80 ||
							*p == ' ' ||
							*p == '"' ||
							*p == '\'' ||
							*p == '`' ||
							*p == '\'' ||
							*p == '&' ||
							*p == '$' ||
							*p == '%' ||
							*p == '/' ||
							*p == '[' ||
							*p == ']' ||
							*p == '{' ||
							*p == '}' ||
							*p == '!' ||
							*p == ':' ||
							*p == ',' ||
							*p == ';' ||
							*p == '?' ||
							1 <= *p && *p < 32 
						) *p = '_' , do_print = 1 ;
					} while ( *p++ ) ;
					if (do_print) printf("%s\n",vb);
				}
			}

			break;
		}
		n++ ;
	}
}

int main(int argc,char*argv[]){
	int verbose_level = 0 ;
	FILE*ctrl_file = NULL ;
	char*(*d)[3] = d_crid ;

	while ( argc > 1 ) {
		if ( argv[1][0] == '-' ){

			if ( !strcmp(argv[1],"-l")) verbose_level++  ;
			if ( !strcmp(argv[1],"-v")) verbose_level+=9 ;

			if ( !strcmp(argv[1],"--get-title")) d_crid[15][2] = "1" ;
			if ( !strcmp(argv[1],"-t")) d_crid[15][2] = "1" ;

			if ( !strcmp(argv[1],"-u")) d_crid[12][2] = "1" ;
			if ( !strcmp(argv[1],"---get-name-of-contol-file")) d_crid[12][2] = "1" ;

			if ( !strcmp(argv[1],"-fmpg")) d = d_fmpg ;
			if ( !strcmp(argv[1],"-idx")) d = d_idx ;
			if ( !strcmp(argv[1],"-midx")) d = d_midx ;

			argv[1] = argv[0] ;
			argv++;
			argc--;
		} else break ;
	}

	if ( argc == 0 ) {
		fprintf(stderr,"No file name!");
		exit(1);
	}

	ctrl_file = fopen(argv[1],"r");
	if ( ctrl_file == NULL ) {
		fprintf(stderr,"Unable to open file!");
		exit(1);
	}

	p(ctrl_file,d,verbose_level);
	if ( verbose_level > 0 ) {
		while ( !feof(ctrl_file)) {
			printf("----------------\n");
			p(ctrl_file,d,verbose_level);
		}
	}

	fclose(ctrl_file);

	return 0 ;
}

