/*
 *TEcHNO Own Multimedia Files Parser Procedures v0.1-pre1.1-CdCat
 *Currently released under GNU LGPL Licence (or somthing like that)
 *Bla Bla, will add Later
 *
 *Currently Works on AVI's only. 
 *TODO:	-Rewrite to make scanning Linear, not Bulk
 *	-Add "bla bla" part
 *	-add idxh parser!
 *	-Control Flags
 *	-Minimise memmory usage
 *	-LIST/INFO Still not working
 *	-change that name
 *	-Warnings, hell lot of them
 *
 *FIXED:-Fixed dang LIST/INFO missing
 *	-Now returns QString (for CDCat only)
 *	-(obsolet)define some returning structure!
 *	-Quick fix for some files that didn't work correctly
 *	
 *Wonder if It gets to CdCat.
 *It maid it's way. 
 *
 *Made with kate, greates editor EVER ^__^
 *
 *Copyright Piotr "|TEcHNO|" Lewandowski, 2004
 */
//#include <iostream.h>
//#include <stdio.h>
#include <malloc.h>
#include <qstring.h>

#include "tparser.h"
#include "config.h"

/*
 *this version assumes only 2 streams in avi file, one video, one audio
 */

/*
 *FOURCC codes
 *These are reversed ie. RIFF=FFIR 
 *Do NOT change these
 */
#define RIFF 0x46464952
#define _AVI 0x20495641 /*"AVI "*/
#define LIST 0x5453494c
#define HDRL 0x6c726468
#define STRL 0x6c727473
#define STRH 0x68727473 /*Not used*/
#define VIDS 0x73646976 /*vids*/
#define AUDS 0x73647561 /*auds*/
#define MIDS 0x7364696d /*mids*/
#define TXTS 0x73747874 /*txts*/
#define STRF 0x66727473
#define JUNK 0x4b4e554a
#define ODML 0x6c6d646f
#define INFO 0x4f464e49
/*
 *Format specific fourCC's
 */
#define _div3 0x33766964
#define _DIV3 0x33564944
#define _xvid 0x64697678
#define _XVID 0x44495658
#define _divx 0x78766964
#define _DIVX 0x58564944
#define _DX50 0x30355844
#define _wmv3 0x33766d77
#define _WMV3 0x33564d57
#define _wmv2 0x32766d77
#define _wmv1 0x31766d77


/*
 *here are audio codec fourCC's
 *I've selected only the most obvious/common
 *all are taken from Mmreg.h from MSVS
 *Renaming done be me
 *UPDATE: Some new added, basing on what I 
 *found in my avi's
 */
#define WADPCM  0x0002
#define WFLOAT  0x0003
#define WMSNAU  0x0032
#define WMP3    0x0055
#define WVIVO   0x0111
#define WVIVOS  0x0112
#define WCADPCM 0x0200
#define WESSAC3 0x0241
#define WMPEG   0x0050
#define WDVM    0x2000
 
/*
 *INFOLIST header helper data
 */
#define _IART 0x54524149
#define _ICMT 0x544d4349
#define _ICOP 0x504f4349
#define _ICRD 0x44524349
#define _IENG 0x474e4549
#define _IGNR 0x524e4749
#define _INAM 0x4d414e49
#define _IPRD 0x44525049
#define _ISFT 0x54465349 
#define _ISRC 0x43525349 
#define _ISBJ 0x4a425349 
#define _ITHC 0x43485449


 
/*
 *Pointed out to me by someone on #C++ that
 *I shoudl be using:
 * const static unsigned long mids = 0x7364696d; 
 *and such, Must try it out later.
 */

/*
 *Definitions of common and/or long 
 */
#define _FPS (1000000/(float)avih.dwMicroSecPerFrame)
#define HX__ "0x%08x"
#define HXT_ "0x%08x, %c%c%c%C"
#define HXU_ "0x%08x, %u"
#define _INFOSIZE infoH.fSize+((infoH.fSize%4)==0?0:(4-infoH.fSize%4))
#define _INFOSIZE_2 infoH.fSize+((infoH.fSize%2)==0?0:(2-infoH.fSize%4))

/*
 *Global Variable
 *It shoudl NOT be done so
 */

/*
 *experimental, to be used later
 *13.IV.2004 - First test passed
 *Remeber: int and long int are 4 bytes
 *	   short int is 2 bytes long
 *         char is 1 byte long
 */
union _DWORD{
	unsigned long hex;
	char txt[4];
	}strfFourCC,strfFourCC2,listDW;

union _WORD{
	unsigned short hex;
	char txt[2];
	};

/*
 *Rather messy helper tool
 */
union _ALLC{
	unsigned long hex;
	unsigned short shex[2];
	char txt[4];
	}allc[10];

struct myStdHeader{
	_DWORD header;
	unsigned long fSize;
	_DWORD fType;
	} topHeader,listH,strl,strf,strf2,junk,junk2,list1,list2,listI,listI2;

struct srtHeader{
	_DWORD header;
	unsigned long fSize;
	}infoH;
/*
 *taken from:
 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/htm/avimainheaderstructure.asp
 *modified later. 
 *Chceck your implementation if it's 4 bytes long (sizeof(unsigned long)==4);
 */
struct avih{
	_DWORD fcc;
	unsigned long cb;
	unsigned long dwMicroSecPerFrame;
	unsigned long dwMaxBytesPerSec;
	unsigned long dwPaddingGranularity;
	unsigned long dwFlags;
	unsigned long dwTotalFrames;
	unsigned long dwInitialFrames;
	unsigned long dwStreams;
	unsigned long dwSuggestedBufferSize;
	unsigned long dwWidth;
	unsigned long dwHeight;
	unsigned long dwReserved[4];
	}avih;

/*
 *taken from:
 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/htm/avistreamheaderstructure.asp
 *and later modified.
 */
struct _avistreamheader {
	_DWORD fcc;
	unsigned long  cb;
	_DWORD fccType;
	_DWORD fccHandler;
	unsigned long  dwFlags;
	_WORD wPriority;
	_WORD wLanguage;
	unsigned long dwInitialFrames;
	unsigned long dwScale;
	unsigned long dwRate;
	unsigned long dwStart;
	unsigned long dwLength;
	unsigned long dwSuggestedBufferSize;
	long dwQuality; /*yes, this is signed data, -1==default*/
	unsigned long dwSampleSize;
	struct {
		short int left;
		short int top;
		short int right;
		short int bottom;
		}  rcFrame;
	} streamH, streamH2; /*16*/

/*
 *From:
 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/htm/waveformatexstructure.asp
 */
struct WAVEFORMATEX{ 
	_WORD  wFormatTag; 
	unsigned short  nChannels; 
	unsigned long nSamplesPerSec; 
	unsigned long nAvgBytesPerSec; 
	unsigned short nBlockAlign; 
	unsigned short wBitsPerSample; 
	unsigned short cbSize; 
	} waveH;

/*
 *All of these will be null-treminated 
 *(or some strange sequence-terminated)
 */
struct INFOLIST{
	char* IART; /*Artist*/
	char* ICMT; /*Comments*/
	char* ICOP; /*Copyrights*/
	char* ICRD; /*Creation Date*/
	char* IENG; /*Engineer*/
	char* IGNR; /*Gener*/
	char* INAM; /*Name*/
	char* IPRD; /*Product*/
	char* ISFT; /*Software*/
	char* ISRC; /*Source*/
	char* ISBJ; /*Subject*/
	char* ITHC; /*Technician*/
	} infoList; /*12*/

unsigned int allcCount=0;/*temportarily used for additional data stored after waveH*/

#include <iostream>

QString parseAviHeader(FILE* file){
	long filelength=0;
	
	fseek(file, 0L, SEEK_END);
	filelength=ftell(file);
	rewind(file); /*fseek(stream, 0L, SEEK_SET);*/
	QString ReturnData="";
	/*
	 *Load Data
	 *Since these are structs, we can point at the beginning and 
	 *overflow to other memebers.
	 */
        if(filelength-ftell(file) < (long)sizeof(unsigned long int) * (3+3+16+3+16+3))
	      return QObject::tr("Not a RIFF/AVI file OR header broken!");
	      
	fread((void*)&topHeader.header,sizeof(unsigned long int),3,file);
	if(topHeader.header.hex!=RIFF&&topHeader.fType.hex!=_AVI){
		#ifdef DoAviDebug
		ReturnData+=QObject::tr("Not a RIFF/AVI file OR header broken!"); 
		ReturnData+="\n"; 
		ReturnData+= QString("FOURCC1	= %2%3%4%5 (0x%1)\n")
			.arg(topHeader.header.hex)
			.arg(topHeader.header.txt[0])
			.arg(topHeader.header.txt[1])
			.arg(topHeader.header.txt[2])
			.arg(topHeader.header.txt[3]);
		ReturnData+="\000";
		cout << ReturnData;
		#endif
		ReturnData+="\000";
		return ReturnData;
		}
	fread((void*)&listH.header.hex,sizeof(unsigned long int),3,file);
	if(listH.header.hex!=LIST&&listH.fType.hex!=HDRL){
		#ifdef DoAviDebug
		ReturnData+=QObject::tr("Not a RIFF/AVI file OR header broken!"); 
		ReturnData+= "\n";
		ReturnData+= QString("FOURCC1	= %2%3%4%5 (0x%1)\n")
			.arg(listH.header.hex)
			.arg(listH.header.txt[0])
			.arg(listH.header.txt[1])
			.arg(listH.header.txt[2])
			.arg(listH.header.txt[3]);
		ReturnData+="\000";
		cout << ReturnData;
		#endif
		ReturnData+="\000";
		return ReturnData;
		}
	fread((void*)&avih.fcc.hex,sizeof(unsigned long int),16,file);
	fread((void*)&strl.header.hex,sizeof(unsigned long int),3,file);
	if(listH.header.hex!=LIST&&listH.fType.hex!=STRL){
		#ifdef DoAviDebug
		ReturnData+=QObject::tr("Not a RIFF/AVI file OR header broken!"); 
		ReturnData+= "\n";
		ReturnData+= QString("FOURCC1	= %1%2%3%4 (0x%5)\n")
			.arg(topHeader.header.txt[0])
			.arg(topHeader.header.txt[1])
			.arg(topHeader.header.txt[2])
			.arg(topHeader.header.txt[3])
			.arg(topHeader.header.hex);
		ReturnData+="\000";
		cout << ReturnData;
		#endif
		ReturnData+="\000";
		return ReturnData;
		}
	fread((void*)&streamH.fcc.hex,sizeof(unsigned long int),16,file);
	fread((void*)&strf.header.hex,sizeof(unsigned long int),3,file);
	/*
	 *You can also find an idxh index header
	 *Add IT!!!
	 */
	if(strf.header.hex!=STRF&&strf.fType.hex!=0x00000028){ /*Broken? 0x28=="(   "*/
		#ifdef DoAviDebug
		ReturnData+=QObject::tr("Not a RIFF/AVI file OR header broken!"); 
		ReturnData+= "\n";
		ReturnData+= QString("FOURCC1	= %1%2%3%4 (0x%5)\n")

			.arg(strf.header.txt[0])
			.arg(strf.header.txt[1])
			.arg(strf.header.txt[2])
			.arg(strf.header.txt[3])
			.arg(strf.header.hex);
		ReturnData+= QString("FOURCC2	= %1%2%3%4 (0x%5)\n")
			.arg(strf.fType.txt[0])
			.arg(strf.fType.txt[1])
			.arg(strf.fType.txt[2])
			.arg(strf.fType.txt[3])
			.arg(strf.fType.hex);
		ReturnData+="\000";
		cout << ReturnData;
		#endif
		ReturnData+="\000";
		return ReturnData;
		}
	fseek(file,12,SEEK_CUR);
        if(filelength-ftell(file) < (long)sizeof(unsigned long int) * 1)
	      return QObject::tr("Not a RIFF/AVI file OR header broken!");
	fread((void*)&strfFourCC.hex,sizeof(unsigned long int),1,file);
	fseek(file,strf.fSize-20,SEEK_CUR);
	fread((void*)&junk.header.hex,sizeof(unsigned long int),3,file);

	if(junk.header.hex!=JUNK){
		fseek(file,-12,SEEK_CUR);
		}
	else{
		fseek(file, junk.fSize-4, SEEK_CUR);
		};

        if(filelength-ftell(file) < (long)sizeof(unsigned long int) * 21)
	      return QObject::tr("Not a RIFF/AVI file OR header broken!");
	fread((void*)&list1.header.hex,sizeof(unsigned long int),3,file);
	fread((void*)&streamH2.fcc.hex,sizeof(unsigned long int),16,file);
	fread((void*)&strf2.header.hex,sizeof(unsigned long int),3,file);
	if(strf2.header.hex!=STRF){ /*Broken? 0x28=="(   "*/
		#ifdef DoAviDebug
		ReturnData+=QObject::tr("Not a RIFF/AVI file OR header broken!"); 
		ReturnData+= "\n";
		ReturnData+= QString("FOURCC1	= %1%2%3%4 (0x%5)\n")
			.arg(strf2.header.txt[0])
			.arg(strf2.header.txt[1])
			.arg(strf2.header.txt[2])
			.arg(strf2.header.txt[3])
			.arg(strf2.header.hex);
		ReturnData+= QString("FOURCC2	= %1%2%3%4 (0x%5)\n")
			.arg(strf2.fType.txt[0])
			.arg(strf2.fType.txt[1])
			.arg(strf2.fType.txt[2])
			.arg(strf2.fType.txt[3])
			.arg(strf2.fType.hex);
		ReturnData+="\000";
		cout << ReturnData;
		#endif
		ReturnData+="\000";
		return ReturnData;
		};
	fseek(file,-4,SEEK_CUR);
        if(filelength-ftell(file) < (long)sizeof(short int) * 9)
	      return QObject::tr("Not a RIFF/AVI file OR header broken!");
	fread((void*)&waveH.wFormatTag.hex,sizeof(short int),9,file);
	if(waveH.cbSize>0){
		allcCount=(waveH.cbSize/4)+(waveH.cbSize%4>0?1:0);
		int i=0;
		
		if(filelength-ftell(file) < (long)(allcCount *sizeof(long int)))
	    	    return QObject::tr("Not a RIFF/AVI file OR header broken!");
		while(i<(int)allcCount){
		        if(i>=10) break; //have to end the loop becuse we alloc the "allc" only 10 element 
			                 //(caused seg. fault. with some .avi)
			fread((void*)&allc[i].hex,sizeof(long int),1,file);
			i++;
			};
		};
	/*
	 *You can also find an idxh index header
	 *Add IT!!!
	 */
	fseek(file,-(waveH.cbSize),SEEK_CUR);/*We'll chcek it if it's Junk or Something*/
	/*
	 *everything is broken from here to writing data out
	 */
	/*
	 *Since most implementations are bad
	 *we have to seek for LIST sequence
	 *Quite Crude, but should be efficient in finding
	 *not protected against EOF and such (ie. Borken Files)
	 */
	listDW.hex=0x0;
	while(listDW.hex!=LIST){
		fread((void*)&listDW.txt[0],sizeof(char),1,file);
		if((int)listDW.txt[0]==EOF)  return ReturnData;
		if((int)listDW.txt[0]==0x4c)
		    fread((void*)&listDW.txt[1],sizeof(char),1,file);
		if((int)listDW.txt[1]==0x49){
			fread((void*)&listDW.txt[2],sizeof(char),1,file);
			};
		if((int)listDW.txt[2]==0x53){
			fread((void*)&listDW.txt[3],sizeof(char),1,file);
			};
		};
	fseek(file,-4,SEEK_CUR);
	
        if(filelength-ftell(file) < 4*3)
	      return QObject::tr("Not a RIFF/AVI file OR header broken!");
	fread((void*)&listI.header.hex,4,3,file);
	/*
	 *We skip ODML data for now
	 */
	if(listI.fType.hex==ODML){
		listDW.hex=0x00000000; /*clear data*/
		while(listDW.hex!=LIST){
			fread((void*)&listDW.txt[0],sizeof(char),1,file);
			if((int)listDW.txt[0]==EOF)  return ReturnData;      
			if((int)listDW.txt[0]==0x4c)fread((void*)&listDW.txt[1],sizeof(char),1,file);
			if((int)listDW.txt[1]==0x49){
				fread((void*)&listDW.txt[2],sizeof(char),1,file);
				};
			if((int)listDW.txt[2]==0x53){
				fread((void*)&listDW.txt[3],sizeof(char),1,file);
				};
			};
		fseek(file,-4,SEEK_CUR);
		};
	/*
	 *now we are somewhere around LIST/INFO
	 */
        if(filelength-ftell(file) < 4 * 3)
	      return QString("Broken header");
	fread((void*)&listI2.header.hex,4,3,file);
	if(listI2.fType.hex==INFO){
		while(infoH.header.hex!=JUNK&&infoH.header.hex!=LIST){
			/*
			 *Make it linear later
			 *Ten minutes later: made it, and what a hack it is ><'
			 *Two minutes later: made a better hack --' 
			 *Ten minutes later discovered it actualy fails, reverted to old version
			 *Another three minutes showed why it wasn't working
			 *Ten minutes later, donnerwetter, still fails
			 */
			infoH.header.txt[0]=infoH.header.txt[1];
			infoH.header.txt[1]=infoH.header.txt[2];
			infoH.header.txt[2]=infoH.header.txt[3];
			/*infoH.header.hex >> 1;*/ /*
						*Why it doesn't work? 
						*It does now, but it shoudl 
						*have been working with 8 
						*(ie. 8 bits, not 8 bytes)
						*Still brokem
						*/
			fread((void*)&infoH.header.txt[3],1,1,file);
			/*
			 *Too lazy to make it a separate function for it now
			 *Remember to free memory of non-NULL pointers
			 */
			switch(infoH.header.hex){
				case _IART: fread((void*)&infoH.fSize,4,1,file);
					infoList.IART=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.IART,_INFOSIZE_2,1,file);
					break;
				case _ICMT: fread((void*)&infoH.fSize,4,1,file);
					infoList.ICMT=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ICMT,_INFOSIZE_2,1,file);
					break;
				case _ICOP: fread((void*)&infoH.fSize,4,1,file);
					infoList.ICOP=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ICOP,_INFOSIZE_2,1,file);
					break;
				case _ICRD: fread((void*)&infoH.fSize,4,1,file);
					infoList.ICRD=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ICRD,_INFOSIZE_2,1,file);
					break;
				case _IENG: fread((void*)&infoH.fSize,4,1,file);
					infoList.IENG=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.IENG,_INFOSIZE_2,1,file);
					break;
				case _IGNR: fread((void*)&infoH.fSize,4,1,file);
					infoList.IGNR=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.IGNR,_INFOSIZE_2,1,file);
					break;
				case _INAM: fread((void*)&infoH.fSize,4,1,file);
					infoList.INAM=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.INAM,_INFOSIZE_2,1,file);
					break;
				case _IPRD: fread((void*)&infoH.fSize,4,1,file);
					infoList.IPRD=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.IPRD,_INFOSIZE_2,1,file);
					break;
				case _ISFT: fread((void*)&infoH.fSize,4,1,file);
					infoList.ISFT=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ISFT,_INFOSIZE_2,1,file);
					break;
				case _ISRC: fread((void*)&infoH.fSize,4,1,file);
					infoList.ISRC=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ISRC,_INFOSIZE_2,1,file);
					break;
				case _ISBJ: fread((void*)&infoH.fSize,4,1,file);
					infoList.ISBJ=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ISBJ,_INFOSIZE_2,1,file);
					break;
				case _ITHC: fread((void*)&infoH.fSize,4,1,file);	
					infoList.ITHC=(char*)calloc(_INFOSIZE_2,1);
					fread((void*)infoList.ITHC,_INFOSIZE_2,1,file);
					break;
				case JUNK: break;
				default: break;
				}
			/*
			 *if last sign is 0x0 move 2 bytes back, 
			 *if it's JUNK, leave, it may be also a miss aligned data 
			 */
			}
		};

	/*
	 *We shoudl be done by now, nothing of interests here 
	 *
	 *Here we actually write the data out, 
	 *this part can, and will be modified to print
	 *out only that what we need.
	 */
	ReturnData+=QObject::tr("Video:\n");
	ReturnData+="\n";	
	fourccSwitch(strfFourCC.hex, ReturnData);
	
	ReturnData+=QObject::tr("Total Time") + QString(" = %1:%2:%3\n").arg((unsigned long)((float)avih.dwTotalFrames/_FPS)/3600,2,10).arg(((unsigned long)((float)avih.dwTotalFrames/_FPS)/60)%60,2,10).arg((unsigned long)((float)avih.dwTotalFrames/_FPS)%60,2,10);
//	cout << "|0" <<
//	printf("%.2lu:%.2lu:%.2lu",(unsigned long)((float)avih.dwTotalFrames/_FPS)/3600,// << ":" << /*((unsigned long)((float)avih.dwTotalFrames/_FPS)/60ul)<10?"0":"" <<*/
//	((unsigned long)((float)avih.dwTotalFrames/_FPS)/60)%60,//< ":" << /*((unsigned long)((float)avih.dwTotalFrames/_FPS)%60)<ul10?"0":"" <<*/
//	(unsigned long)((float)avih.dwTotalFrames/_FPS)%60) ;
	ReturnData+=QObject::tr("Framerate")  + QString(" = %1 f/s\n").arg(_FPS,0,'f',3);
	ReturnData+=QObject::tr("Resolution") + QString(" = %1x%2\n").arg(avih.dwWidth).arg(avih.dwHeight);
	ReturnData+="\n";
	ReturnData+=QObject::tr("Audio:");	
	ReturnData+="\n";
	fourccSwitch2(waveH.wFormatTag.hex, ReturnData);
	ReturnData+=QObject::tr("Channels")  + QString(" = %1 \n").arg(waveH.nChannels);
	ReturnData+=QObject::tr("Sample/s") + QString(" = %1kHz \n").arg((float)waveH.nSamplesPerSec/1000,0,'f',1); /*use waveH.nSamplesPerSec if you want to*/
	ReturnData+=QObject::tr("Bitrate")   + QString(" = %1 kBit\n").arg((waveH.nAvgBytesPerSec*8)/1000);
	
	ReturnData+="\n";
	ReturnData+=QObject::tr("More Data:");	
	ReturnData+="\n";
	
	if(infoList.IART!=NULL)ReturnData+= QObject::tr("Artist")        + QString(" = %1\n").arg(infoList.IART);
	if(infoList.ICMT!=NULL)ReturnData+= QObject::tr("Comments")      + QString(" = %1\n").arg(infoList.ICMT);
	if(infoList.ICOP!=NULL)ReturnData+= QObject::tr("Copyright")     + QString(" = %1\n").arg(infoList.ICOP);
	if(infoList.ICRD!=NULL)ReturnData+= QObject::tr("Creation Date") + QString(" = %1\n").arg(infoList.ICRD);
	if(infoList.IENG!=NULL)ReturnData+= QObject::tr("Engineer")      + QString(" = %1\n").arg(infoList.IENG);
	if(infoList.IGNR!=NULL)ReturnData+= QObject::tr("Genre")         + QString(" = %1\n").arg(infoList.IGNR);
	if(infoList.INAM!=NULL)ReturnData+= QObject::tr("Name")          + QString(" = %1\n").arg(infoList.INAM);
	if(infoList.IPRD!=NULL)ReturnData+= QObject::tr("Product")       + QString(" = %1\n").arg(infoList.IPRD);
	if(infoList.ISFT!=NULL)ReturnData+= QObject::tr("Software")      + QString(" = %1\n").arg(infoList.ISFT);
	if(infoList.ISRC!=NULL)ReturnData+= QObject::tr("Source")        + QString(" = %1\n").arg(infoList.ISRC);
	if(infoList.ISBJ!=NULL)ReturnData+= QObject::tr("Subject")       + QString(" = %1\n").arg(infoList.ISBJ);
	if(infoList.ITHC!=NULL)ReturnData+= QObject::tr("Technician")    + QString(" = %1\n").arg(infoList.ITHC);
	
	freeINFOLIST();
	ReturnData+="\0"; //Protection?
//	cout << "\n" << ReturnData;
	return ReturnData;
	}


/*
 *This is used to print out 
 *information about found codec FourCC's
 */
void fourccSwitch(unsigned long fcc, QString &ReturnData){
	switch(fcc){
		case _DIV3:
		case _div3:ReturnData+="DivX MPEG-4 ver.3 (Low Motion)\n";
			break;
		case _DX50:ReturnData+="DivX MPEG-4 ver.5 \n";
			break;
		case _XVID:
		case _xvid:ReturnData+="XVID MPEG-4\n";
			break;
		case _DIVX:
		case _divx:ReturnData+="DivX MPEG-4 v4.x/v5.x OR OpenDivX MPEG-4 or derived from it\n";
			break;
		case _WMV3:
		case _wmv3:ReturnData+="Microsoft Windows Media Video 9\n";
			break;
		case _wmv2:ReturnData+="Microsoft Windows Media Video 8\n";
			break;
		case _wmv1:ReturnData+="Microsoft Windows Media Video 7\n";
			break;
		case 0x0:ReturnData+="Broken/Look in strf\n";
			break;
		default:ReturnData+="Unknown/not implemented/broken header\n";
		};
	}

/*
 *these are not actually fourcc's! 
 *they are 2 bytes long
 */
void fourccSwitch2(unsigned short fcc, QString &ReturnData){
	switch(fcc){
		case WADPCM:ReturnData+="Microsoft ADPCM  \n";
			break;
		case WFLOAT:ReturnData+="Microsoft IEEE-Float ADPCM \n";
			break;
		case WMSNAU:ReturnData+="Microsoft NAUDIO(?) \n";
			break;
		case WMP3:ReturnData+="ISO/MPEG Layer-3 \n";
			break;
		case WMPEG:ReturnData+="MPEG Layer-2 or MPEG Layer-3 \n";
			break;
		case WVIVO:ReturnData+="Vivo Software G.723 \n";
			break;
		case WVIVOS:ReturnData+="Vivo Software Siren \n";
			break;
		case WCADPCM:ReturnData+="Creative ADPCM \n";
			break;
		case WESSAC3:ReturnData+="ESS Technology, Inc. AC3 \n";
			break;
		case WDVM:ReturnData+="AC3 Stream OR FAST Multimedia AG DVM\n";
			break;
		default:ReturnData+=QObject::tr("Unknown/not implemented/broken header\n");
		};
	}

void freeINFOLIST(void){
	if(infoList.IART!=NULL){
		free(infoList.IART);
		infoList.IART=NULL;
		};
	if(infoList.ICMT!=NULL){
		free(infoList.ICMT);
		infoList.ICMT=NULL;
		};
	if(infoList.ICOP!=NULL){
		free(infoList.ICOP);
		infoList.ICOP=NULL;
		};
	if(infoList.ICRD!=NULL){
		free(infoList.ICRD);
		infoList.ICRD=NULL;
		};
	if(infoList.IENG!=NULL){
		free(infoList.IENG);
		infoList.IENG=NULL;
		};
	if(infoList.IGNR!=NULL){
		free(infoList.IGNR);
		infoList.IGNR=NULL;
		};
	if(infoList.INAM!=NULL){
		free(infoList.INAM);
		infoList.INAM=NULL;
		};
	if(infoList.IPRD!=NULL){
		free(infoList.IPRD);
		infoList.IPRD=NULL;
		};
	if(infoList.ISFT!=NULL){
		free(infoList.ISFT);
		infoList.ISFT=NULL;
		};
	if(infoList.ISRC!=NULL){
		free(infoList.ISRC);
		infoList.ISRC=NULL;
		};
	if(infoList.ISBJ!=NULL){
		free(infoList.ISBJ);
		infoList.ICOP=NULL;
		};
	if(infoList.ITHC!=NULL){
		free(infoList.ITHC);
		infoList.ITHC=NULL;
		};
	}
