/*
 * Tomb Raider III cdaudio.wad Editor (v3.0)
 * Copyright (C) 2016  b122251
 * 
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

/*
 * cdaudio.wad File Format Specification
 * =====================================
 * 
 *	entry[130]{
 *		string Title;	// Title of the track	(260 bytes)
 *		uint32 length;	// Length of the track	(4 bytes)
 *		uint32 offset;	// Offset of the track	(4 bytes)
 *	}
 *	WAVE DATA;		// Embedded wave files	(unknown length)
 * 
 * ________________________________________________________
 * The file starts with a 130-entry index, consisting of 268 bytes per
 * entry (34840 bytes in total). Each entry consists of a 260-bytes long
 * title (in the form of a string), a 32-bit unsigned integer (length) 
 * containing the length of that track in bytes, and a 32-bit unsigned 
 * integer (offset) containing the absolute position of that wave-file
 * within cdaudio.wad. These integers are Little-Endian.
 * Following this index, the rest of the file is filled up with embedded
 * wave-files.
 */

/* File Inclusions */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <ctype.h>

/* Function Declarations */
int main(int argc, char *argv[]);
int listTracks(char *inFilePath);
int renameTrack(char *inFilePath, long int track, char *title);
int extractTrack(char *inFilePath, long int track, char *outFilePath);
int unpack(char *inFilePath, char *outPath);
int pack(char *inFilePath, char *outFilePath);
void errorMessage(char *argv[], int errorCode);

/*
 * Main function. It reads the input given by the user, 
 * starts the corresponding functions, and shows potential errors.
 * Parameters:
 *   argc=The number of command-line parameters
 *   argv=Command-line parameters
 * Return codes:
 *  -1=Insufficient number of command-line parameters
 *   0=Everything went well
 *   1-3=listTracks{
 * 	 	1=inFilePath could not be opened
 * 	 	2=Buffer could not be allocated
 * 	 	3=inFilepath is not a valid wad-file
 *   }
 *   4-6=renameTrack{
 *   	4=inFilePath could not be opened
 *   	5=inFilepath is not a valid wad-file
 *   	6=Track outside of 0-129 range
 *   }
 *   7-13=extractTrack{
 *   	7=Track outside of 0-129 range
 *   	8=inFilePath could not be opened
 *   	9=inFilepath is not a valid wad-file
 *   	10=outFilePath could not be opened
 *   	11=Buffer could not be allocated
 *   	12=Reading from inFilepath failed
 *   	13=Writing to outFilePath failed
 *   }
 *   14-19=unpack{
 *   	14=inFilePath could not be opened
 *   	15=Buffer could not be allocated
 *   	16=inFilepath is not a valid wad-file
 *   	17=Reading from inFilePath failed
 *   	18=outPath directory could not be made
 *   	19=Output index.xml could not be made
 *   }
 * 	 20-27=pack{
 * 	 	20=Buffer could not be allocated
 * 	 	21=index.xml could not be opened
 * 	 	22=index.xml is not valid
 * 	 	23=cdaudio.wad could not be opened
 * 	 	24=Writing to cdaudio.wad failed
 * 	 	25=Reading from index.xml failed
 * 	 	26=Filepath too long (>512 bytes)
 *   	27=Track outside of 0-129 range
 * 	 }
 *   2048-4095=(unpack) Extracting track failed (0000 1EEE TTTT TTTT){
 *  	1=Track outsize of 0-129 range
 *   	2=inFilePath could not be opened
 *   	3=inFilepath is not a valid wad-file
 *   	4=outFilePath could not be opened on track T
 *   	5=No buffer could be allocated
 *   	6=Read from inFilepath failed on track T
 *   	7=Write to outFilePath failed on track T
 *   }
 * 	 4096-8191=(pack)   Reading track failed (0001 00EE TTTT TTTT){
 *   	0=Failed to open file on track T
 *   	1=Reading from index.xml failed on track T
 *   	2=Writing to cdaudio.wad failed on track T
 *   }
 */
int main(int argc, char *argv[]){
	/* Variable Declarations */
	int retcode; /* Return value of the called function */
	int curChar; /* Current char in converting argv[1] to lowercase */
	
	/* Checks number of parameters */
	if (argc<3){
		errorMessage(argv,-1);
		return -1;
	}
	
	/* Converts argv[1] to lower case */
	for (curChar=0;curChar<strlen(argv[1]);curChar++)
		argv[1][curChar]=tolower(argv[1][curChar]);
	
	/* Interprets user input */
	if (!strncmp(argv[1],"list",4)){
		retcode=listTracks(argv[2]);
	} else if (!strncmp(argv[1],"rename",6)){
		if (argc<5){
			errorMessage(argv,-1);
			return -1;
		}
		retcode=renameTrack(argv[2],strtol(argv[3],NULL,10),argv[4]);
	} else if (!strncmp(argv[1],"extract",7)){
		if (argc<5){
			errorMessage(argv,-1);
			return -1;
		}
		retcode=extractTrack(argv[2],strtol(argv[3],NULL,10),argv[4]);
	} else if (!strncmp(argv[1],"unpack",6)){
		if (argc<4){
			errorMessage(argv,-1);
			return -1;
		}
		retcode=unpack(argv[2],argv[3]);
	} else if (!strncmp(argv[1],"pack",4)){
		if (argc<4){
			errorMessage(argv,-1);
			return -1;
		}
		retcode=pack(argv[2],argv[3]);
	} else {
		errorMessage(argv,-1);
		return -1;
	}
	
	/* Prints potential errors */
	if (retcode) errorMessage(argv,retcode);
	return retcode;
}

/*
 * Function that prints the titles of all tracks to the output.
 * Parameters:
 *   inFilePath=Path to cdaudio.wad
 * Return codes:
 *   0=Everything went well
 *   1=inFilePath could not be opened
 *   2=Buffer could not be allocated
 *   3=inFilepath is not a valid wad-file
 */
int listTracks(char *inFilePath){
	/* Variable Declarations */
	FILE *cdaudio; /* cdaudio file */
	char *title; /* String the title is to be read into */
	unsigned long int curpos; /* Current Position when reading */
	unsigned long int fileSize; /* Size of cdaudio.wad in bytes */
	size_t readBytes; /* Return value of fread */
	
	/* Opens cdaudio.wad */
	cdaudio=fopen(inFilePath,"rb");
	if (cdaudio==NULL) return 1;
	
	/* Determines fileSize */
	fseek(cdaudio,0,SEEK_END);
	fileSize=ftell(cdaudio);
	if (fileSize<34840) return 3;
	
	/* Allocates the title string */
	title=malloc(261);
	if (title==NULL) return 2;
	memset(title,0,261);
	
	/* Prints the titles */
	for (curpos=0;curpos<34840;curpos+=268){
		fseek(cdaudio,curpos,SEEK_SET);
		readBytes=fread(title,1,260,cdaudio);
		if (readBytes!=260) return 1;
		printf("%s\n",title);
	}
	
	/* Closes the file and returns 0 */
	fclose(cdaudio);
	free(title);
	return 0;
}

/*
 * Function that renames a track.
 * Parameters:
 *   inFilePath=Path to cdaudio.wad
 *   track=Track number (counted from 0)
 *   title=New title for this track
 * Return codes:
 *   0=Everything went well
 *   4=inFilePath could not be opened
 *   5=inFilepath is not a valid wad-file
 *   6=Track outside of 0-129 range
 */
int renameTrack(char *inFilePath, long int track, char *title){
	/* Variable Declarations */
	FILE *cdaudio; /* cdaudio file */
	int titleLength; /* Length of the title in bytes */
	unsigned long int curpos; /* Current position in file */
	unsigned long int fileSize; /* Size of cdaudio.wad in bytes */
	
	/* Opens cdaudio.wad */
	cdaudio=fopen(inFilePath,"r+b");
	if (cdaudio==NULL) return 4;
	
	/* Determines fileSize */
	fseek(cdaudio,0,SEEK_END);
	fileSize=ftell(cdaudio);
	if (fileSize<34840) return 5;
	
	/* Determines titleLength */
	titleLength=((strlen(title)>259)?259:strlen(title));
	
	/* Checks track number */
	if ((track<0)||(track>129)) return 6;
	
	/* Writes the title to the file */
	fseek(cdaudio,(track*268),SEEK_SET);
	fwrite(title,1,titleLength,cdaudio);
	
	/* Fills the rest of the title space with zeroes */
	for (curpos=(260-titleLength);curpos>0;curpos--) fputc(0,cdaudio);
	
	/* Closes the file and returns 0 */
	fclose(cdaudio);
	return 0;
}

/*
 * Function that extracts a single track file from cdaudio.wad.
 * Parameters:
 *   inFilePath=Path of cdaudio.wad
 *   track=Track number (counted from 0)
 *   outFilePath=Path to output wave file
 * Return codes:
 *   0=Everything went well
 *   7=Track outside of 0-129 range
 *   8=inFilePath could not be opened
 *   9=inFilepath is not a valid wad-file
 *   10=outFilePath could not be opened
 *   11=Buffer could not be allocated
 *   12=Reading from inFilepath failed
 *   13=Writing to outFilePath failed
 */
int extractTrack(char *inFilePath, long int track, char *outFilePath){
	/* Variable Declarations */
	FILE *cdaudio; /* cdaudio file */
	FILE *wave; /* Ouput wave-file */
	char *buffer; /* Buffer for the audio track */
	unsigned long int bufferSize; /* Length of the buffer in size */
	unsigned long int fileSize; /* Size of cdaudio.wad in bytes */
	unsigned long int startPos=0; /* Offset of current track */
	unsigned long int endPos=0; /* Ending position of current track */
	size_t readBytes; /* Return value of fread */
	size_t writtenBytes; /* Return value of fwrite */
	
	/* Opens input file */
	cdaudio=fopen(inFilePath,"rb");
	if (cdaudio==NULL) return 8;
	
	/* Determines fileSize */
	fseek(cdaudio,0,SEEK_END);
	fileSize=ftell(cdaudio);
	if (fileSize<34840) return 9;
	
	/* Checks track number */
	if ((track<0)||(track>129)) return 7;
	
	/* Allocates buffer */
	buffer=NULL;
	bufferSize=0xFFFFFF;
	do{
		buffer=malloc(bufferSize);
		if ((bufferSize==1)&&(buffer==NULL)) return 11;
		if (buffer==NULL) bufferSize>>=1;
	}while (buffer==NULL);
	
	/* Opens output file */
	wave=fopen(outFilePath,"wb");
	if (wave==NULL) return 10;
	
	/* Reads startPos and endPos */
	fseek(cdaudio,((track*268)+260),SEEK_SET);
	readBytes=fread(&endPos,1,4,cdaudio);
	if (readBytes!=4) return 12;
	readBytes=fread(&startPos,1,4,cdaudio);
	if (readBytes!=4) return 12;
	endPos+=startPos;
	
	/* Checks whether track exists */
	if (endPos>fileSize) return 9;
	
	/* Writes the track to the output file */
	fseek(cdaudio,startPos,SEEK_SET);
	while (startPos!=endPos){
		/* Checks whether the rest of the track fits inside buffer */
		if ((endPos-startPos)>bufferSize){
			/* The rest of the track does NOT fit inside buffer */
			readBytes=fread(buffer,1,bufferSize,cdaudio);
			if (readBytes!=bufferSize) return 12;
			writtenBytes=fwrite(buffer,1,bufferSize,wave);
			if (writtenBytes!=bufferSize) return 13;
			startPos+=bufferSize;
		}else{
			/* The rest of the track does fit inside buffer */
			readBytes=fread(buffer,1,(endPos-startPos),cdaudio);
			if (readBytes!=(endPos-startPos)) return 12;
			writtenBytes=fwrite(buffer,1,(endPos-startPos),wave);
			if (writtenBytes!=(endPos-startPos)) return 13;
			startPos=endPos;
		}
	}
	
	/* Closes all files and returns 0 */
	fclose(cdaudio);
	fclose(wave);
	free(buffer);
	return 0;
}

/*
 * Function that unpacks the whole cdaudio.wad file.
 * Parameters:
 *   inFilePath=Path of cdaudio.wad
 *   outPath=Path to output directory
 * Return codes:
 *   0=Everything went well
 *   14=inFilePath could not be opened
 *   15=Buffer could not be allocated
 *   16=inFilepath is not a valid wad-file
 *   17=Reading from inFilePath failed
 *   18=outPath directory could not be made
 *   19=Output index.xml could not be made
 *   2048-4095=Extracting track failed (0000 1EEE TTTT TTTT){
 *   	1=Track outside of 0-129 range
 *   	2=inFilePath could not be opened
 *   	3=inFilepath is not a valid wad-file
 *   	4=outFilePath could not be opened
 *   	5=Buffer could not be allocated
 *   	6=Read from inFilepath failed
 *   	7=Write to outFilePath failed
 *   }
 */
int unpack(char *inFilePath, char *outPath){
	/* Variable Declarations */
	FILE *cdaudio; /* cdaudio.wad input file */
	FILE *index; /* index.xml output file */
	char *title; /* Buffer for the title */
	int extRet; /* Return value of extractTrack */
	int curTrack; /* Current Track */
	int mkdirReturn; /* Return value of mkdir */
	unsigned long int curpos; /* Current Position */
	unsigned long int inFileSize; /* Size of cdaudio.wad */
	size_t readBytes; /* Return value of fread */
	
	/* Opens cdaudio.wad */
	cdaudio=fopen(inFilePath,"rb");
	if (cdaudio==NULL) return 14;
	
	/* Determines inFilesize */
	fseek(cdaudio,0,SEEK_END);
	inFileSize=ftell(cdaudio);
	if (inFileSize<34840) return 16;
	
	/* Allocates title buffer */
	title=malloc(strlen(outPath)+266);
	if (title==NULL) return 15;
	memset(title,0,strlen(outPath)+266);
	
	/* Makes output directory */
	mkdirReturn=mkdir(outPath,0755);
	if (mkdirReturn) return 18;
	
	/* Opens index.txt */
	sprintf(title,"%s/index.xml",outPath);
	index=fopen(title,"w");
	if (index==NULL) return 19;
	fprintf(index,"<cdaudio>\n");
	
	/* Extracts tracks and index */
	curTrack=0;
	for (curpos=0;curpos<34840;curpos+=268){
		/* Reads current title */
		fseek(cdaudio,curpos,SEEK_SET);
		readBytes=fread(title+4,1,260,cdaudio);
		if (readBytes!=260) return 17;
		/* Reads length of current track */
		readBytes=fread(title,1,4,cdaudio);
		if (readBytes!=4) return 17;
		/* Checks whether to write anything to index.xml */
		if (title[0]||title[1]||title[2]||title[3]||strlen(title+4)){
			/* Writes track number */
			fprintf(index,"\t<track>\n");
			fprintf(index,"\t\t<number>%i</number>\n",curTrack);
			/* Writes filepath */
			if (title[0]||title[1]||title[2]||title[3]){
				fprintf(index,"\t\t<file>%03i.wav</file>\n",curTrack);
			}
			/* Writes title */
			if (strlen(title+4)){
				fprintf(index,"\t\t<title>%s</title>\n",(title+4));
			}
			fprintf(index,"\t</track>\n");
			/* Writes the wave file if needed */
			if (title[0]||title[1]||title[2]||title[3]){
				sprintf(title,"%s/%03i.wav",outPath,curTrack);
				extRet=extractTrack(inFilePath,curTrack,title);
				if (extRet) return (0x800|(((extRet-6)&7)<<8)|curTrack);
			}
		}
		curTrack++;
	}
	fprintf(index,"</cdaudio>\n");
	
	/* Closes the files and returns */
	fclose(cdaudio);
	fclose(index);
	free(title);
	return 0;
}

/*
 * Function that makes a new cdaudio.wad file from an index.xml file.
 * Parameters:
 *   inFilePath=Path to input index.xml
 *   outFilePath=Path to output cdaudio.wad
 * Return codes:
 *   0=Everything went well         
 * 	 20=Buffer could not be allocated
 * 	 21=index.xml could not be opened
 * 	 22=index.xml is not valid
 * 	 23=cdaudio.wad could not be opened
 * 	 24=Writing to cdaudio.wad failed
 * 	 25=Reading from index.xml failed
 * 	 26=Filepath too long (>512 bytes)
 *   27=Track outside of 0-129 range
 *   4096-8191=Failed to read wave ((errorcode&0x700)>>8){
 *   	0=Failed to open file on track T
 *   	1=Reading from index.xml failed on track T
 *   	2=Writing to cdaudio.wad failed on track T
 *   }
 */
int pack(char *inFilePath, char *outFilePath){
	/* Variable Declarations */
	FILE *cdaudio; /* Output cdaudio.wad */
	FILE *index; /* Input index.xml file */
	FILE *wave; /* Input wave file */
	char *buffer; /* Buffer for general use */
	char *title; /* Buffer for titles and filepaths */
	char *pointer1; /* Pointer for general use */
	char *pointer2; /* Pointer for general use */
	unsigned int titleOffset[130]; /* Offset of title in index.xml */
	unsigned int titleLength[130]; /* Length of title */
	unsigned int filePathOffset[130]; /* Offset of path in index.xml */
	unsigned int filePathLength[130]; /* Length of path */
	unsigned long int outLength; /* Length of output cdaudio.wad */
	unsigned long int bufferSize; /* Size of the buffer in bytes */
	unsigned long int length; /* Length of current track */
	unsigned long int curpos; /* Current position */
	unsigned long int indexSize; /* Length of the index in bytes */
	unsigned long int curTrack; /* Current Track */
	size_t readBytes; /* Return value of fread */
	size_t writBytes; /* Return value of fwrite */
	
	/* Allocates buffer */
	buffer=NULL;
	bufferSize=0xFFFFFF;
	do{
		buffer=malloc(bufferSize);
		if ((bufferSize==1023)&&(buffer==NULL)) return 20;
		if (buffer==NULL) bufferSize>>=1;
	}while (buffer==NULL);
	
	/* Allocates title buffer */
	title=malloc(513);
	if (title==NULL) return 20;
	memset(title,0,513);
	
	/* Sets all lengths and offsets to 0 */
	memset(&titleOffset[0],0,(sizeof(unsigned int)*130));
	memset(&titleLength[0],0,(sizeof(unsigned int)*130));
	memset(&filePathOffset[0],0,(sizeof(unsigned int)*130));
	memset(&filePathLength[0],0,(sizeof(unsigned int)*130));
	
	/* Opens index.xml */
	index=fopen(inFilePath,"rb");
	if (index==NULL) return 21;
	fseek(index,0,SEEK_END);
	indexSize=ftell(index);
	
	/* Process index.xml */
	curpos=0;
	while (curpos!=indexSize){
		fseek(index,curpos,SEEK_SET);
		/* Checks whether rest of index fits inside buffer */
		if ((indexSize-curpos)>(bufferSize-1)){
			/* Rest of index.xml does NOT fit inside buffer */
			readBytes=fread(buffer,1,(bufferSize-1),index);
			if (readBytes!=(bufferSize-1)) return 25;
			/* Isolates track entry */
			buffer[bufferSize-1]=0;
			pointer1=strstr(buffer,"</track>");
			if (pointer1==NULL) return 22;
		}else{
			/* The rest of index.xml does fit inside buffer */
			readBytes=fread(buffer,1,(indexSize-curpos),index);
			if (readBytes!=(indexSize-curpos)) return 25;
			/* Isolates track entry */
			buffer[(indexSize-curpos)]=0;
			pointer1=strstr(buffer,"</track>");
			if (pointer1==NULL) break;
		}
		length=(pointer1-buffer)+8;
		memset(pointer1,0,1);
		/* Determines track number */
		pointer1=strstr(buffer,"<number>");
		if (pointer1==NULL) return 22;
		curTrack=strtol(pointer1+8,NULL,10);
		/* Checks track number */
		if ((curTrack<0)||(curTrack>129)) return 27;
		/* Determines title offset and length */
		pointer1=strstr(buffer,"<title>");
		pointer2=strstr(buffer,"</title>");
		if ((pointer1!=NULL)&&(pointer2!=NULL)){
			titleOffset[curTrack]=(curpos+(pointer1-buffer)+7);
			titleLength[curTrack]=((pointer2-pointer1)-7);
		}
		/* Determines filepath offset and length */
		pointer1=strstr(buffer,"<file>");
		pointer2=strstr(buffer,"</file>");
		if ((pointer1!=NULL)&&(pointer2!=NULL)){
			filePathOffset[curTrack]=(curpos+(pointer1-buffer)+6);
			filePathLength[curTrack]=((pointer2-pointer1)-6);
		}
		curpos+=length;
	}
	
	/* Opens cdaudio.wad */
	cdaudio=fopen(outFilePath,"wb");
	if (cdaudio==NULL) return 23;
	
	/* Writes an empty cdaudio.wad index */
	fseek(cdaudio,0,SEEK_SET);
	for(outLength=34840;outLength>0;outLength--) fputc(0,cdaudio);
	if (ftell(cdaudio)!=34840) return 24;
	outLength=34840;
	
	/* Adds tracks to cdaudio.wad */
	for (curTrack=0;curTrack<130;curTrack++){
		/* Checks for title */
		if (titleLength[curTrack]){
			/* Reads title from index.xml */
			if (titleLength[curTrack]>260) titleLength[curTrack]=260;
			fseek(index,titleOffset[curTrack],SEEK_SET);
			fseek(cdaudio,(curTrack*268),SEEK_SET);
			readBytes=fread(title,1,titleLength[curTrack],index);
			if (readBytes!=titleLength[curTrack]) return 25;
			/* Writes title to cdaudio.wad */
			writBytes=fwrite(title,1,titleLength[curTrack],cdaudio);
			if (writBytes!=titleLength[curTrack]) return 24;
		}
		/* Checks for wave file */
		if (filePathLength[curTrack]){
			if (filePathLength[curTrack]>512) return 26;
			/* Reads file path from index.xml */
			fseek(index,filePathOffset[curTrack],SEEK_SET);
			fseek(cdaudio,((curTrack*268)+260),SEEK_SET);
			readBytes=fread(title,1,filePathLength[curTrack],index);
			if (readBytes!=filePathLength[curTrack]) return 25;
			title[filePathLength[curTrack]]=0;
			/* Opens wave file */
			wave=fopen(title,"rb");
			if (wave==NULL) return (0x1000|curTrack);
			fseek(wave,0,SEEK_END);
			length=ftell(wave);
			/* Writes length to cdaudio.wad */
			fwrite(&length,1,4,cdaudio);
			/* Writes offset to cdaudio.wad */
			fwrite(&outLength,1,4,cdaudio);
			/* Adds wave file to cdaudio.wad */
			fseek(cdaudio,outLength,SEEK_SET);
			fseek(wave,0,SEEK_SET);
			curpos=0;
			while (curpos!=length){
				/* Checks whether rest of track fits inside buffer */
				if ((length-curpos)>bufferSize){
					/* Rest of track does NOT fit inside buffer */
					readBytes=fread(buffer,1,bufferSize,wave);
					if (readBytes!=bufferSize) return (0x1100|curTrack);
					writBytes=fwrite(buffer,1,bufferSize,cdaudio);
					if (writBytes!=bufferSize) return (0x1200|curTrack);
					outLength+=bufferSize;
					curpos+=bufferSize;
				}else{
					/* The rest of the track does fit inside buffer */
					readBytes=fread(buffer,1,(length-curpos),wave);
					if (readBytes!=(length-curpos))
						return (0x1100|curTrack);
					writBytes=fwrite(buffer,1,(length-curpos),cdaudio);
					if (writBytes!=(length-curpos))
						return (0x1200|curTrack);
					outLength+=(length-curpos);
					curpos=length;
				}
			}
			/* Closes wave file */
			fclose(wave);
		}
	}
	
	/* Closes files and returns function */
	fclose(cdaudio);
	fclose(index);
	free(buffer);
	free(title);
	return 0;
}

/*
 * Function that prints an error message if needed.
 * Parameters:
 *   argv=Command-line parameters
 *   errorCode=Error code
 */
void errorMessage(char *argv[], int errorCode){
	/* Variable Declarations */
	int freeint1; /* integer for general use */
	
	/* Processes error messages */
	if (errorCode==(-1)){
		printf("audio3: missing operands\n"
		       "Usage: \n"
		       "\taudio3 list cdaudio.wad\n"
		       "\taudio3 rename cdaudio.wad track \"New Title\"\n"
		       "\taudio3 extract cdaudio.wad track output(wave file)\n"
		       "\taudio3 unpack input(cdaudio.wad) output(directory)\n"
		       "\taudio3 pack index.xml output(cdaudio.wad)\n"
		       "\n");
	} else if ((errorCode>=1)&&(errorCode<=27)){
		switch (errorCode){
			case 1:
				printf("audio3: %s could not be opened\n",argv[2]);
				break;
			case 2:
				printf("audio3: Buffer could not be allocated\n");
				break;
			case 3:
				printf("audio3: %s is not a valid wad-file\n",argv[2]);
				break;
			case 4:
				printf("audio3: %s could not be opened\n",argv[2]);
				break;
			case 5:
				printf("audio3: %s is not a valid wad-file\n",argv[2]);
				break;
			case 6:
				printf("audio3: Track number outside of 0-129 range\n");
				break;
			case 7:
				printf("audio3: Track number outside of 0-129 range\n");
				break;
			case 8:
				printf("audio3: %s could not be opened\n",argv[2]);
				break;
			case 9:
				printf("audio3: %s is not a valid wad-file\n",argv[2]);
				break;
			case 10:
				printf("audio3: %s could not be opened\n",argv[4]);
				break;
			case 11:
				printf("audio3: Buffer could not be allocated\n");
				break;
			case 12:
				printf("audio3: Reading from %s failed\n",argv[2]);
				break;
			case 13:
				printf("audio3: Writing to %s failed\n",argv[4]);
				break;
			case 14:
				printf("audio3: %s could not be opened\n",argv[2]);
				break;
			case 15:
				printf("audio3: Buffer could not be allocated\n");
				break;
			case 16:
				printf("audio3: %s is not a valid wad-file\n",argv[2]);
				break;
			case 17:
				printf("audio3: Reading from %s failed\n",argv[2]);
				break;
			case 18:
				printf("audio3: Directory %s could not be made\n"
				       ,argv[3]);
				break;
			case 19:
				printf("audio3: %s/index.xml could not be written to\n"
				       ,argv[3]);
				break;
			case 20:
				printf("audio3: Buffer could not be allocated\n");
				break;
			case 21:
				printf("audio3: %s could not be opened\n",argv[2]);
				break;
			case 22:
				printf("audio3: %s is not valid\n",argv[2]);
				break;
			case 23:
				printf("audio3: %s could not be opened\n",argv[3]);
				break;
			case 24:
				printf("audio3: Writing to %s failed\n",argv[3]);
				break;
			case 25:
				printf("audio3: Reading from %s failed\n",argv[2]);
				break;
			case 26:
				printf("audio3: Filepath too long (>512 characters)\n");
				break;
			case 27:
				printf("audio3: Track number outside of 0-129 range\n");
				break;
		}
	} else if ((errorCode>=2048)&&(errorCode<=4095)){
		freeint1=(errorCode&0x700)>>8;
		errorCode&=0xFF;
		switch (freeint1){
			case 1:
				printf("audio3: Track number outside of 0-129 range\n");
				break;
			case 2:
				printf("audio3: %s could not be opened\n",argv[2]);
				break;
			case 3:
				printf("audio3: %s is not a valid wad-file\n",argv[2]);
				break;
			case 4:
				printf("audio3: File could not be opened on track %i\n"
				       ,freeint1);
				break;
			case 5:
				printf("audio3: Buffer could not be allocated\n");
				break;
			case 6:
				printf("audio3: Reading from %s failed\n",argv[2]);
				break;
			case 7:
				printf("audio3: Failed to extract track %i\n",freeint1);
				break;
		}
	} else if ((errorCode>=4096)&&(errorCode<=8191)){
		freeint1=(errorCode&0x700)>>8;
		errorCode&=0xFF;
		switch (freeint1){
			case 0:
				printf("audio3: File could not be opened on track %i\n"
				       ,errorCode);
				break;
			case 1:
				printf("audio3: Reading from %s failed\n",argv[2]);
				break;
			case 2:
				printf("audio3: Writing to %s failed\n",argv[3]);
				break;
		}
	}
}
