/*
 * Copyright (C) 2002 Scott Smith (trckjunky@users.sourceforge.net)
 *
 * This program 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.
 *
 * This program 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
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <dirent.h>
#include <errno.h>

static const char RCSID[]="$Id: tocgen.c,v 1.1 2003/01/01 13:08:20 bero Exp $";

// keeps TT_SRPT within 1 sector
#define MAXVTS 170

struct vtsdef {
    int numchapters,numsectors;
    char vtssummary[0x300],vtscat[4];
} vts[MAXVTS];
int numvts=0;

unsigned int read2(unsigned char *p)
{
    return (p[0]<<8)|p[1];
}

void write2(unsigned char *p,unsigned int foo)
{
    p[0]=foo>>8;
    p[1]=foo&255;
}

unsigned int read4(unsigned char *p)
{
    return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
}

void write4(char *p,unsigned int v)
{
    p[0]=(v>>24)&255;
    p[1]=(v>>16)&255;
    p[2]=(v>>8)&255;
    p[3]=v&255;
}

int toclen()
{
    return 2+(8+numvts*0x30c+2047)/2048;
}

void TocGen(char *fname)
{
    static char buf[2048];
    int i,j;
    FILE *h;

    h=fopen(fname,"w");

    memset(buf,0,2048);
    memcpy(buf,"DVDVIDEO-VMG",12);
    buf[0xf]=toclen()*2-1;
    buf[0x1f]=toclen()-1;
    buf[0x21]=0x11;
    buf[0x27]=1;
    buf[0x29]=1;
    buf[0x2a]=1;
    write2(buf+0x3e,numvts);
    memcpy(buf+0x40,"dvdauthor",9);
    buf[0x82]=5;
    buf[0x83]=0xb;
    buf[0x86]=4;
    buf[0xc7]=1;
    buf[0xd3]=2;
    buf[0x407]=0xc0;
    buf[0x4e5]=0xec;
    buf[0x4ed]=3;
    buf[0x4f3]=0x1f;
    buf[0x4f4]=0x71;
    buf[0x4fc]=0x71;
    buf[0x4ff]=1;
    buf[0x504]=0x30;
    buf[0x505]=0x02;
    buf[0x509]=1;
    fwrite(buf,1,2048,h);


    // TT_SRPT
    // right now we assume 1 title per titleset, thus # titles == # titlesets
    memset(buf,0,2048);
    write2(buf,numvts); // # of titles
    write4(buf+4,7+12*numvts); // last byte of entry
    j=toclen()*2;
    for( i=0; i<numvts; i++ ) {
        buf[0x8+i*12]=0x3c; // title type
        buf[0x9+i*12]=0x1; // number of angles
        write2(buf+0xa+i*12,vts[i].numchapters); // number of chapters
        buf[0xe + i*12]=i+1; // VTS #
        buf[0xf+i*12]=1; // title # within VTS
        write4(buf+0x10+i*12,j); // start sector for VTS
        j+=vts[i].numsectors;
    }
    fwrite(buf,1,2048,h);

    // VMG_VTS_ATRT
    memset(buf,0,2048);
    j=8+numvts*4;
    write2(buf,numvts);
    write4(buf+4,numvts*0x30c+8-1);
    for( i=0; i<numvts; i++ )
        write4(buf+8+i*4,j+i*0x308);
    fwrite(buf,1,j,h);
    for( i=0; i<numvts; i++ ) {
        write4(buf,0x307);
        memcpy(buf+4,vts[i].vtscat,4);
        memcpy(buf+8,vts[i].vtssummary,0x300);
        fwrite(buf,1,0x308,h);
        j+=0x308;
    }
    j=2048-(j&2047);
    if( j < 2048 ) {
        memset(buf,0,j);
        fwrite(buf,1,j,h);
    }
    fclose(h);
}

void ScanIfo(char *ifo)
{
    static unsigned char buf[2048];
    FILE *h=fopen(ifo,"r");
    if( !h ) {
        fprintf(stderr,"cannot open %s: %s\n",ifo,strerror(errno));
        exit(1);
    }
    if( numvts+1 >= MAXVTS ) {
        fprintf(stderr,"Too many VTSs\n");
        exit(1);
    }
    fread(buf,1,2048,h);
    vts[numvts].numsectors=read4(buf+0xc)+1;
    memcpy(vts[numvts].vtscat,buf+0x22,4);
    memcpy(vts[numvts].vtssummary,buf+0x100,0x300);
    fread(buf,1,2048,h); // VTS_PTT_SRPT is 2nd sector
    vts[numvts].numchapters=read2(buf+read4(buf+4)-1);
    fclose(h);
    numvts++;
}

int main(int argc,char **argv)
{
    int i,nm=0;
    DIR *d;
    struct dirent *de;
    static char fbuf[1000];
    if( argc != 2 ) {
        fprintf(stderr,"Must pass in VIDEO_TS directory as a parameter\n");
        return 1;
    }
    fprintf(stderr,"tocgen running\n");
    d=opendir(argv[1]);
    while ((de=readdir(d))!=0) {
        i=strlen(de->d_name);
        if( i==12 && !strcmp(de->d_name+i-6,"_0.IFO") &&
            !memcmp(de->d_name,"VTS_",4)) {
            i=(de->d_name[4]-'0')*10+(de->d_name[5]-'0');
            if( i > nm )
                nm=i;
        }
    }
    closedir(d);
    for( i=1; i<=nm; i++ ) {
        sprintf(fbuf,"%s/VTS_%02d_0.IFO",argv[1],i);
        fprintf(stderr,"scanning %s\n",fbuf);
        ScanIfo(fbuf);
    }
    if( !numvts ) {
        fprintf(stderr,"No .IFO files to process\n");
        return 1;
    }
    sprintf(fbuf,"%s/VIDEO_TS.IFO",argv[1]);
    TocGen(fbuf);
    sprintf(fbuf,"%s/VIDEO_TS.BUP",argv[1]);
    TocGen(fbuf);
    return 0;
}
