// (c) 2002-2007 Electronic Arts Inc.
//

// Copyright (C) Electronic Arts Canada Inc. 1990-2002.  All rights reserved.

const char *SPIT_history[] =
{
"------------------------------------------------------------------",
"                                                                  ",
"                          Chunkify v1.06                          ",
"                                                                  ",
"        by Patrick Ratto, S. Wardle, M. Ockenden, F. Barchard     ",
"                                                                  ",
"                    Main program - Mar 14, 2006                   ",
"                                                                  ",
"------------------------------------------------------------------",
"                                                                  ",
" Version Date   SE History:                                       ",
" ------- ----   -- --------                                       ",
"    1.00 010101 PR initial version by Patrick Ratto               ",
"    1.01 011001 SW multi files                                    ",
"    1.02 020822 MO response files                                 ",
"    1.03 020911 FB fix multi file bug                             ",
"    1.04 030826 FB bloodhound tracking added                      ",
"    1.05 060314 FB bumped max chunk from 200 to 500 KB            ",
"    1.06 060417 FB less verbose                                   ",
"                                                                  ",
"------------------------------------------------------------------",
"\0"
};


 /*
;
; ABSTRACT
;
; chunkify - make m2v into mpc
;
; SUMMARY
;
; chunkify file.m2v =out.mpc
;
; DESCRIPTION
;
; chunkify tool converts mpeg 2 video streams (m2v) into mpc chunk streams
;
;
; SEE ALSO
;
; chimp, gx, sx, rcmp
;
; EXAMPLE
;
; chunkify seq1.m2v seq2.m2v =bob.mpc
;
; END ABSTRACT
;
*/

#if defined(_MSC_VER)
#pragma warning(disable: 4996)  // warning C4996: 'fscanf' was declared deprecated
#endif
#if defined(__ICL)
#pragma warning(disable: 1478)  // (icl) warning #1478: function "strcpy" was declared "deprecated"
#endif

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

#define MAX_CHUNKSIZE   500000
#define CHUNK_ALIGN     4


static FILE *infile = NULL;
static char infilebuf[4096];
static int  infilebufsize=0;
static int  infilepos=0;

static char databuf[MAX_CHUNKSIZE];

static char chunkhdr[8] = { 'M', 'P', 'C', 'h' };


static int getbyte(void)
{
    int i;

    i = infilepos & 4095;
    if (i == 0)
    {
        fseek(infile, infilepos, SEEK_SET);
        infilebufsize = (int)(fread(infilebuf, 1, 4096, infile));
    }
    if (i == infilebufsize) return(EOF);
    ++infilepos;
    return((unsigned char) infilebuf[i]);
}

static int find_header(void)
{
    int state;
    int ch;

    state = 0;
    while ((ch = getbyte()) != EOF)
    {
        if (state < 2)
        {
            if (ch == 0x00) ++state;
            else state = 0;
        }
        else if (state == 2)
        {
            if (ch == 0x01) ++state;
            else if (ch != 0) state = 0;
        }
        else
        {
            if (ch == 0xb8) return(1);
            else if (ch == 0x00) return(2);
            else state = 0;
        }
    }

    return(0);
}

static void find_sequence(void)
{
    int val;

    val = (getbyte() << 24) + (getbyte() << 16) + (getbyte() << 8) + getbyte();

    if (val != 0x000001b3)
    {
        printf("Failed to find sequence header\n");
        exit(1);
    }
}

static void find_GOP(void)
{
    if (find_header() != 1)
    {
        printf("Failed to find GOP header\n");
        exit(1);
    }
}

static void find_picture(void)
{
    if (find_header() != 2)
    {
        printf("Failed to find picture header following GOP\n");
        exit(1);
    }
}

//------------------------------------------------------------------------------------

// command line arguments can be entered in 1 of two formats:
// 1) to create an .mpc file from a list of files,
//    "chunkify file1 file2 fileN -=output.mpc"
// 2) to create an .mpc file from a text file containing a list of file names:
//    "chunkify @file.txt -=output.mpc"
int main( int argc, char** argv )
{
    const int FILENAMES_FROM_CMD_LINE  = 0;
    const int FILENAMES_FROM_TEXT_FILE = 1;

    FILE* textFile = NULL;
    FILE* outFile  = NULL;

    int fileNameSource = FILENAMES_FROM_CMD_LINE;
    int  prevpos       = 0;
    int  size          = 0;
    int  alignsize     = 0;
    int  chunksize     = 0;
    int  type          = 0;
    int  outFileIndex  = 0;
    int  curFileIndex  = 0;
    int  lastFileIndex = 0;
    int  verbose       = 0;

    char inFileName[256] = "bob.txt";
    char outName[256]    = "chunkify.mpc";


    // display app. version info.
    printf("Chunkify, v1.06, 2006.4.17 by Frank Barchard\n");

    // check for a minimum number of command line arguments;
    // print a 'usage' message if less than 3
    if (argc < 2)
    {
        printf("Usage: CHUNKIFY <file1> <file2> <file...> <fileN> =<output.mpc>\n");
        printf(" OR    CHUNKIFY @<file.txt> =<output.mpc>\n" );
        return(0);
    }

    // if only 3 arguments, check for the '@' symbol in the second argument
    // to indicate that file names will be read from a text file
    else if( argc == 3 )
    {
        // is this argument a text file name?
        if( argv[1][0] == '@' )
        {
            // skip over the '@' symbol to get the file name
            if( (textFile = fopen( &argv[1][1], "r" )) == NULL)
            {
                printf( "error: could not open input text file %s\n", &argv[1][1] );
                exit(1);
            }
            fileNameSource = FILENAMES_FROM_TEXT_FILE;
        }
    }

    // search the command line arguments for the output file name;
    // use the "-=" or "=" symbols to identify it
    for ( curFileIndex = 1; curFileIndex < argc; curFileIndex++ )
    {
        if( argv[curFileIndex][0]== '-' && argv[curFileIndex][1]=='=' )
        {
            strcpy( outName, &argv[curFileIndex][2] );
            outFileIndex = curFileIndex;
            break;
        }
        else if( argv[curFileIndex][0]== '=' )
        {
            strcpy(outName,&argv[curFileIndex][1]);
            outFileIndex = curFileIndex;
            break;
        }
    }

    // create the output file
    if( (outFile = fopen( outName, "wb" )) == NULL )
    {
        printf( "error: could not create output file %s\n", outName );

        // clean up before exit
        if( textFile )
            fclose( textFile );

        exit(1);
    }

    // loop through and chunkify all input files
    lastFileIndex = (argc - 1);

    for( curFileIndex=1;   ;curFileIndex++)
    {
        // if input file names come from the command line, get them through argv
        if( fileNameSource == FILENAMES_FROM_CMD_LINE )
        {
            // out of arguments; (argc - 1) is maximum index
            if( curFileIndex > lastFileIndex )
            {
                break;
            }

            // is this argument the output file name? skip it.
            if( curFileIndex == outFileIndex )
            {
                continue;
            }

            // get the input file name
            strcpy( inFileName, argv[curFileIndex] );

        }

        // if input file names come from a text file, read each one using fgets
        else if( fileNameSource == FILENAMES_FROM_TEXT_FILE )
        {
            if( (fgets( inFileName, 256, textFile )) == NULL )
            {
                // check eof vs. error here - fail for error, break for normal eof condition
                if( feof( textFile ) )
                {
                    break;  // normal eof found
                }
                else        // error
                {
                    printf( "error: ferror in fgets for text file %s\n",inFileName );
                    fclose( textFile );
                    exit(1);
                }
            }

            // get rid of any whitespace at the end of the string
            char* pTmp = inFileName + strlen(inFileName) - 1;
            while( isspace(*pTmp) )
                pTmp--;
            *(pTmp + 1) = '\0';

            lastFileIndex = curFileIndex;
        }

        // open the next input file
        if( (infile = fopen( inFileName, "rb" )) == NULL )
        {
            printf("error: unable to open input file %s\n", inFileName );
            if( textFile )
                fclose( textFile );
            exit(1);
        }

        // chunkify the input file
        printf( "Chunkifying file %s\n", inFileName );

        infilebufsize = 0;
        infilepos     = 0;

        find_sequence();
        find_GOP();

        if(curFileIndex == 1)
            prevpos = 0;
        else
            prevpos = (infilepos - 4);

        find_picture();

        do
        {
            type = find_header();

            if( (type == 0) && (curFileIndex == lastFileIndex) )
            {
                // end of file; include sequence end
                size = (infilepos - prevpos);
            }
            else
            {
                // don't include found header
                size = (infilepos - prevpos - 4);
            }

            alignsize = (((size+8)+(CHUNK_ALIGN-1)) & -CHUNK_ALIGN) - 8;
            if (alignsize > MAX_CHUNKSIZE)
            {
                printf("Chunk too large at offset %x\n", prevpos);
                exit(1);
            }

            if (verbose)
                printf("start = %08x, len = %08x\n", prevpos, size);

            chunksize = alignsize + 8;
            chunkhdr[4] = (unsigned char) (chunksize & 0xff);
            chunkhdr[5] = (unsigned char) ((chunksize >> 8) & 0xff);
            chunkhdr[6] = (unsigned char) ((chunksize >> 16) & 0xff);
            fwrite(chunkhdr, 8, 1, outFile);

            fseek(infile, prevpos, SEEK_SET);
            fread(databuf, size, 1, infile);

            {
                int i = 0;
                for( i = size; i < alignsize; ++i )
                    databuf[i] = 0;
            }

            fwrite(databuf, alignsize, 1, outFile);

            prevpos += size;
            if (type == 1)
                find_picture();

        } while(type > 0);

        fclose(infile);

    } // end for(;;)

    // clean up
    fclose(outFile);

    if( textFile )
        fclose( textFile );

    return(0);
}

//------------------------------------------------------------------------------------
