/***************************************************************************
                          ADM_Atom  -  description
                             -------------------

	Helper class to deal with atom

    begin                : Mon Jul 21 2003
    copyright            : (C) 2001 by mean
    email                : fixounet@free.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/


#include <string.h>
#include <math.h>

#include "ADM_default.h"
#include "ADM_Video.h"

#include "fourcc.h"
#include "ADM_atom.h"
#if 1
        #define aprintf(...) {}
#else
    #define aprintf printf
    #define _3G_LOGO
    #define ATOM_DEBUG
#endif

adm_atom::adm_atom(adm_atom *atom)
{
	_fd=atom->_fd;
	_atomStart=ftello(_fd);
	_atomSize=read32();
	_atomFCC=read32();
	// Gross hack for some (buggy ?) movie
	if(!_atomSize)
	{
		printf("3GP:Workaround: detected wrong sized atom!\nTrying to continue\n");
		_atomStart+=4;
		_atomSize-=4;
		fseeko(_fd,_atomStart,SEEK_SET);
		_atomSize=read32();
		_atomFCC=read32();
	}

	if ( /* fourCC::check(_atomFCC, (uint8_t *)"tadm") && */ _atomSize == 1) // extended size
	{
		_atomSize=read64();
		printf("Atom \"%s\" using extended size: %" PRIu64"\n", fourCC::tostringBE(_atomFCC), _atomSize);
		ADM_assert(_atomSize >= 16);
	} else if (_atomSize < 8)
	{
		printf("Atom \"%s\" too short: %" PRIu64", crashing.\n", fourCC::tostringBE(_atomFCC), _atomSize);
		ADM_assert(0);
	}

#ifdef ATOM_DEBUG
	dumpAtom();
#endif
}
/**
    \fn duplicate 
    \brief returns a copy of the current atom
*/
adm_atom        *adm_atom::duplicate()
{
    adm_atom *t  =new adm_atom(0);
    t->_fd       =_fd;
    t->_atomStart=_atomStart;
    t->_atomSize =_atomSize;
    t->_atomFCC  =_atomFCC;
#ifdef _3G_LOGO

#endif    
    return t;
}
/**
 * 
 * @param x
 */
adm_atom::adm_atom(int x)
{
    
}
adm_atom::adm_atom(FILE *fd )
{
int64_t orgpos;
	_fd=fd;
        orgpos=ftello(fd);
	fseeko(_fd,0,SEEK_END);
	_atomFCC=fourCC::get((uint8_t *)"MOVI");
	_atomSize=ftello(_fd);//-orgpos;

	fseeko(_fd,orgpos,SEEK_SET);
	_atomStart=0;
#ifdef ATOM_DEBUG
	dumpAtom();
#endif
#ifdef _3G_LOGO
        printf("Starting at %x  atom ",_atomStart);
        fourCC::printBE(_atomFCC);
        printf("\n");
#endif

}
bool adm_atom::skipBytes( uint32_t nb )
{
int64_t pos;
#ifdef ATOM_DEBUG
        printf("Atom: Skipping %d bytes\n",nb);
#endif

	fseeko(_fd,nb,SEEK_CUR);
	pos=ftello(_fd);
	if(pos>_atomStart+_atomSize+1)
	{
		printf("Atom: invalid attempt to skip %" PRIu32" bytes starting at offset %" PRIu64", atom \"%s\" at %" PRIu64" of size %" PRIu64"\n",
			nb, pos, fourCC::tostringBE(_atomFCC), _atomStart, _atomSize);
		ADM_assert(0);
	}
	return 1;
}

uint8_t adm_atom::read( void )
{
	uint8_t a1;

		a1=fgetc(_fd);
	return a1;

}

uint16_t adm_atom::read16( void )
{
	uint8_t a1,a2;

		a1=fgetc(_fd);
		a2=fgetc(_fd);
	return (a1<<8)+(a2);

}


uint32_t adm_atom::read32( void )
{
	uint8_t a1,a2,a3,a4;

		a1=fgetc(_fd);
		a2=fgetc(_fd);
		a3=fgetc(_fd);
		a4=fgetc(_fd);
	return (a1<<24)+(a2<<16)+(a3<<8)+(a4);

}

uint64_t adm_atom::read64( void )
{
	uint64_t a1 = read32();

	return (a1 << 32) + read32();
}

uint32_t adm_atom::getFCC( void )
{
	return _atomFCC;
}

int64_t adm_atom::getRemainingSize( void )
{
        int64_t pos=ftello(_fd);

        return _atomStart+_atomSize-pos;
}

bool adm_atom::readPayload( uint8_t *whereto, uint32_t rd)
{
	int64_t pos;

	pos=ftello(_fd);
	if(pos+rd>_atomSize+_atomStart)
	{
		printf("\n Going out of atom's bound!! (%" PRId64"  / %" PRId64" )\n",pos+rd,_atomSize+_atomStart);
		dumpAtom();
		exit(0);
	}
	uint32_t i;
	i=fread(whereto,rd,1,_fd);
	if(i!=1)
	{
		printf("\n oops asked %" PRIu32" got %" PRIu32" \n",rd,i);
	return 0;
	}
	return 1;

}
bool adm_atom::dumpAtom( void )
{

	aprintf("Atom :");
	fourCC::print(_atomFCC);
	aprintf(" starting at pos %lu, size %lu\n",_atomStart,_atomSize);
	return 1;

}

bool adm_atom::skipAtom( void )
{
	fseeko(_fd,_atomStart+_atomSize,SEEK_SET);
#ifdef _3G_LOGO
        printf("skipping to the end of atom ");
        fourCC::printBE(_atomFCC);
        printf(" at %" PRIu64"\n",_atomStart+_atomSize);
#endif
	return 1;


}
bool adm_atom::isDone( void )
{
	int64_t pos=ftello(_fd);

	if(pos>=(_atomStart+_atomSize)) return 1;
	return 0;

}




//EOF

