import from SF CVS
git-svn-id: https://svn.musicpd.org/mpd/trunk@1 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
		
							
								
								
									
										15
									
								
								src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| bin_PROGRAMS = mpd | ||||
| SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR) | ||||
| mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \ | ||||
| 	song.h list.h directory.h tables.h utils.h path.h mp3_decode.h \ | ||||
| 	tag.h player.h listen.h conf.h ogg_decode.h volume.h flac_decode.h \ | ||||
| 	audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \ | ||||
| 	audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h | ||||
| mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \ | ||||
| 	song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \ | ||||
| 	tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \ | ||||
| 	audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \ | ||||
| 	audiofile_decode.c charConv.c permission.c pcm_utils.c $(mpd_headers) | ||||
|  | ||||
| mpd_CFLAGS = $(MPD_CFLAGS) | ||||
| mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) | ||||
							
								
								
									
										199
									
								
								src/audio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								src/audio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "audio.h" | ||||
| #include "conf.h" | ||||
| #include "log.h" | ||||
| #include "sig_handlers.h" | ||||
|  | ||||
| #include <string.h> | ||||
| #include <assert.h> | ||||
| #include <signal.h> | ||||
|  | ||||
| int audio_write_size; | ||||
|  | ||||
| int audio_ao_driver_id; | ||||
| ao_option * audio_ao_options; | ||||
|  | ||||
| AudioFormat audio_format; | ||||
| ao_device * audio_device = NULL; | ||||
|  | ||||
| void initAudioDriver() { | ||||
| 	ao_info * ai; | ||||
| 	char * dup; | ||||
| 	char * stk1; | ||||
| 	char * stk2; | ||||
| 	char * n1; | ||||
| 	char * key; | ||||
| 	char * value; | ||||
| 	char * test; | ||||
| 	/*int found; | ||||
| 	int i;*/ | ||||
|  | ||||
| 	audio_write_size = strtol((getConf())[CONF_AUDIO_WRITE_SIZE],&test,10); | ||||
| 	if (*test!='\0') { | ||||
| 		ERROR("\"%s\" is not a valid write size", | ||||
| 			(getConf())[CONF_AUDIO_WRITE_SIZE]); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	audio_ao_options = NULL; | ||||
|  | ||||
| 	ao_initialize(); | ||||
| 	if(strcmp(AUDIO_AO_DRIVER_DEFAULT,(getConf())[CONF_AO_DRIVER])==0) { | ||||
| 		audio_ao_driver_id = ao_default_driver_id(); | ||||
| 	} | ||||
| 	else if((audio_ao_driver_id =  | ||||
| 		ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) { | ||||
| 		ERROR("\"%s\" is not a valid ao driver\n", | ||||
| 			(getConf())[CONF_AO_DRIVER]); | ||||
| 		exit(-1); | ||||
| 	} | ||||
| 	 | ||||
| 	if((ai = ao_driver_info(audio_ao_driver_id))==NULL) { | ||||
| 		ERROR("problems getting ao_driver_info\n"); | ||||
| 		ERROR("you may not have permission to the audio device\n"); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	dup = strdup((getConf())[CONF_AO_DRIVER_OPTIONS]); | ||||
| 	if(strlen(dup)) { | ||||
| 		stk1 = NULL; | ||||
| 		n1 = strtok_r(dup,";",&stk1); | ||||
| 		while(n1) { | ||||
| 			stk2 = NULL; | ||||
| 			key = strtok_r(n1,"=",&stk2); | ||||
| 			if(!key) { | ||||
| 				ERROR("problems parsing " | ||||
| 					"ao_driver_options \"%s\"\n", n1); | ||||
| 				exit(-1); | ||||
| 			} | ||||
| 			/*found = 0; | ||||
| 			for(i=0;i<ai->option_count;i++) { | ||||
| 				if(strcmp(ai->options[i],key)==0) { | ||||
| 					found = 1; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			if(!found) { | ||||
| 				ERROR("\"%s\" is not an option for " | ||||
| 					 "\"%s\" ao driver\n",key, | ||||
| 					 ai->short_name); | ||||
| 				exit(-1); | ||||
| 			}*/ | ||||
| 			value = strtok_r(NULL,"",&stk2); | ||||
| 			if(!value) { | ||||
| 				ERROR("problems parsing " | ||||
| 					"ao_driver_options \"%s\"\n", n1); | ||||
| 				exit(-1); | ||||
| 			} | ||||
| 			ao_append_option(&audio_ao_options,key,value); | ||||
| 			n1 = strtok_r(NULL,";",&stk1); | ||||
| 		} | ||||
| 	} | ||||
| 	free(dup); | ||||
| } | ||||
|  | ||||
| void finishAudioDriver() { | ||||
| 	ao_free_options(audio_ao_options); | ||||
|  | ||||
| 	ao_shutdown(); | ||||
| } | ||||
|  | ||||
| int isCurrentAudioFormat(AudioFormat * audioFormat) { | ||||
| 	if(!audio_device) return 0; | ||||
|  | ||||
| 	if(audio_format.bits!=audioFormat->bits ||  | ||||
| 			audio_format.sampleRate!=audioFormat->sampleRate || | ||||
| 			audio_format.channels!=audioFormat->channels)  | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int initAudio(AudioFormat * audioFormat) { | ||||
| 	ao_sample_format format; | ||||
|  | ||||
| 	if(!isCurrentAudioFormat(audioFormat)) { | ||||
| 		finishAudio(); | ||||
| 	} | ||||
|  | ||||
| 	if(!audio_device) { | ||||
| 		format.bits = audioFormat->bits; | ||||
| 		format.rate = audioFormat->sampleRate; | ||||
| 		format.byte_format = AO_FMT_NATIVE; | ||||
| 		format.channels = audioFormat->channels; | ||||
| 		audio_format.bits = format.bits; | ||||
| 		audio_format.sampleRate = format.rate; | ||||
| 		audio_format.channels = format.channels; | ||||
|  | ||||
| 		blockSignals(); | ||||
|  | ||||
| 		audio_device = ao_open_live(audio_ao_driver_id, &format,  | ||||
| 					audio_ao_options); | ||||
|  | ||||
| 		if(audio_device==NULL) { | ||||
| 			unblockSignals(); | ||||
| 			audioError(); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		unblockSignals(); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void playAudio(char * playChunk, int size) { | ||||
| 	int send; | ||||
| 	 | ||||
| 	assert(audio_device!=NULL); | ||||
|  | ||||
| 	while(size>0) { | ||||
| 		send = audio_write_size>size?size:audio_write_size; | ||||
| 		 | ||||
| 		ao_play(audio_device,playChunk,send); | ||||
|  | ||||
| 		playChunk+=send; | ||||
| 		size-=send; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void finishAudio() { | ||||
| 	if(audio_device) { | ||||
| 		blockSignals(); | ||||
| 		ao_close(audio_device); | ||||
| 		audio_device = NULL; | ||||
| 		unblockSignals(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void audioError() { | ||||
| 	ERROR("Error opening audio device\n"); | ||||
| 	if(errno==AO_ENOTLIVE) { | ||||
| 		ERROR("not a live ao device\n"); | ||||
| 	} | ||||
| 	else if(errno==AO_EOPENDEVICE) { | ||||
| 		ERROR("not able to open audio device\n"); | ||||
| 	} | ||||
| 	else if(errno==AO_EBADOPTION) { | ||||
| 		ERROR("bad driver option\n"); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										50
									
								
								src/audio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/audio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef AUDIO_H | ||||
| #define AUDIO_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <ao/ao.h> | ||||
|  | ||||
| #define AUDIO_AO_DRIVER_DEFAULT	"default" | ||||
|  | ||||
| typedef struct _AudioFormat { | ||||
| 	int channels; | ||||
| 	int sampleRate; | ||||
| 	int bits; | ||||
| } AudioFormat; | ||||
|  | ||||
| extern int audio_ao_driver_id; | ||||
| extern ao_option * audio_ao_options; | ||||
|  | ||||
| void initAudioDriver(); | ||||
|  | ||||
| void finishAudioDriver(); | ||||
|  | ||||
| int initAudio(AudioFormat * audioFormat); | ||||
|  | ||||
| void playAudio(char * playChunk,int size); | ||||
|  | ||||
| void finishAudio(); | ||||
|  | ||||
| void audioError(); | ||||
|  | ||||
| int isCurrentAudioFormat(AudioFormat * audioFormat); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										138
									
								
								src/audiofile_decode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/audiofile_decode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  *  | ||||
|  * libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.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 | ||||
|  */ | ||||
|  | ||||
| #ifdef HAVE_AUDIOFILE | ||||
|  | ||||
| #include "audiofile_decode.h" | ||||
|  | ||||
| #include "command.h" | ||||
| #include "utils.h" | ||||
| #include "audio.h" | ||||
| #include "log.h" | ||||
| #include "pcm_utils.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <audiofile.h> | ||||
|  | ||||
| int getAudiofileTotalTime(char * file) | ||||
| { | ||||
| 	int time; | ||||
| 	AFfilehandle af_fp = afOpenFile(file, "r", NULL); | ||||
| 	if(af_fp == AF_NULL_FILEHANDLE) { | ||||
| 		return -1; | ||||
| 	} | ||||
| 	time = (int) | ||||
| 		((double)afGetFrameCount(af_fp,AF_DEFAULT_TRACK) | ||||
| 		 /afGetRate(af_fp,AF_DEFAULT_TRACK)); | ||||
| 	afCloseFile(af_fp); | ||||
| 	return time; | ||||
| } | ||||
|  | ||||
| int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) | ||||
| { | ||||
| 	int fs, frame_count; | ||||
| 	AFfilehandle af_fp; | ||||
| 		 | ||||
| 	af_fp = afOpenFile(dc->file,"r", NULL); | ||||
| 	if(af_fp == AF_NULL_FILEHANDLE) { | ||||
| 		ERROR("failed to open %s\n",dc->file); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	afGetSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &af->bits); | ||||
| 	af->sampleRate = (int)afGetRate(af_fp, AF_DEFAULT_TRACK); | ||||
| 	af->channels = afGetChannels(af_fp,AF_DEFAULT_TRACK); | ||||
| 	 | ||||
| 	frame_count = afGetFrameCount(af_fp,AF_DEFAULT_TRACK); | ||||
| 	 | ||||
| 	cb->totalTime = ((float)frame_count/(float)af->sampleRate); | ||||
| 	 | ||||
| 	if (af->bits != 8 && af->bits != 16) { | ||||
| 		ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n", | ||||
| 			dc->file,af->bits); | ||||
| 		afCloseFile(af_fp); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	fs = (int)afGetFrameSize(af_fp, AF_DEFAULT_TRACK,1); | ||||
|  | ||||
| 	dc->state = DECODE_STATE_DECODE; | ||||
| 	dc->start = 0; | ||||
| 	{ | ||||
| 		int ret, eof = 0, current = 0; | ||||
| 		unsigned char chunk[CHUNK_SIZE]; | ||||
|  | ||||
| 		while(!eof) { | ||||
| 			if(dc->seek) { | ||||
| 				cb->end = 0; | ||||
| 				cb->wrap = 0; | ||||
| 				current = dc->seekWhere * af->sampleRate; | ||||
| 				afSeekFrame(af_fp, AF_DEFAULT_TRACK,current); | ||||
| 				 | ||||
| 				dc->seek = 0; | ||||
| 			} | ||||
|  | ||||
| 			ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, CHUNK_SIZE/fs); | ||||
| 			if(ret<=0) eof = 1; | ||||
| 			else { | ||||
| 				while(cb->begin==cb->end && cb->wrap && | ||||
| 						!dc->stop && !dc->seek){ | ||||
| 					usleep(1000); | ||||
| 				} | ||||
| 				if(dc->stop) break; | ||||
| 				else if(dc->seek) continue; | ||||
| 				 | ||||
| #ifdef WORDS_BIGENDIAN | ||||
| 				pcm_changeBufferEndianness(chunk,CHUNK_SIZE, | ||||
| 						af->bits); | ||||
| #endif | ||||
| 				memcpy(cb->chunks+cb->end*CHUNK_SIZE,chunk, | ||||
| 						CHUNK_SIZE); | ||||
| 				cb->chunkSize[cb->end] = CHUNK_SIZE; | ||||
| 				 | ||||
| 				current += ret; | ||||
| 				cb->times[cb->end] = (float)current/(float)af->sampleRate; | ||||
| 				 | ||||
| 				++cb->end; | ||||
| 				 | ||||
| 				if(cb->end>=BUFFERED_CHUNKS) { | ||||
| 					cb->end = 0; | ||||
| 					cb->wrap = 1; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if(dc->seek) dc->seek = 0; | ||||
|  | ||||
| 		if(dc->stop) { | ||||
| 			dc->state = DECODE_STATE_STOP; | ||||
| 			dc->stop = 0; | ||||
| 		} | ||||
| 		else dc->state = DECODE_STATE_STOP; | ||||
| 	} | ||||
| 	afCloseFile(af_fp); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif /* HAVE_AUDIOFILE */ | ||||
							
								
								
									
										32
									
								
								src/audiofile_decode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/audiofile_decode.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  *  | ||||
|  * libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.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 | ||||
|  */ | ||||
|  | ||||
| #ifndef AUDIOFILE_DECODE_H | ||||
| #define AUDIOFILE_DECODE_H | ||||
|  | ||||
| #ifdef HAVE_AUDIOFILE | ||||
|  | ||||
| #include "playerData.h" | ||||
|  | ||||
| int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc); | ||||
| int getAudiofileTotalTime(char * file); | ||||
|  | ||||
| #endif /* HAVE_AUDIOFILE */ | ||||
| #endif /* AUDIOFILE_DECODE_H */ | ||||
							
								
								
									
										114
									
								
								src/buffer2array.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/buffer2array.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "buffer2array.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| int buffer2array(char * origBuffer, char *** array) { | ||||
| 	int quotes = 0; | ||||
| 	int count = 0; | ||||
| 	int i; | ||||
| 	int curr; | ||||
| 	int * beginArray; | ||||
| 	char * buffer = strdup(origBuffer); | ||||
| 	int bufferLength = strlen(buffer); | ||||
| 	char * markArray = malloc(sizeof(char)*(bufferLength+1)); | ||||
|  | ||||
| 	for(curr=0;curr<bufferLength;curr++) { | ||||
| 		if(!quotes && (buffer[curr]==' ' || buffer[curr]=='\t') ) { | ||||
| 			markArray[curr] = '0'; | ||||
| 		} | ||||
| 		else if(buffer[curr] == '\"') { | ||||
| 			if(curr>0 && buffer[curr-1]!='\\') { | ||||
| 				quotes = quotes?0:1; | ||||
| 				markArray[curr] = '0'; | ||||
| 			} | ||||
| 			else { | ||||
| 				markArray[curr] = '1'; | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			markArray[curr] = '1'; | ||||
| 		} | ||||
| 		if(markArray[curr]=='1') { | ||||
| 			if(curr>0) { | ||||
| 				if(markArray[curr-1]=='0') { | ||||
| 					count++; | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				count++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	markArray[bufferLength] = '\0'; | ||||
|  | ||||
| 	beginArray = malloc(sizeof(int)*count); | ||||
| 	(*array) = malloc(sizeof(char *)*count); | ||||
|  | ||||
| 	count = 0; | ||||
| 	 | ||||
| 	for(curr=0;curr<bufferLength;curr++) { | ||||
| 		if(markArray[curr]=='1') { | ||||
| 			if(curr>0) { | ||||
| 				if(markArray[curr-1]=='0') { | ||||
| 					beginArray[count++] = curr; | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				beginArray[count++] = curr; | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			buffer[curr] = '\0'; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for(i=0;i<count;i++) { | ||||
| 		int len = strlen(buffer+beginArray[i])+1; | ||||
| 		int arrayCurr = 0; | ||||
| 		(*array)[i] = malloc(sizeof(char)*len); | ||||
| 		for(curr=beginArray[i];buffer[curr]!='\0';curr++) { | ||||
| 			if(buffer[curr]=='\\') { | ||||
| 				if(buffer[curr+1]!='\0') { | ||||
| 					curr++; | ||||
| 				} | ||||
| 			} | ||||
| 			(*array)[i][arrayCurr++] = buffer[curr]; | ||||
| 		} | ||||
| 		(*array)[i][arrayCurr] = '\0'; | ||||
| 	} | ||||
|  | ||||
| 	free(markArray); | ||||
| 	free(beginArray); | ||||
| 	free(buffer); | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| void freeArgArray(char ** array, int argArrayLength) { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0;i<argArrayLength;i++) { | ||||
| 		free(array[i]); | ||||
| 	} | ||||
| 	free(array); | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/buffer2array.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/buffer2array.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef BUFFER_2_ARRAY_H | ||||
| #define BUFFER_2_ARRAY_H | ||||
|  | ||||
| int buffer2array(char * buffer, char *** array); | ||||
|  | ||||
| void freeArgArray(char ** array, int argArrayLength); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										99
									
								
								src/charConv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/charConv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "charConv.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef HAVE_ICONV | ||||
| #include <iconv.h> | ||||
| iconv_t char_conv_iconv; | ||||
| char * char_conv_to = NULL; | ||||
| char * char_conv_from = NULL; | ||||
| #endif | ||||
|  | ||||
| #define BUFFER_SIZE	1024 | ||||
|  | ||||
| int setCharSetConversion(char * to, char * from) { | ||||
| #ifdef HAVE_ICONV | ||||
| 	if(char_conv_to && strcmp(to,char_conv_to)==0 && | ||||
| 			char_conv_from && strcmp(from,char_conv_from)==0) | ||||
| 	{  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	closeCharSetConversion(); | ||||
|  | ||||
| 	if((char_conv_iconv = iconv_open(to,from))==(iconv_t)(-1)) return -1; | ||||
|  | ||||
| 	char_conv_to = strdup(to); | ||||
| 	char_conv_from = strdup(from); | ||||
|  | ||||
| 	return 0; | ||||
| #endif | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| char * convStrDup(char * string) { | ||||
| #ifdef HAVE_ICONV | ||||
| 	char buffer[BUFFER_SIZE]; | ||||
| 	size_t inleft = strlen(string); | ||||
| 	char * ret; | ||||
| 	size_t outleft; | ||||
| 	int retlen = 0; | ||||
| 	size_t err; | ||||
| 	char * bufferPtr; | ||||
|  | ||||
| 	if(!char_conv_to) return NULL; | ||||
|  | ||||
| 	ret = strdup(""); | ||||
|  | ||||
| 	while(inleft) { | ||||
| 		bufferPtr = buffer; | ||||
| 		outleft = BUFFER_SIZE; | ||||
| 		err = iconv(char_conv_iconv,&string,&inleft,&bufferPtr, | ||||
| 					&outleft); | ||||
| 		if(outleft==BUFFER_SIZE || (err<0 && errno!=E2BIG)) { | ||||
| 			free(ret); | ||||
| 			return NULL; | ||||
| 		} | ||||
|  | ||||
| 		ret = realloc(ret,retlen+BUFFER_SIZE-outleft+1); | ||||
| 		strncpy(&(ret[retlen]),buffer,BUFFER_SIZE-outleft); | ||||
| 		retlen+=BUFFER_SIZE-outleft; | ||||
| 		ret[retlen] = '\0'; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| #endif | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| void closeCharSetConversion() { | ||||
| #ifdef HAVE_ICONV | ||||
| 	if(char_conv_to) { | ||||
| 		iconv_close(char_conv_iconv); | ||||
| 		free(char_conv_to); | ||||
| 		free(char_conv_from); | ||||
| 		char_conv_to = NULL; | ||||
| 		char_conv_from = NULL; | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/charConv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/charConv.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef CHAR_CONV_H | ||||
| #define CHAR_CONV_H | ||||
|  | ||||
| int setCharSetConversion(char * to, char * from); | ||||
|  | ||||
| char * convStrDup(char * string); | ||||
|  | ||||
| void closeCharSetConversion(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										617
									
								
								src/command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										617
									
								
								src/command.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,617 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "command.h" | ||||
| #include "player.h" | ||||
| #include "playlist.h" | ||||
| #include "ls.h" | ||||
| #include "directory.h" | ||||
| #include "tables.h" | ||||
| #include "volume.h" | ||||
| #include "path.h" | ||||
| #include "stats.h" | ||||
| #include "myfprintf.h" | ||||
| #include "list.h" | ||||
| #include "conf.h" | ||||
| #include "permission.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #define COMMAND_PLAY            "play" | ||||
| #define COMMAND_STOP            "stop" | ||||
| #define COMMAND_PAUSE           "pause" | ||||
| #define COMMAND_STATUS          "status" | ||||
| #define COMMAND_KILL            "kill" | ||||
| #define COMMAND_CLOSE           "close" | ||||
| #define COMMAND_ADD             "add" | ||||
| #define COMMAND_DELETE          "delete" | ||||
| #define COMMAND_PLAYLIST        "playlist" | ||||
| #define COMMAND_SHUFFLE         "shuffle" | ||||
| #define COMMAND_CLEAR           "clear" | ||||
| #define COMMAND_SAVE            "save" | ||||
| #define COMMAND_LOAD            "load" | ||||
| #define COMMAND_LSINFO          "lsinfo" | ||||
| #define COMMAND_RM              "rm" | ||||
| #define COMMAND_PLAYLISTINFO    "playlistinfo" | ||||
| #define COMMAND_FIND            "find" | ||||
| #define COMMAND_SEARCH          "search" | ||||
| #define COMMAND_UPDATE          "update" | ||||
| #define COMMAND_NEXT            "next" | ||||
| #define COMMAND_PREVIOUS        "previous" | ||||
| #define COMMAND_LISTALL         "listall" | ||||
| #define COMMAND_VOLUME          "volume" | ||||
| #define COMMAND_REPEAT          "repeat" | ||||
| #define COMMAND_RANDOM          "random" | ||||
| #define COMMAND_STATS           "stats" | ||||
| #define COMMAND_CLEAR_ERROR     "clearerror" | ||||
| #define COMMAND_LIST            "list" | ||||
| #define COMMAND_MOVE            "move" | ||||
| #define COMMAND_SWAP            "swap" | ||||
| #define COMMAND_SEEK            "seek" | ||||
| #define COMMAND_LISTALLINFO	"listallinfo" | ||||
| #define COMMAND_PING		"ping" | ||||
| #define COMMAND_SETVOL		"setvol" | ||||
| #define COMMAND_PASSWORD	"password" | ||||
| #define COMMAND_CROSSFADE	"crossfade" | ||||
|  | ||||
| #define COMMAND_STATUS_VOLUME           "volume" | ||||
| #define COMMAND_STATUS_STATE            "state" | ||||
| #define COMMAND_STATUS_REPEAT           "repeat" | ||||
| #define COMMAND_STATUS_RANDOM           "random" | ||||
| #define COMMAND_STATUS_PLAYLIST         "playlist" | ||||
| #define COMMAND_STATUS_PLAYLIST_LENGTH  "playlistlength" | ||||
| #define COMMAND_STATUS_SONG             "song" | ||||
| #define COMMAND_STATUS_TIME             "time" | ||||
| #define COMMAND_STATUS_BITRATE          "bitrate" | ||||
| #define COMMAND_STATUS_ERROR            "error" | ||||
|  | ||||
| typedef int (* CommandHandlerFunction)(FILE *, unsigned int *, int, char **); | ||||
|  | ||||
| /* if min: -1 don't check args * | ||||
|  * if max: -1 no max args      */ | ||||
| typedef struct _CommandEntry { | ||||
|         char * cmd; | ||||
|         int min; | ||||
|         int max; | ||||
| 	unsigned int reqPermission; | ||||
|         CommandHandlerFunction handler; | ||||
| } CommandEntry; | ||||
|  | ||||
| List * commandList; | ||||
|  | ||||
| CommandEntry * newCommandEntry() { | ||||
|         CommandEntry * cmd = malloc(sizeof(CommandEntry)); | ||||
|         cmd->cmd = NULL; | ||||
|         cmd->min = 0; | ||||
|         cmd->max = 0; | ||||
|         cmd->handler = NULL; | ||||
| 	cmd->reqPermission = 0; | ||||
|         return cmd; | ||||
| } | ||||
|  | ||||
| void addCommand(char * name, unsigned int reqPermission, int minargs, | ||||
|                  int maxargs, CommandHandlerFunction handler_func)  | ||||
| { | ||||
|         CommandEntry * cmd = newCommandEntry(); | ||||
|         cmd->cmd = name; | ||||
|         cmd->min = minargs; | ||||
|         cmd->max = maxargs; | ||||
|         cmd->handler = handler_func; | ||||
| 	cmd->reqPermission = reqPermission; | ||||
|  | ||||
|         insertInList(commandList, cmd->cmd, cmd); | ||||
| } | ||||
|  | ||||
| int handlePlay(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int song = -1; | ||||
|         char * test; | ||||
|  | ||||
|         if(argArrayLength==2) { | ||||
|                 song = strtol(argArray[1],&test,10); | ||||
|                 if(*test!='\0') { | ||||
|                         myfprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR); | ||||
|                         return -1; | ||||
|                 } | ||||
|         } | ||||
|         return playPlaylist(fp,song,1); | ||||
| } | ||||
|  | ||||
| int handleStop(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return stopPlaylist(fp); | ||||
| } | ||||
|  | ||||
| int handlePause(FILE * fp, unsigned int * permission,  | ||||
| 		int argArrayLength, char ** argArray)  | ||||
| { | ||||
|         return playerPause(fp); | ||||
| } | ||||
|  | ||||
| int commandStatus(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         char * state = NULL; | ||||
|  | ||||
|         playPlaylistIfPlayerStopped(); | ||||
|         switch(getPlayerState()) { | ||||
|                 case PLAYER_STATE_STOP: | ||||
|                         state = strdup(COMMAND_STOP); | ||||
|                         break; | ||||
|                 case PLAYER_STATE_PAUSE: | ||||
|                         state = strdup(COMMAND_PAUSE); | ||||
|                         break; | ||||
|                 case PLAYER_STATE_PLAY: | ||||
|                         state = strdup(COMMAND_PLAY); | ||||
|                         break; | ||||
|         } | ||||
|  | ||||
|         myfprintf(fp,"%s: %i\n",COMMAND_STATUS_VOLUME,getVolumeLevel()); | ||||
|         myfprintf(fp,"%s: %i\n",COMMAND_STATUS_REPEAT,getPlaylistRepeatStatus()); | ||||
|         myfprintf(fp,"%s: %i\n",COMMAND_STATUS_RANDOM,getPlaylistRandomStatus()); | ||||
|         myfprintf(fp,"%s: %li\n",COMMAND_STATUS_PLAYLIST,getPlaylistVersion()); | ||||
|         myfprintf(fp,"%s: %i\n",COMMAND_STATUS_PLAYLIST_LENGTH,getPlaylistLength()); | ||||
|         myfprintf(fp,"%s: %s\n",COMMAND_STATUS_STATE,state); | ||||
|  | ||||
|         if(getPlayerState()!=PLAYER_STATE_STOP) { | ||||
|                 myfprintf(fp,"%s: %i\n",COMMAND_STATUS_SONG,getPlaylistCurrentSong()); | ||||
|                 myfprintf(fp,"%s: %i:%i\n",COMMAND_STATUS_TIME,getPlayerElapsedTime(),getPlayerTotalTime()); | ||||
|                 myfprintf(fp,"%s: %li\n",COMMAND_STATUS_BITRATE,getPlayerBitRate(),getPlayerTotalTime()); | ||||
|         } | ||||
|  | ||||
|         if(getPlayerError()!=PLAYER_ERROR_NOERROR) { | ||||
|                 myfprintf(fp,"%s: %s\n",COMMAND_STATUS_ERROR,getPlayerErrorStr()); | ||||
|         } | ||||
|  | ||||
|         free(state); | ||||
|  | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| int handleKill(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return COMMAND_RETURN_KILL; | ||||
| } | ||||
|  | ||||
| int handleClose(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return COMMAND_RETURN_CLOSE; | ||||
| } | ||||
|  | ||||
| int handleAdd(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         char * directory = NULL; | ||||
|  | ||||
|         if(argArrayLength == 2) directory = argArray[1]; | ||||
|         return addAllIn(fp,directory); | ||||
| } | ||||
|  | ||||
| int handleDelete(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int song; | ||||
|         char * test; | ||||
|  | ||||
|         song = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR); | ||||
|                 return -1; | ||||
|         } | ||||
|         return deleteFromPlaylist(fp,song);  | ||||
| } | ||||
|  | ||||
| int handlePlaylist(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return showPlaylist(fp); | ||||
| } | ||||
|  | ||||
| int handleShuffle(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return shufflePlaylist(fp); | ||||
| } | ||||
|  | ||||
| int handleClear(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return clearPlaylist(fp); | ||||
| } | ||||
|  | ||||
| int handleSave(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return savePlaylist(fp,argArray[1]); | ||||
| } | ||||
|  | ||||
| int handleLoad(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return loadPlaylist(fp,argArray[1]); | ||||
| } | ||||
|  | ||||
| int handleLsInfo(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         if(argArrayLength==1) { | ||||
|                 if(printDirectoryInfo(fp,NULL)<0) return -1; | ||||
|                 else return lsPlaylists(fp,""); | ||||
|         } | ||||
|         else { | ||||
|                 if(printDirectoryInfo(fp,argArray[1])<0) return -1; | ||||
|                 else return lsPlaylists(fp,argArray[1]); | ||||
|         } | ||||
| } | ||||
|  | ||||
| int handleRm(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return deletePlaylist(fp,argArray[1]); | ||||
| } | ||||
|  | ||||
| int handlePlaylistInfo(FILE * fp, unsigned int * permission,  | ||||
| 		int argArrayLength, char ** argArray)  | ||||
| { | ||||
|         int song = -1; | ||||
|         char * test; | ||||
|  | ||||
|         if(argArrayLength == 2) { | ||||
|                 song = strtol(argArray[1],&test,10); | ||||
|                 if(*test!='\0') { | ||||
|                         myfprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR); | ||||
|                         return -1; | ||||
|                 } | ||||
|         } | ||||
|         return playlistInfo(fp,song); | ||||
| } | ||||
|  | ||||
| int handleFind(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return findSongsIn(fp,NULL,argArray[1],argArray[2]); | ||||
| } | ||||
|  | ||||
| int handleSearch(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return searchForSongsIn(fp,NULL,argArray[1],argArray[2]); | ||||
| } | ||||
|  | ||||
| int handleUpdate(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return updateMp3Directory(fp); | ||||
| } | ||||
|  | ||||
| int handleNext(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return nextSongInPlaylist(fp); | ||||
| } | ||||
|  | ||||
| int handlePrevious(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return previousSongInPlaylist(fp); | ||||
| } | ||||
|  | ||||
| int handleListAll(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         char * directory = NULL; | ||||
|  | ||||
|         if(argArrayLength==2) directory = argArray[1]; | ||||
|         return printAllIn(fp,directory); | ||||
| } | ||||
|  | ||||
| int handleVolume(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int change; | ||||
|         char * test; | ||||
|  | ||||
|         change = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s need an integer\n",COMMAND_RESPOND_ERROR); | ||||
|                 return -1; | ||||
|         } | ||||
|         return changeVolumeLevel(fp,change,1); | ||||
| } | ||||
|  | ||||
| int handleSetVol(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int level; | ||||
|         char * test; | ||||
|  | ||||
|         level = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s need an integer\n",COMMAND_RESPOND_ERROR); | ||||
|                 return -1; | ||||
|         } | ||||
|         return changeVolumeLevel(fp,level,0); | ||||
| } | ||||
|  | ||||
| int handleRepeat(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int status; | ||||
|         char * test; | ||||
|  | ||||
|         status = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s need an integer\n",COMMAND_RESPOND_ERROR); | ||||
|                 return -1; | ||||
|         } | ||||
|         return setPlaylistRepeatStatus(fp,status); | ||||
| } | ||||
|  | ||||
| int handleRandom(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int status; | ||||
|         char * test; | ||||
|  | ||||
|         status = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s need an integer\n",COMMAND_RESPOND_ERROR); | ||||
|                 return -1; | ||||
|         } | ||||
|         return setPlaylistRandomStatus(fp,status); | ||||
| } | ||||
|  | ||||
| int handleStats(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return printStats(fp); | ||||
| } | ||||
|  | ||||
| int handleClearError(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         clearPlayerError(); | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| int handleList(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         char * arg1 = NULL; | ||||
|  | ||||
|         if(argArrayLength==3) arg1 = argArray[2]; | ||||
|         return printAllKeysOfTable(fp,argArray[1],arg1); | ||||
| } | ||||
|  | ||||
| int handleMove(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int from; | ||||
|         int to; | ||||
|         char * test; | ||||
|  | ||||
|         from = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[1]); | ||||
|                 return -1; | ||||
|         } | ||||
|         to = strtol(argArray[2],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[2]); | ||||
|                 return -1; | ||||
|         } | ||||
|         return moveSongInPlaylist(fp,from,to); | ||||
| } | ||||
|  | ||||
| int handleSwap(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int song1; | ||||
|         int song2; | ||||
|         char * test; | ||||
|  | ||||
|         song1 = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[1]); | ||||
|                 return -1; | ||||
|         } | ||||
|         song2 = strtol(argArray[2],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[2]); | ||||
|                 return -1; | ||||
|         } | ||||
|         return swapSongsInPlaylist(fp,song1,song2); | ||||
| } | ||||
|  | ||||
| int handleSeek(FILE * fp, unsigned int * permission, int argArrayLength, | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int song; | ||||
|         int time; | ||||
|         char * test; | ||||
|  | ||||
|         song = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[1]); | ||||
|                 return -1; | ||||
|         } | ||||
|         time = strtol(argArray[2],&test,10); | ||||
|         if(*test!='\0') { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[2]); | ||||
|                 return -1; | ||||
|         } | ||||
|         return seekSongInPlaylist(fp,song,time); | ||||
| } | ||||
|  | ||||
| int handleListAllInfo(FILE * fp, unsigned int * permission, int argArrayLength, | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         char * directory = NULL; | ||||
|  | ||||
|         if(argArrayLength==2) directory = argArray[1]; | ||||
|         return printInfoForAllIn(fp,directory); | ||||
| } | ||||
|  | ||||
| int handlePing(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| int handlePassword(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
| 	if(getPermissionFromPassword(argArray[1],permission)<0) { | ||||
| 		myfprintf(fp,"%s incorrect password\n",COMMAND_RESPOND_ERROR); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int handleCrossfade(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         int time; | ||||
|         char * test; | ||||
|  | ||||
| 	if(argArrayLength==1) { | ||||
| 		myfprintf(fp,"crossfade: %i\n",(int)(getPlayerCrossFade())); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|         time = strtol(argArray[1],&test,10); | ||||
|         if(*test!='\0' || time<0) { | ||||
|                 myfprintf(fp,"%s \"%s\" is not a integer >= 0\n", | ||||
|                                 COMMAND_RESPOND_ERROR,argArray[1]); | ||||
|                 return -1; | ||||
|         } | ||||
|  | ||||
| 	setPlayerCrossFade(time); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void initCommands() { | ||||
|         commandList = makeList(free); | ||||
|  | ||||
|         addCommand(COMMAND_PLAY        ,PERMISSION_CONTROL, 0, 1,handlePlay); | ||||
|         addCommand(COMMAND_STOP        ,PERMISSION_CONTROL, 0, 0,handleStop); | ||||
|         addCommand(COMMAND_PAUSE       ,PERMISSION_CONTROL, 0, 0,handlePause); | ||||
|         addCommand(COMMAND_STATUS      ,PERMISSION_READ,    0, 0,commandStatus); | ||||
|         addCommand(COMMAND_KILL        ,PERMISSION_ADMIN,  -1,-1,handleKill); | ||||
|         addCommand(COMMAND_CLOSE       ,0,                 -1,-1,handleClose); | ||||
|         addCommand(COMMAND_ADD         ,PERMISSION_ADD,     0, 1,handleAdd); | ||||
|         addCommand(COMMAND_DELETE      ,PERMISSION_CONTROL, 1, 1,handleDelete); | ||||
|         addCommand(COMMAND_PLAYLIST    ,PERMISSION_READ,    0, 0,handlePlaylist); | ||||
|         addCommand(COMMAND_SHUFFLE     ,PERMISSION_CONTROL, 0, 0,handleShuffle); | ||||
|         addCommand(COMMAND_CLEAR       ,PERMISSION_CONTROL, 0, 0,handleClear); | ||||
|         addCommand(COMMAND_SAVE        ,PERMISSION_CONTROL, 1, 1,handleSave); | ||||
|         addCommand(COMMAND_LOAD        ,PERMISSION_ADD,     1, 1,handleLoad); | ||||
|         addCommand(COMMAND_LSINFO      ,PERMISSION_READ,    0, 1,handleLsInfo); | ||||
|         addCommand(COMMAND_RM          ,PERMISSION_CONTROL, 1, 1,handleRm); | ||||
|         addCommand(COMMAND_PLAYLISTINFO,PERMISSION_READ,    0, 1,handlePlaylistInfo); | ||||
|         addCommand(COMMAND_FIND        ,PERMISSION_READ,    2, 2,handleFind); | ||||
|         addCommand(COMMAND_SEARCH      ,PERMISSION_READ,    2, 2,handleSearch); | ||||
|         addCommand(COMMAND_UPDATE      ,PERMISSION_ADMIN,   0, 0,handleUpdate); | ||||
|         addCommand(COMMAND_NEXT        ,PERMISSION_CONTROL, 0, 0,handleNext); | ||||
|         addCommand(COMMAND_PREVIOUS    ,PERMISSION_CONTROL, 0, 0,handlePrevious); | ||||
|         addCommand(COMMAND_LISTALL     ,PERMISSION_READ,    0, 1,handleListAll); | ||||
|         addCommand(COMMAND_VOLUME      ,PERMISSION_CONTROL, 1, 1,handleVolume); | ||||
|         addCommand(COMMAND_REPEAT      ,PERMISSION_CONTROL, 1, 1,handleRepeat); | ||||
|         addCommand(COMMAND_RANDOM      ,PERMISSION_CONTROL, 1, 1,handleRandom); | ||||
|         addCommand(COMMAND_STATS       ,PERMISSION_READ,    0, 0,handleStats); | ||||
|         addCommand(COMMAND_CLEAR_ERROR ,PERMISSION_CONTROL, 0, 0,handleClearError); | ||||
|         addCommand(COMMAND_LIST        ,PERMISSION_READ,    1, 2,handleList); | ||||
|         addCommand(COMMAND_MOVE        ,PERMISSION_CONTROL, 2, 2,handleMove); | ||||
|         addCommand(COMMAND_SWAP        ,PERMISSION_CONTROL, 2, 2,handleSwap); | ||||
|         addCommand(COMMAND_SEEK        ,PERMISSION_CONTROL, 2, 2,handleSeek); | ||||
|         addCommand(COMMAND_LISTALLINFO ,PERMISSION_READ,    0, 1,handleListAllInfo); | ||||
|         addCommand(COMMAND_PING        ,0,                  0, 0,handlePing); | ||||
|         addCommand(COMMAND_SETVOL      ,PERMISSION_CONTROL, 1, 1,handleSetVol); | ||||
|         addCommand(COMMAND_PASSWORD    ,0,                  1, 1,handlePassword); | ||||
|         addCommand(COMMAND_CROSSFADE   ,PERMISSION_CONTROL, 0, 1,handleCrossfade); | ||||
|  | ||||
|         sortList(commandList); | ||||
| } | ||||
|  | ||||
| void finishCommands() { | ||||
|         freeList(commandList); | ||||
| } | ||||
|  | ||||
| int checkArgcAndPermission(CommandEntry * cmd, FILE *fp,  | ||||
| 		unsigned int permission, int argc, char** argArray) | ||||
| { | ||||
|         int min = cmd->min + 1; | ||||
|         int max = cmd->max + 1; | ||||
|  | ||||
| 	if (cmd->reqPermission != (permission & cmd->reqPermission)) { | ||||
|                 myfprintf(fp,"%s You don't have permission for \"%s\"\n",COMMAND_RESPOND_ERROR,cmd->cmd); | ||||
|                 return -1; | ||||
| 	} | ||||
|  | ||||
|         if (min == 0) return 0; | ||||
|  | ||||
|         if (min == max && max != argc) { | ||||
|                 myfprintf(fp,"%s Wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); | ||||
|                 return -1; | ||||
|         } | ||||
|         else if (argc < min) { | ||||
|                 myfprintf(fp,"%s too few arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); | ||||
|                 return -1; | ||||
|         } | ||||
|         else if (argc > max && max /* != 0 */) { | ||||
|                 myfprintf(fp,"%s too many arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); | ||||
|                 return -1; | ||||
|         } | ||||
|         else return 0; | ||||
| } | ||||
|  | ||||
| int processCommand(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray)  | ||||
| { | ||||
|         CommandEntry * cmd; | ||||
|  | ||||
|         if(argArrayLength == 0) return 0; | ||||
|  | ||||
|         if(!findInList(commandList, argArray[0],(void *)&cmd)) { | ||||
|                 myfprintf(fp,"%s Unknown command \"%s\"\n",COMMAND_RESPOND_ERROR, | ||||
|                                 argArray[0]); | ||||
|                 return -1; | ||||
|         } | ||||
|  | ||||
|         if(checkArgcAndPermission(cmd, fp, *permission, argArrayLength,  | ||||
| 			argArray) < 0)  | ||||
| 	{ | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|         return cmd->handler(fp, permission, argArrayLength, argArray); | ||||
| } | ||||
							
								
								
									
										37
									
								
								src/command.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/command.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef COMMAND_H | ||||
| #define COMMAND_H | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #define COMMAND_RETURN_KILL	10 | ||||
| #define COMMAND_RETURN_CLOSE	20 | ||||
|  | ||||
| #define COMMAND_RESPOND_ERROR	"ACK" | ||||
| #define COMMAND_RESPOND_OK	"OK" | ||||
|  | ||||
| int processCommand(FILE * fp, unsigned int * permission, int argArrayLength,  | ||||
| 		char ** argArray); | ||||
|  | ||||
| void initCommands(); | ||||
|  | ||||
| void finishCommands(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										221
									
								
								src/conf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								src/conf.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "conf.h" | ||||
|  | ||||
| #include "log.h" | ||||
|  | ||||
| #include "utils.h" | ||||
| #include "buffer2array.h" | ||||
| #include "audio.h" | ||||
| #include "volume.h" | ||||
|  | ||||
| #include <sys/param.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define MAX_STRING_SIZE	MAXPATHLEN+80 | ||||
|  | ||||
| #define CONF_COMMENT	'#' | ||||
|  | ||||
| #define CONF_NUMBER_OF_PARAMS		27 | ||||
| #define CONF_NUMBER_OF_PATHS		6 | ||||
| #define CONF_NUMBER_OF_REQUIRED		5 | ||||
| #define CONF_NUMBER_OF_ALLOW_CATS	1 | ||||
|  | ||||
| #define CONF_CONNECTION_TIMEOUT_DEFAULT			"60" | ||||
| #define CONF_MAX_CONNECTIONS_DEFAULT			"5" | ||||
| #define CONF_MAX_PLAYLIST_LENGTH_DEFAULT		"4096" | ||||
| #define CONF_BUFFER_BEFORE_PLAY_DEFAULT			"25%" | ||||
| #define CONF_MAX_COMMAND_LIST_SIZE_DEFAULT		"2048" | ||||
| #define CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT		"2048" | ||||
| #define CONF_AO_DRIVER_DEFAULT				AUDIO_AO_DRIVER_DEFAULT | ||||
| #define CONF_AO_DRIVER_OPTIONS_DEFAULT			"" | ||||
| #define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT	"no" | ||||
| #define CONF_BIND_TO_ADDRESS_DEFAULT			"any" | ||||
| #define CONF_USER_DEFAULT				"" | ||||
| #define CONF_LOG_LEVEL_DEFAULT				"default" | ||||
| #define CONF_AUDIO_WRITE_SIZE_DEFAULT			"1024" | ||||
| #define CONF_BUFFER_SIZE_DEFAULT			"2048" | ||||
| #ifndef NO_OSS_MIXER | ||||
| #define CONF_MIXER_TYPE_DEFAULT				VOLUME_MIXER_OSS | ||||
| #define CONF_MIXER_DEVICE_DEFAULT			"" | ||||
| #else | ||||
| #ifdef HAVE_ALSA | ||||
| #define CONF_MIXER_TYPE_DEFAULT				VOLUME_MIXER_ALSA | ||||
| #define CONF_MIXER_DEVICE_DEFAULT			"" | ||||
| #else | ||||
| #define CONF_MIXER_TYPE_DEFAULT				VOLUME_MIXER_NULL | ||||
| #define CONF_MIXER_DEVICE_DEFAULT			"" | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| char * conf_params[CONF_NUMBER_OF_PARAMS]; | ||||
|  | ||||
| void initConf() { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) conf_params[i] = NULL; | ||||
|  | ||||
| 	/* we don't specify these on the command line */ | ||||
| 	conf_params[CONF_CONNECTION_TIMEOUT] = strdup(CONF_CONNECTION_TIMEOUT_DEFAULT); | ||||
| 	conf_params[CONF_MIXER_DEVICE] = strdup(CONF_MIXER_DEVICE_DEFAULT); | ||||
| 	conf_params[CONF_MAX_CONNECTIONS] = strdup(CONF_MAX_CONNECTIONS_DEFAULT); | ||||
| 	conf_params[CONF_MAX_PLAYLIST_LENGTH] = strdup(CONF_MAX_PLAYLIST_LENGTH_DEFAULT); | ||||
| 	conf_params[CONF_BUFFER_BEFORE_PLAY] = strdup(CONF_BUFFER_BEFORE_PLAY_DEFAULT); | ||||
| 	conf_params[CONF_MAX_COMMAND_LIST_SIZE] = strdup(CONF_MAX_COMMAND_LIST_SIZE_DEFAULT); | ||||
| 	conf_params[CONF_MAX_OUTPUT_BUFFER_SIZE] = strdup(CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT); | ||||
| 	conf_params[CONF_AO_DRIVER] = strdup(CONF_AO_DRIVER_DEFAULT); | ||||
| 	conf_params[CONF_AO_DRIVER_OPTIONS] = strdup(CONF_AO_DRIVER_OPTIONS_DEFAULT); | ||||
| 	conf_params[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS] = strdup(CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT); | ||||
| 	conf_params[CONF_BIND_TO_ADDRESS] = strdup(CONF_BIND_TO_ADDRESS_DEFAULT); | ||||
| 	conf_params[CONF_MIXER_TYPE] = strdup(CONF_MIXER_TYPE_DEFAULT); | ||||
| 	conf_params[CONF_USER] = strdup(CONF_USER_DEFAULT); | ||||
| 	conf_params[CONF_LOG_LEVEL] = strdup(CONF_LOG_LEVEL_DEFAULT); | ||||
| 	conf_params[CONF_AUDIO_WRITE_SIZE] = strdup(CONF_AUDIO_WRITE_SIZE_DEFAULT); | ||||
| 	conf_params[CONF_BUFFER_SIZE] = strdup(CONF_BUFFER_SIZE_DEFAULT); | ||||
| } | ||||
|  | ||||
| char ** readConf(char * file) { | ||||
| 	char * conf_strings[CONF_NUMBER_OF_PARAMS] = { | ||||
| 		"port", | ||||
| 		"music_directory", | ||||
| 		"playlist_directory", | ||||
| 		"log_file", | ||||
| 		"error_file", | ||||
| 		"connection_timeout", | ||||
| 		"mixer_device", | ||||
| 		"max_connections", | ||||
| 		"max_playlist_length", | ||||
| 		"buffer_before_play", | ||||
| 		"max_command_list_size", | ||||
| 		"max_output_buffer_size", | ||||
| 		"ao_driver", | ||||
| 		"ao_driver_options", | ||||
| 		"save_absolute_paths_in_playlists", | ||||
| 		"bind_to_address", | ||||
| 		"mixer_type", | ||||
| 		"state_file", | ||||
| 		"user", | ||||
| 		"db_file", | ||||
| 		"log_level", | ||||
| 		"mixer_control", | ||||
| 		"audio_write_size", | ||||
| 		"filesystem_charset", | ||||
| 		"password", | ||||
| 		"default_permissions", | ||||
| 		"buffer_size" | ||||
| 	}; | ||||
|  | ||||
| 	int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { | ||||
| 		CONF_MUSIC_DIRECTORY, | ||||
| 		CONF_PLAYLIST_DIRECTORY, | ||||
| 		CONF_LOG_FILE, | ||||
| 		CONF_ERROR_FILE, | ||||
| 		CONF_STATE_FILE, | ||||
| 		CONF_DB_FILE | ||||
| 	}; | ||||
|  | ||||
| 	int conf_required[CONF_NUMBER_OF_REQUIRED] = { | ||||
| 		CONF_MUSIC_DIRECTORY, | ||||
| 		CONF_PLAYLIST_DIRECTORY, | ||||
| 		CONF_LOG_FILE, | ||||
| 		CONF_ERROR_FILE, | ||||
| 		CONF_PORT | ||||
| 	}; | ||||
|  | ||||
| 	short conf_allowCat[CONF_NUMBER_OF_ALLOW_CATS] = { | ||||
| 		CONF_PASSWORD | ||||
| 	}; | ||||
|  | ||||
| 	FILE * fp; | ||||
| 	char string[MAX_STRING_SIZE+1]; | ||||
| 	char ** array; | ||||
| 	int i; | ||||
| 	int numberOfArgs; | ||||
| 	short allowCat[CONF_NUMBER_OF_PARAMS]; | ||||
|  | ||||
| 	for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) allowCat[i] = 0; | ||||
|  | ||||
| 	for(i=0;i<CONF_NUMBER_OF_ALLOW_CATS;i++) allowCat[conf_allowCat[i]] = 1; | ||||
|  | ||||
| 	if(!(fp=fopen(file,"r"))) { | ||||
| 		ERROR("problems opening file %s for reading\n",file); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	while(myFgets(string,sizeof(string),fp)) { | ||||
| 		if(string[0]==CONF_COMMENT) continue; | ||||
| 		numberOfArgs = buffer2array(string,&array); | ||||
| 		if(numberOfArgs==0) continue; | ||||
| 		if(2!=numberOfArgs) { | ||||
| 			ERROR("need two args in conf at: %s\n",string); | ||||
| 			exit(-1); | ||||
| 		} | ||||
| 		i = 0; | ||||
| 		while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++; | ||||
| 		if(i>=CONF_NUMBER_OF_PARAMS) { | ||||
| 			ERROR("unrecognized line in conf: %s\n",string); | ||||
| 			exit(-1); | ||||
| 		} | ||||
| 		if(conf_params[i]!=NULL) { | ||||
| 			if(allowCat[i]) { | ||||
| 				conf_params[i] = realloc(conf_params[i], | ||||
| 						strlen(conf_params[i])+ | ||||
| 						strlen(CONF_CAT_CHAR)+ | ||||
| 						strlen(array[1])+1); | ||||
| 				strcat(conf_params[i],CONF_CAT_CHAR); | ||||
| 				strcat(conf_params[i],array[1]); | ||||
| 			} | ||||
| 			else { | ||||
| 				free(conf_params[i]); | ||||
| 				conf_params[i] = strdup(array[1]); | ||||
| 			} | ||||
| 		} | ||||
| 		else conf_params[i] = strdup(array[1]); | ||||
| 		free(array[0]); | ||||
| 		free(array[1]); | ||||
| 		free(array); | ||||
| 	} | ||||
|  | ||||
| 	fclose(fp); | ||||
|  | ||||
| 	for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) { | ||||
| 		if(conf_params[conf_required[i]] == NULL) { | ||||
| 			ERROR("%s is unassigned in conf file\n", | ||||
| 					conf_strings[conf_required[i]]); | ||||
| 			exit(-1); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for(i=0;i<CONF_NUMBER_OF_PATHS;i++) { | ||||
| 		if(conf_params[conf_absolutePaths[i]] &&  | ||||
| 			conf_params[conf_absolutePaths[i]][0]!='/') { | ||||
| 			ERROR("\"%s\" is not an absolute path\n", | ||||
| 					conf_params[conf_absolutePaths[i]]); | ||||
| 			exit(-1); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return conf_params; | ||||
| } | ||||
|  | ||||
| char ** getConf() { | ||||
| 	return conf_params; | ||||
| } | ||||
							
								
								
									
										61
									
								
								src/conf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/conf.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef CONF_H | ||||
| #define CONF_H | ||||
|  | ||||
| #define CONF_PORT				0 | ||||
| #define CONF_MUSIC_DIRECTORY			1 | ||||
| #define CONF_PLAYLIST_DIRECTORY			2 | ||||
| #define CONF_LOG_FILE				3 | ||||
| #define CONF_ERROR_FILE				4 | ||||
| #define CONF_CONNECTION_TIMEOUT			5 | ||||
| #define CONF_MIXER_DEVICE			6 | ||||
| #define CONF_MAX_CONNECTIONS			7 | ||||
| #define CONF_MAX_PLAYLIST_LENGTH		8 | ||||
| #define CONF_BUFFER_BEFORE_PLAY			9 | ||||
| #define CONF_MAX_COMMAND_LIST_SIZE		10 | ||||
| #define CONF_MAX_OUTPUT_BUFFER_SIZE		11 | ||||
| #define CONF_AO_DRIVER				12 | ||||
| #define CONF_AO_DRIVER_OPTIONS			13 | ||||
| #define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS	14 | ||||
| #define CONF_BIND_TO_ADDRESS			15 | ||||
| #define CONF_MIXER_TYPE				16 | ||||
| #define CONF_STATE_FILE				17 | ||||
| #define CONF_USER				18 | ||||
| #define CONF_DB_FILE				19 | ||||
| #define CONF_LOG_LEVEL				20 | ||||
| #define CONF_MIXER_CONTROL			21 | ||||
| #define CONF_AUDIO_WRITE_SIZE			22 | ||||
| #define CONF_FS_CHARSET				23 | ||||
| #define CONF_PASSWORD				24 | ||||
| #define CONF_DEFAULT_PERMISSIONS		25 | ||||
| #define CONF_BUFFER_SIZE			26 | ||||
|  | ||||
| #define CONF_CAT_CHAR				"\n" | ||||
|  | ||||
| /* do not free the return value, it is a static variable */ | ||||
| char ** readConf(char * file); | ||||
|  | ||||
| char ** getConf(); | ||||
|  | ||||
| void initConf(); | ||||
|  | ||||
| void writeConf(char * file); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										456
									
								
								src/decode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										456
									
								
								src/decode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,456 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "decode.h" | ||||
| #include "player.h" | ||||
| #include "playerData.h" | ||||
| #include "utils.h" | ||||
| #include "pcm_utils.h" | ||||
| #include "audio.h" | ||||
| #include "path.h" | ||||
| #include "log.h" | ||||
|  | ||||
| #ifdef HAVE_MAD | ||||
| #include "mp3_decode.h" | ||||
| #endif | ||||
| #ifdef HAVE_OGG | ||||
| #include "ogg_decode.h" | ||||
| #endif | ||||
| #ifdef HAVE_FLAC | ||||
| #include "flac_decode.h" | ||||
| #endif | ||||
| #ifdef HAVE_AUDIOFILE | ||||
| #include "audiofile_decode.h" | ||||
| #endif | ||||
|  | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define FADE_CHUNKS	1024 | ||||
|  | ||||
| int decode_pid = 0; | ||||
|  | ||||
| void decodeSigHandler(int sig) { | ||||
| 	if(sig==SIGCHLD) { | ||||
| 		int status; | ||||
| 		if(decode_pid==wait3(&status,WNOHANG,NULL)) { | ||||
| 			if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) { | ||||
| 				ERROR("decode process died from a " | ||||
| 						"non-TERM signal: %i\n", | ||||
| 						WTERMSIG(status)); | ||||
| 			} | ||||
| 			decode_pid = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	else if(sig==SIGTERM) { | ||||
| 		int pid = decode_pid; | ||||
| 		if(pid>0) kill(pid,SIGTERM); | ||||
| 		exit(0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void stopDecode(DecoderControl * dc) { | ||||
| 	if(decode_pid>0 && (dc->start || dc->state==DECODE_STATE_DECODE)) { | ||||
| 		dc->stop = 1; | ||||
| 		while(decode_pid>0 && dc->stop) usleep(10); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void quitDecode(PlayerControl * pc, DecoderControl * dc) { | ||||
| 	stopDecode(dc); | ||||
| 	pc->state = PLAYER_STATE_STOP; | ||||
| 	pc->play = 0; | ||||
| 	pc->stop = 0; | ||||
| 	pc->pause = 0; | ||||
| 	kill(getppid(),SIGUSR1); | ||||
| } | ||||
|  | ||||
| int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) { | ||||
| 	int chunks; | ||||
|  | ||||
| 	if(pc->crossFade<=0) return 0; | ||||
|  | ||||
| 	chunks = (af->sampleRate*af->bits*af->channels/8.0/CHUNK_SIZE); | ||||
| 	chunks = (chunks*pc->crossFade+0.5); | ||||
|  | ||||
| 	if(chunks>BUFFERED_CHUNKS-buffered_before_play) { | ||||
| 		chunks = BUFFERED_CHUNKS-buffered_before_play; | ||||
| 	} | ||||
|  | ||||
| 	return chunks; | ||||
| } | ||||
|  | ||||
| int waitOnDecode(PlayerControl * pc, AudioFormat * af, DecoderControl * dc, | ||||
| 		Buffer * cb)  | ||||
| { | ||||
| 	while(decode_pid>0 && dc->start) usleep(10); | ||||
|  | ||||
| 	if(dc->start || dc->error!=DECODE_ERROR_NOERROR) { | ||||
| 		strcpy(pc->erroredFile,pc->file); | ||||
| 		pc->error = PLAYER_ERROR_FILE; | ||||
| 		quitDecode(pc,dc); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if(initAudio(af)<0) { | ||||
| 		strcpy(pc->erroredFile,pc->file); | ||||
| 		pc->error = PLAYER_ERROR_AUDIO; | ||||
| 		quitDecode(pc,dc); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	pc->elapsedTime = 0; | ||||
| 	pc->bitRate = 0; | ||||
| 	pc->totalTime = cb->totalTime; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void decodeSeek(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,  | ||||
| 		Buffer * cb)  | ||||
| { | ||||
| 	if(decode_pid>0) { | ||||
| 		cb->next = -1; | ||||
| 		if(dc->state!=DECODE_STATE_DECODE || dc->error ||  | ||||
| 				strcmp(dc->file,pc->file)!=0)  | ||||
| 		{ | ||||
| 			stopDecode(dc); | ||||
| 			cb->end = 0; | ||||
| 			dc->error = 0; | ||||
| 			dc->start = 1; | ||||
| 			dc->error = 0; | ||||
| 			waitOnDecode(pc,af,dc,cb); | ||||
| 		} | ||||
| 		if(decode_pid>0 && dc->state==DECODE_STATE_DECODE) { | ||||
| 			dc->seekWhere = pc->seekWhere > pc->totalTime-1 ? | ||||
| 						pc->totalTime-1 : pc->seekWhere; | ||||
| 			dc->seekWhere = 1 > dc->seekWhere ? 1 : dc->seekWhere; | ||||
| 			cb->begin = 0; | ||||
| 			dc->seek = 1; | ||||
| 			pc->elapsedTime = dc->seekWhere; | ||||
| 			pc->bitRate = 0; | ||||
| 			while(decode_pid>0 && dc->seek) usleep(10); | ||||
| 		} | ||||
| 	} | ||||
| 	pc->seek = 0; | ||||
| } | ||||
|  | ||||
| #define processDecodeInput() \ | ||||
| 	if(pc->lockQueue) { \ | ||||
| 		pc->queueLockState = PLAYER_QUEUE_LOCKED; \ | ||||
| 		pc->lockQueue = 0; \ | ||||
| 	} \ | ||||
| 	if(pc->unlockQueue) { \ | ||||
| 		pc->queueLockState = PLAYER_QUEUE_UNLOCKED; \ | ||||
| 		pc->unlockQueue = 0; \ | ||||
| 	} \ | ||||
| 	if(pc->pause) { \ | ||||
| 		pause = !pause; \ | ||||
| 		if(pause) pc->state = PLAYER_STATE_PAUSE; \ | ||||
| 		else pc->state = PLAYER_STATE_PLAY; \ | ||||
| 		pc->pause = 0; \ | ||||
| 		kill(getppid(),SIGUSR1); \ | ||||
| 	} \ | ||||
| 	if(pc->seek) { \ | ||||
| 		pc->totalPlayTime+= pc->elapsedTime-pc->beginTime; \ | ||||
| 		decodeSeek(pc,af,dc,cb); \ | ||||
| 		pc->beginTime = pc->elapsedTime; \ | ||||
| 		doCrossFade = 0; \ | ||||
| 		nextChunk =  -1; \ | ||||
| 		bbp = 0; \ | ||||
| 	} \ | ||||
| 	if(pc->stop) { \ | ||||
| 		pc->totalPlayTime+= pc->elapsedTime-pc->beginTime; \ | ||||
| 		quitDecode(pc,dc); \ | ||||
| 		return; \ | ||||
| 	} | ||||
|  | ||||
| int decoderInit(PlayerControl * pc, Buffer * cb, AudioFormat *af,  | ||||
| 			DecoderControl * dc) { | ||||
| 	decode_pid = fork(); | ||||
|  | ||||
| 	if(decode_pid==0) { | ||||
| 		/* CHILD */ | ||||
|  | ||||
| 		while(1) { | ||||
| 			if(dc->start) { | ||||
| 				strcpy(dc->file,pc->file); | ||||
| 				switch(pc->decodeType) { | ||||
| #ifdef HAVE_MAD | ||||
| 				case DECODE_TYPE_MP3: | ||||
| 					dc->error = mp3_decode(cb,af,dc); | ||||
| 					break; | ||||
| #endif | ||||
| #ifdef HAVE_OGG | ||||
| 				case DECODE_TYPE_OGG: | ||||
| 					dc->error = ogg_decode(cb,af,dc); | ||||
| 					break; | ||||
| #endif | ||||
| #ifdef HAVE_FLAC | ||||
| 				case DECODE_TYPE_FLAC: | ||||
| 					dc->error = flac_decode(cb,af,dc); | ||||
| 					break; | ||||
| #endif | ||||
| #ifdef HAVE_AUDIOFILE | ||||
| 				case DECODE_TYPE_AUDIOFILE: | ||||
| 					dc->error = audiofile_decode(cb,af,dc); | ||||
| 					break; | ||||
| #endif | ||||
| 				default: | ||||
| 					dc->error = DECODE_ERROR_UNKTYPE; | ||||
| 				} | ||||
| 				if(dc->error!=DECODE_ERROR_NOERROR) { | ||||
| 					dc->start = 0; | ||||
| 					dc->stop = 0; | ||||
| 					dc->state = DECODE_STATE_STOP; | ||||
| 				} | ||||
| 			} | ||||
| 			else if(dc->stop) { | ||||
| 				dc->state = DECODE_STATE_STOP; | ||||
| 				dc->stop = 0; | ||||
| 			} | ||||
| 			else if(dc->seek) dc->start = 1; | ||||
| 			else usleep(1000); | ||||
| 		} | ||||
|  | ||||
| 		exit(0); | ||||
| 		/* END OF CHILD */ | ||||
| 	} | ||||
| 	else if(decode_pid<0) { | ||||
| 		strcpy(pc->erroredFile,pc->file); | ||||
| 		pc->error = PLAYER_ERROR_SYSTEM; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* decode w/ buffering | ||||
|  * this will fork another process | ||||
|  * child process does decoding | ||||
|  * parent process does playing audio | ||||
|  */ | ||||
| void decode() { | ||||
| 	Buffer * cb; | ||||
| 	PlayerControl * pc; | ||||
| 	AudioFormat * af; | ||||
| 	DecoderControl * dc; | ||||
|  | ||||
| 	cb = &(getPlayerData()->buffer); | ||||
|  | ||||
| 	cb->begin = 0; | ||||
| 	cb->end = 0; | ||||
| 	cb->wrap = 0; | ||||
| 	pc = &(getPlayerData()->playerControl); | ||||
| 	dc = &(getPlayerData()->decoderControl); | ||||
| 	af = &(getPlayerData()->audioFormat); | ||||
| 	dc->error = 0; | ||||
| 	dc->start = 1; | ||||
| 	cb->next = -1; | ||||
|  | ||||
| 	if(decode_pid<=0) { | ||||
| 		if(decoderInit(pc,cb,af,dc)<0) return; | ||||
| 	} | ||||
|  | ||||
| 	{ | ||||
| 		/* PARENT */ | ||||
| 		char silence[CHUNK_SIZE]; | ||||
| 		int pause = 0; | ||||
| 		int quit = 0; | ||||
| 		int bbp = buffered_before_play; | ||||
| 		int doCrossFade = 0; | ||||
| 		int crossFadeChunks = 0; | ||||
| 		int fadePosition; | ||||
| 		int nextChunk = -1; | ||||
| 		int test; | ||||
|  | ||||
| 		memset(silence,0,CHUNK_SIZE); | ||||
|  | ||||
| 		if(waitOnDecode(pc,af,dc,cb)<0) return; | ||||
|  | ||||
| 		pc->state = PLAYER_STATE_PLAY; | ||||
| 		pc->play = 0; | ||||
| 		pc->beginTime = pc->elapsedTime; | ||||
| 		kill(getppid(),SIGUSR1); | ||||
| 	 | ||||
| 		while(decode_pid>0 && !cb->wrap && cb->end-cb->begin<bbp &&  | ||||
| 				dc->state==DECODE_STATE_DECODE)  | ||||
| 		{ | ||||
| 			processDecodeInput(); | ||||
| 			if(quit) return; | ||||
| 			usleep(100); | ||||
| 		} | ||||
|  | ||||
| 		while(!quit) { | ||||
| 			processDecodeInput(); | ||||
| 			if(dc->state==DECODE_STATE_STOP &&  | ||||
| 				pc->queueState==PLAYER_QUEUE_FULL && | ||||
| 				pc->queueLockState==PLAYER_QUEUE_UNLOCKED)  | ||||
| 			{ | ||||
| 				cb->next = cb->end; | ||||
| 				dc->start = 1; | ||||
| 				pc->queueState = PLAYER_QUEUE_DECODE; | ||||
| 				kill(getppid(),SIGUSR1); | ||||
| 			} | ||||
| 			if(cb->next>=0 && doCrossFade==0 && !dc->start) { | ||||
| 				nextChunk = -1; | ||||
| 				if(isCurrentAudioFormat(af)) { | ||||
| 					doCrossFade = 1; | ||||
| 					crossFadeChunks =  | ||||
| 						calculateCrossFadeChunks(pc,af); | ||||
| 					if(!crossFadeChunks || | ||||
| 						pc->crossFade>=cb->totalTime)  | ||||
| 					{ | ||||
| 						doCrossFade = -1; | ||||
| 					} | ||||
| 				} | ||||
| 				else doCrossFade = -1; | ||||
| 			} | ||||
| 			if(pause) playAudio(silence,CHUNK_SIZE); | ||||
| 			else if((cb->begin!=cb->end || cb->wrap) &&  | ||||
| 				cb->begin!=cb->next) | ||||
| 			{ | ||||
| 				if(doCrossFade==1 && cb->next>=0 &&  | ||||
| 					((cb->next>cb->begin &&  | ||||
| 					(fadePosition=cb->next-cb->begin) | ||||
| 					<=crossFadeChunks) ||  | ||||
| 					(cb->begin>cb->next && | ||||
| 					(fadePosition=cb->next-cb->begin+ | ||||
| 					BUFFERED_CHUNKS)<=crossFadeChunks))) | ||||
| 				{ | ||||
| 					if(nextChunk==-1) { | ||||
| 						crossFadeChunks = fadePosition; | ||||
| 					} | ||||
| 					nextChunk = cb->begin+crossFadeChunks; | ||||
| 					test = cb->end; | ||||
| 					if(cb->wrap) test+=BUFFERED_CHUNKS; | ||||
| 					if(nextChunk<test) { | ||||
| 						if(nextChunk>=BUFFERED_CHUNKS) | ||||
| 						{ | ||||
| 							nextChunk-= | ||||
| 								BUFFERED_CHUNKS; | ||||
| 						} | ||||
| 						pcm_mix(cb->chunks+cb->begin* | ||||
| 							CHUNK_SIZE, | ||||
| 							cb->chunks+nextChunk* | ||||
| 							CHUNK_SIZE, | ||||
| 							cb->chunkSize[ | ||||
| 								cb->begin], | ||||
| 							cb->chunkSize[ | ||||
| 								nextChunk], | ||||
| 							af, | ||||
| 							((float)fadePosition)/ | ||||
| 							crossFadeChunks); | ||||
| 						if(cb->chunkSize[nextChunk]> | ||||
| 							cb->chunkSize[cb->begin] | ||||
| 							) | ||||
| 						{ | ||||
| 							cb->chunkSize[cb->begin] | ||||
| 								= cb->chunkSize | ||||
| 								[nextChunk]; | ||||
| 						} | ||||
| 					} | ||||
| 					else { | ||||
| 						if(dc->state==DECODE_STATE_STOP) | ||||
| 						{ | ||||
| 							doCrossFade = -1; | ||||
| 						} | ||||
| 						else { | ||||
| 							usleep(10); | ||||
| 							continue; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				pc->elapsedTime = cb->times[cb->begin]; | ||||
| 				pc->bitRate = cb->bitRate[cb->begin]; | ||||
| 				pcm_volumeChange(cb->chunks+cb->begin* | ||||
| 					CHUNK_SIZE, | ||||
| 					cb->chunkSize[cb->begin], | ||||
| 					af, | ||||
| 					pc->softwareVolume); | ||||
| 				playAudio(cb->chunks+cb->begin*CHUNK_SIZE, | ||||
| 					cb->chunkSize[cb->begin]); | ||||
| 				cb->begin++; | ||||
| 				if(cb->begin>=BUFFERED_CHUNKS) { | ||||
| 					cb->begin = 0; | ||||
| 					cb->wrap = 0; | ||||
| 				} | ||||
| 			} | ||||
| 			else if(cb->next==cb->begin) { | ||||
| 				pc->totalPlayTime+= pc->elapsedTime- | ||||
| 							pc->beginTime; | ||||
| 				if(doCrossFade==1 && nextChunk>=0) { | ||||
| 					nextChunk = cb->begin+crossFadeChunks; | ||||
| 					test = cb->end; | ||||
| 					if(cb->wrap) test+=BUFFERED_CHUNKS; | ||||
| 					if(nextChunk<test) { | ||||
| 						if(nextChunk>=BUFFERED_CHUNKS) | ||||
| 						{ | ||||
| 							nextChunk-= | ||||
| 								BUFFERED_CHUNKS; | ||||
| 						} | ||||
| 						cb->begin = nextChunk; | ||||
| 					}	 | ||||
| 				} | ||||
| 				while(pc->queueState==PLAYER_QUEUE_DECODE || | ||||
| 					pc->queueLockState==PLAYER_QUEUE_LOCKED) | ||||
| 				{ | ||||
| 					processDecodeInput(); | ||||
| 					if(quit) { | ||||
| 						quitDecode(pc,dc); | ||||
| 						return; | ||||
| 					} | ||||
| 					usleep(10); | ||||
| 				} | ||||
| 				if(pc->queueState!=PLAYER_QUEUE_PLAY) { | ||||
| 					quit = 1; | ||||
| 					break; | ||||
| 				} | ||||
| 				else { | ||||
| 					cb->next = -1; | ||||
| 					if(waitOnDecode(pc,af,dc,cb)<0) return; | ||||
| 					nextChunk = -1; | ||||
| 					doCrossFade = 0; | ||||
| 					crossFadeChunks = 0; | ||||
| 					pc->queueState = PLAYER_QUEUE_EMPTY; | ||||
| 					kill(getppid(),SIGUSR1); | ||||
| 				} | ||||
| 				pc->beginTime = cb->times[cb->begin]; | ||||
| 			} | ||||
| 			else if(decode_pid<=0 ||  | ||||
| 				(dc->state==DECODE_STATE_STOP && !dc->start))  | ||||
| 			{ | ||||
| 				quit = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 			else usleep(10); | ||||
| 		} | ||||
|  | ||||
| 		pc->totalPlayTime+= pc->elapsedTime-pc->beginTime; \ | ||||
| 		quitDecode(pc,dc); | ||||
|  | ||||
| 		/* END OF PARENT */ | ||||
| 	} | ||||
|  | ||||
| 	return; | ||||
| } | ||||
							
								
								
									
										50
									
								
								src/decode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/decode.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef DECODE_H | ||||
| #define DECODE_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <sys/param.h> | ||||
|  | ||||
| #define DECODE_TYPE_MP3		0 | ||||
| #define DECODE_TYPE_OGG		1 | ||||
| #define DECODE_TYPE_FLAC	2 | ||||
| #define DECODE_TYPE_AUDIOFILE 	3 | ||||
|  | ||||
| #define DECODE_STATE_STOP	0 | ||||
| #define DECODE_STATE_DECODE	1 | ||||
|  | ||||
| #define DECODE_ERROR_NOERROR	0 | ||||
| #define DECODE_ERROR_UNKTYPE	1 | ||||
|  | ||||
| typedef struct _DecoderControl { | ||||
| 	int state; | ||||
| 	int stop; | ||||
| 	int start; | ||||
| 	int error; | ||||
| 	int seek; | ||||
| 	double seekWhere; | ||||
| 	char file[MAXPATHLEN+1]; | ||||
| } DecoderControl; | ||||
|  | ||||
| void decodeSigHandler(int sig); | ||||
|  | ||||
| void decode(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										841
									
								
								src/directory.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										841
									
								
								src/directory.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,841 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "directory.h" | ||||
|  | ||||
| #include "ls.h" | ||||
| #include "command.h" | ||||
| #include "tables.h" | ||||
| #include "utils.h" | ||||
| #include "path.h" | ||||
| #include "log.h" | ||||
| #include "playlist.h" | ||||
| #include "conf.h" | ||||
| #include "stats.h" | ||||
|  | ||||
| #include <string.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <dirent.h> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #define DIRECTORY_DIR		"directory: " | ||||
| #define DIRECTORY_MTIME		"mtime: " | ||||
| #define DIRECTORY_BEGIN		"begin: " | ||||
| #define DIRECTORY_END		"end: " | ||||
| #define DIRECTORY_INFO_BEGIN	"info_begin" | ||||
| #define DIRECTORY_INFO_END	"info_end" | ||||
| #define DIRECTORY_MPD_VERSION	"mpd_version: " | ||||
| #define DIRECTORY_FS_CHARSET	"fs_charset: " | ||||
|  | ||||
| #define DIRECTORY_SEARCH_ALBUM		"album" | ||||
| #define DIRECTORY_SEARCH_ARTIST		"artist" | ||||
| #define DIRECTORY_SEARCH_TITLE		"title" | ||||
| #define DIRECTORY_SEARCH_FILENAME	"filename" | ||||
|  | ||||
| typedef List DirectoryList; | ||||
|  | ||||
| typedef struct _Directory { | ||||
| 	char * utf8name; | ||||
| 	DirectoryList * subDirectories; | ||||
| 	struct _Directory * parentDirectory; | ||||
| 	SongList * songs; | ||||
| 	time_t mtime; /* modification time */ | ||||
| } Directory; | ||||
|  | ||||
| Directory * mp3rootDirectory; | ||||
|  | ||||
| char directorydb[MAXPATHLEN+1]; | ||||
|  | ||||
| DirectoryList * newDirectoryList(); | ||||
|  | ||||
| int addToDirectory(Directory * directory, char * shortname, char * name); | ||||
|  | ||||
| void freeDirectoryList(DirectoryList * list); | ||||
|  | ||||
| void freeDirectory(Directory * directory); | ||||
|  | ||||
| int exploreDirectory(Directory * directory); | ||||
|  | ||||
| int updateDirectory(Directory * directory); | ||||
|  | ||||
| int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name); | ||||
|  | ||||
| Directory * newDirectory(Directory * parentDirectory, char * dirname, time_t mtime) { | ||||
| 	Directory * directory; | ||||
|  | ||||
| 	directory = malloc(sizeof(Directory)); | ||||
|  | ||||
| 	if(dirname!=NULL) directory->utf8name = strdup(dirname); | ||||
| 	else directory->utf8name = NULL; | ||||
| 	directory->parentDirectory = parentDirectory; | ||||
| 	directory->subDirectories = newDirectoryList(); | ||||
| 	directory->songs = newSongList(); | ||||
| 	if(mtime<0) directory->mtime = isDir(dirname); | ||||
| 	else directory->mtime = mtime; | ||||
|  | ||||
| 	return directory; | ||||
| } | ||||
|  | ||||
| void freeDirectory(Directory * directory) { | ||||
| 	freeDirectoryList(directory->subDirectories); | ||||
| 	removeSongsFromTables(directory->songs); | ||||
| 	deleteSongsFromPlaylist(directory->songs); | ||||
| 	freeSongList(directory->songs); | ||||
| 	if(directory->utf8name) free(directory->utf8name); | ||||
| 	free(directory); | ||||
| } | ||||
|  | ||||
| DirectoryList * newDirectoryList() { | ||||
| 	return makeList((ListFreeDataFunc *)freeDirectory); | ||||
| } | ||||
|  | ||||
| void freeDirectoryList(DirectoryList * directoryList) { | ||||
| 	freeList(directoryList); | ||||
| } | ||||
|  | ||||
| void removeSongFromDirectory(Directory * directory, char * shortname) { | ||||
| 	void * song; | ||||
|  | ||||
| 	if(findInList(directory->songs,shortname,&song)) { | ||||
| 		removeASongFromTables((Song *)song); | ||||
| 		deleteASongFromPlaylist((Song *)song); | ||||
| 		deleteFromList(directory->songs,shortname); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int updateInDirectory(Directory * directory, char * shortname, char * name) { | ||||
| 	time_t mtime; | ||||
| 	void * song; | ||||
| 	void * subDir; | ||||
|  | ||||
| 	if((mtime = isMusic(name))) { | ||||
| 		if(0==findInList(directory->songs,shortname,&song)) { | ||||
| 			LOG("adding %s\n",name); | ||||
| 			addToDirectory(directory,shortname,name); | ||||
| 		} | ||||
| 		else if(mtime>((Song *)song)->mtime) { | ||||
| 			LOG("updating %s\n",name); | ||||
| 			updateSongInfo((Song *)song); | ||||
| 		} | ||||
| 	} | ||||
| 	else if((mtime = isDir(name))) { | ||||
| 		if(findInList(directory->subDirectories,shortname,(void **)&subDir)) { | ||||
| 			updateDirectory((Directory *)subDir); | ||||
| 		} | ||||
| 		else addSubDirectoryToDirectory(directory,shortname,name); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int removeDeletedFromDirectory(Directory * directory) { | ||||
| 	DIR * dir; | ||||
| 	char cwd[2]; | ||||
| 	struct dirent * ent; | ||||
| 	char * dirname = directory->utf8name; | ||||
| 	List * entList = makeList(free); | ||||
| 	void * name; | ||||
| 	char * s; | ||||
| 	char * utf8; | ||||
| 	ListNode * node; | ||||
| 	ListNode * tmpNode; | ||||
|  | ||||
| 	cwd[0] = '.'; | ||||
| 	cwd[1] = '\0'; | ||||
| 	if(dirname==NULL) dirname=cwd; | ||||
|  | ||||
| 	if((dir = opendir(rmp2amp(utf8ToFsCharset(dirname))))==NULL) return -1; | ||||
|  | ||||
| 	while((ent = readdir(dir))) { | ||||
| 		if(ent->d_name[0]=='.') continue; /* hide hidden stuff */ | ||||
|  | ||||
| 		utf8 = strdup(fsCharsetToUtf8(ent->d_name)); | ||||
|  | ||||
| 		if(directory->utf8name) { | ||||
| 			s = malloc(strlen(directory->utf8name)+strlen(utf8)+2); | ||||
| 			sprintf(s,"%s/%s",directory->utf8name,utf8); | ||||
| 		} | ||||
| 		else s= strdup(utf8); | ||||
| 		insertInList(entList,fsCharsetToUtf8(ent->d_name),s); | ||||
| 		free(utf8); | ||||
| 	} | ||||
|  | ||||
| 	closedir(dir); | ||||
|  | ||||
| 	node = directory->subDirectories->firstNode; | ||||
| 	while(node) { | ||||
| 		tmpNode = node->nextNode; | ||||
| 		if(findInList(entList,node->key,&name)) { | ||||
| 			if(!isDir((char *)name)) { | ||||
| 				deleteFromList(directory->subDirectories,node->key); | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			deleteFromList(directory->subDirectories,node->key); | ||||
| 		} | ||||
| 		node = tmpNode; | ||||
| 	} | ||||
|  | ||||
| 	node = directory->songs->firstNode; | ||||
| 	while(node) { | ||||
| 		tmpNode = node->nextNode; | ||||
| 		if(findInList(entList,node->key,(void **)&name)) { | ||||
| 			if(!isMusic(name)) { | ||||
| 				removeSongFromDirectory(directory,node->key); | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			removeSongFromDirectory(directory,node->key); | ||||
| 		} | ||||
| 		node = tmpNode; | ||||
| 	} | ||||
|  | ||||
| 	freeList(entList); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int updateDirectory(Directory * directory) { | ||||
| 	DIR * dir; | ||||
| 	char cwd[2]; | ||||
| 	struct dirent * ent; | ||||
| 	char * s; | ||||
| 	char * utf8; | ||||
| 	char * dirname = directory->utf8name; | ||||
|  | ||||
| 	cwd[0] = '.'; | ||||
| 	cwd[1] = '\0'; | ||||
| 	if(dirname==NULL) dirname=cwd; | ||||
|  | ||||
| 	removeDeletedFromDirectory(directory); | ||||
|  | ||||
| 	if((dir = opendir(rmp2amp(utf8ToFsCharset(dirname))))==NULL) return -1; | ||||
|  | ||||
| 	while((ent = readdir(dir))) { | ||||
| 		if(ent->d_name[0]=='.') continue; /* hide hidden stuff */ | ||||
|  | ||||
| 		utf8 = strdup(fsCharsetToUtf8(ent->d_name)); | ||||
|  | ||||
| 		if(directory->utf8name) { | ||||
| 			s = malloc(strlen(directory->utf8name)+strlen(utf8)+2); | ||||
| 			sprintf(s,"%s/%s",directory->utf8name,utf8); | ||||
| 		} | ||||
| 		else s = strdup(utf8); | ||||
| 		updateInDirectory(directory,utf8,s); | ||||
| 		free(utf8); | ||||
| 		free(s); | ||||
| 	} | ||||
| 	 | ||||
| 	closedir(dir); | ||||
|  | ||||
| 	if(directory->utf8name) directory->mtime = isDir(directory->utf8name); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int exploreDirectory(Directory * directory) { | ||||
| 	DIR * dir; | ||||
| 	char cwd[2]; | ||||
| 	struct dirent * ent; | ||||
| 	char * s; | ||||
| 	char * utf8; | ||||
| 	char * dirname = directory->utf8name; | ||||
|  | ||||
| 	cwd[0] = '.'; | ||||
| 	cwd[1] = '\0'; | ||||
| 	if(dirname==NULL) dirname=cwd; | ||||
|  | ||||
| 	DEBUG("explore: attempting to opendir: %s\n",dirname); | ||||
| 	if((dir = opendir(rmp2amp(utf8ToFsCharset(dirname))))==NULL) return -1; | ||||
|  | ||||
| 	LOG("explore: %s\n",dirname); | ||||
| 	while((ent = readdir(dir))) { | ||||
| 		if(ent->d_name[0]=='.') continue; /* hide hidden stuff */ | ||||
|  | ||||
| 		utf8 = strdup(fsCharsetToUtf8(ent->d_name)); | ||||
|  | ||||
| 		DEBUG("explore: found: %s (%s)\n",ent->d_name,utf8); | ||||
|  | ||||
| 		if(directory->utf8name) { | ||||
| 			s = malloc(strlen(directory->utf8name)+strlen(utf8)+2); | ||||
| 			sprintf(s,"%s/%s",directory->utf8name,utf8); | ||||
| 		} | ||||
| 		else s = strdup(utf8); | ||||
| 		addToDirectory(directory,utf8,s); | ||||
| 		free(utf8); | ||||
| 		free(s); | ||||
| 	} | ||||
| 	 | ||||
| 	closedir(dir); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int addSubDirectoryToDirectory(Directory * directory, char * shortname,  | ||||
| 	char * name)  | ||||
| { | ||||
| 	Directory * subDirectory = newDirectory(directory,name,-1); | ||||
| 	 | ||||
| 	insertInList(directory->subDirectories,shortname,subDirectory); | ||||
| 	exploreDirectory(subDirectory); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int addToDirectory(Directory * directory, char * shortname, char * name) { | ||||
| 	if(isDir(name)) { | ||||
| 		return addSubDirectoryToDirectory(directory,shortname,name); | ||||
| 	} | ||||
| 	else if(isMusic(name)) { | ||||
| 		Song * song; | ||||
| 		song = addSongToList(directory->songs,shortname,name); | ||||
| 		if(!song) return -1; | ||||
| 		addSongToTables(song); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	DEBUG("addToDirectory: %s is not a directory or music\n",name); | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void closeMp3Directory() { | ||||
| 	freeDirectory(mp3rootDirectory); | ||||
| } | ||||
|  | ||||
| Directory * findSubDirectory(Directory * directory,char * name) { | ||||
| 	void * subDirectory; | ||||
| 	char * dup = strdup(name); | ||||
| 	char * key; | ||||
|  | ||||
| 	key = strtok(dup,"/"); | ||||
| 	if(!key) { | ||||
| 		free(dup); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	 | ||||
| 	if(findInList(directory->subDirectories,key,&subDirectory)) { | ||||
| 		free(dup); | ||||
| 		return (Directory *)subDirectory; | ||||
| 	} | ||||
|  | ||||
| 	free(dup); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| Directory * getSubDirectory(Directory * directory,char * name) { | ||||
| 	Directory * subDirectory; | ||||
| 	int len; | ||||
|  | ||||
| 	if(name==NULL || name[0]=='\0' || strcmp(name,"/")==0) { | ||||
| 		return directory; | ||||
| 	} | ||||
|  | ||||
| 	if((subDirectory = findSubDirectory(directory,name))==NULL) return NULL; | ||||
|  | ||||
| 	len = 0; | ||||
| 	while(name[len]!='/' && name[len]!='\0') len++; | ||||
| 	while(name[len]=='/') len++; | ||||
|  | ||||
| 	return getSubDirectory(subDirectory,&(name[len])); | ||||
| } | ||||
|  | ||||
| Directory * getDirectory(char * name) { | ||||
| 	return getSubDirectory(mp3rootDirectory,name); | ||||
| } | ||||
|  | ||||
| int printDirectoryList(FILE * fp, DirectoryList * directoryList) { | ||||
| 	ListNode * node = directoryList->firstNode; | ||||
| 	Directory * directory; | ||||
|  | ||||
| 	while(node!=NULL) { | ||||
| 		directory = (Directory *)node->data; | ||||
| 		myfprintf(fp,"%s%s\n",DIRECTORY_DIR,directory->utf8name); | ||||
| 		node = node->nextNode; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int printDirectoryInfo(FILE * fp, char * name) { | ||||
| 	Directory * directory; | ||||
| 	 | ||||
| 	if((directory = getDirectory(name))==NULL) { | ||||
| 		myfprintf(fp,"%s: directory not found\n",COMMAND_RESPOND_ERROR); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	printDirectoryList(fp,directory->subDirectories); | ||||
| 	printSongInfoFromList(fp,directory->songs); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void writeDirectoryInfo(FILE * fp, Directory * directory) { | ||||
| 	ListNode * node = (directory->subDirectories)->firstNode; | ||||
| 	Directory * subDirectory; | ||||
|  | ||||
| 	if(directory->utf8name) { | ||||
| 		myfprintf(fp,"%s%s\n",DIRECTORY_BEGIN,directory->utf8name); | ||||
| 	} | ||||
| 			 | ||||
| 	while(node!=NULL) { | ||||
| 		subDirectory = (Directory *)node->data; | ||||
| 		myfprintf(fp,"%s%s\n",DIRECTORY_DIR,node->key); | ||||
| 		myfprintf(fp,"%s%li\n",DIRECTORY_MTIME,(long)subDirectory->mtime); | ||||
| 		writeDirectoryInfo(fp,subDirectory); | ||||
| 		node = node->nextNode; | ||||
| 	} | ||||
|  | ||||
| 	writeSongInfoFromList(fp,directory->songs); | ||||
|  | ||||
| 	if(directory->utf8name) { | ||||
| 		myfprintf(fp,"%s%s\n",DIRECTORY_END,directory->utf8name); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void readDirectoryInfo(FILE * fp,Directory * directory) { | ||||
| 	char buffer[MAXPATHLEN*2]; | ||||
| 	int bufferSize = MAXPATHLEN*2; | ||||
| 	char * key; | ||||
| 	Directory * subDirectory; | ||||
| 	char * name; | ||||
| 	time_t mtime; | ||||
|  | ||||
| 	while(myFgets(buffer,bufferSize,fp) && 0!=strncmp(DIRECTORY_END,buffer,strlen(DIRECTORY_END))) { | ||||
| 		if(0==strncmp(DIRECTORY_DIR,buffer,strlen(DIRECTORY_DIR))) { | ||||
| 			key = strdup(&(buffer[strlen(DIRECTORY_DIR)])); | ||||
| 			if(myFgets(buffer,bufferSize,fp)<0) { | ||||
| 				ERROR("Error reading db\n"); | ||||
| 				exit(-1); | ||||
| 			} | ||||
| 			if(strncmp(DIRECTORY_MTIME,buffer,strlen(DIRECTORY_MTIME))) { | ||||
| 				ERROR("Error reading db\n"); | ||||
| 				ERROR("%s\n",buffer); | ||||
| 				exit(-1); | ||||
| 			} | ||||
| 			mtime = atoi(&(buffer[strlen(DIRECTORY_BEGIN)])); | ||||
| 			if(myFgets(buffer,bufferSize,fp)<0) { | ||||
| 				ERROR("Error reading db\n"); | ||||
| 				exit(-1); | ||||
| 			} | ||||
| 			if(strncmp(DIRECTORY_BEGIN,buffer,strlen(DIRECTORY_BEGIN))) { | ||||
| 				ERROR("Error reading db\n"); | ||||
| 				exit(-1); | ||||
| 			} | ||||
| 			name = strdup(&(buffer[strlen(DIRECTORY_BEGIN)])); | ||||
| 			subDirectory = newDirectory(directory,name,mtime); | ||||
| 			insertInList(directory->subDirectories,key,(void *)subDirectory); | ||||
| 			free(key); | ||||
| 			free(name); | ||||
| 			readDirectoryInfo(fp,subDirectory); | ||||
| 		} | ||||
| 		else if(0==strncmp(SONG_BEGIN,buffer,strlen(SONG_BEGIN))) { | ||||
| 			readSongInfoIntoList(fp,directory->songs); | ||||
| 		} | ||||
| 		else { | ||||
| 			ERROR("Unknown line in db: %s\n",buffer); | ||||
| 			exit(-1); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void sortDirectory(Directory * directory) { | ||||
| 	ListNode * node = directory->subDirectories->firstNode; | ||||
| 	Directory * subDir; | ||||
| 	 | ||||
| 	sortList(directory->subDirectories); | ||||
| 	sortList(directory->songs); | ||||
|  | ||||
| 	while(node!=NULL) { | ||||
| 		subDir = (Directory *)node->data; | ||||
| 		sortDirectory(subDir); | ||||
| 		node = node->nextNode; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int writeDirectoryDB() { | ||||
| 	FILE * fp; | ||||
|  | ||||
| 	sortDirectory(mp3rootDirectory); | ||||
| 	stats.numberOfSongs = countSongsIn(stderr,NULL); | ||||
|  | ||||
| 	while(!(fp=fopen(directorydb,"w")) && errno==EINTR); | ||||
| 	if(!fp) return -1; | ||||
|  | ||||
| 	myfprintf(fp,"%s\n",DIRECTORY_INFO_BEGIN); | ||||
| 	myfprintf(fp,"%s%s\n",DIRECTORY_MPD_VERSION,VERSION); | ||||
| 	myfprintf(fp,"%s%s\n",DIRECTORY_FS_CHARSET,getFsCharset()); | ||||
| 	myfprintf(fp,"%s\n",DIRECTORY_INFO_END); | ||||
|  | ||||
| 	writeDirectoryInfo(fp,mp3rootDirectory); | ||||
| 	while(fclose(fp) && errno==EINTR); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int readDirectoryDB() { | ||||
| 	FILE * fp; | ||||
|  | ||||
| 	mp3rootDirectory = newDirectory(NULL,NULL,0); | ||||
| 	while(!(fp=fopen(directorydb,"r")) && errno==EINTR); | ||||
| 	if(!fp) return -1; | ||||
|  | ||||
| 	/* get initial info */ | ||||
| 	{ | ||||
| 		char buffer[100]; | ||||
| 		int bufferSize = 100; | ||||
| 		int foundFsCharset = 0; | ||||
| 		int foundVersion = 0; | ||||
|  | ||||
| 		if(myFgets(buffer,bufferSize,fp)<0) { | ||||
| 			ERROR("Error reading db\n"); | ||||
| 			exit(-1); | ||||
| 		} | ||||
| 		if(0==strcmp(DIRECTORY_INFO_BEGIN,buffer)) { | ||||
| 			while(myFgets(buffer,bufferSize,fp) &&  | ||||
| 					0!=strcmp(DIRECTORY_INFO_END,buffer))  | ||||
| 			{ | ||||
| 				if(0==strncmp(DIRECTORY_MPD_VERSION,buffer, | ||||
| 						strlen(DIRECTORY_MPD_VERSION))) | ||||
| 				{ | ||||
| 					if(foundVersion) { | ||||
| 						ERROR("already found " | ||||
| 							"version in db\n"); | ||||
| 						exit(-1); | ||||
| 					} | ||||
| 					foundVersion = 1; | ||||
| 				} | ||||
| 				else if(0==strncmp(DIRECTORY_FS_CHARSET,buffer, | ||||
| 						strlen(DIRECTORY_FS_CHARSET))) | ||||
| 				{ | ||||
| 					char * fsCharset;  | ||||
|  | ||||
| 					if(foundFsCharset) { | ||||
| 						ERROR("already found " | ||||
| 							"fs charset in db\n"); | ||||
| 						exit(-1); | ||||
| 					} | ||||
|  | ||||
| 					foundFsCharset = 1; | ||||
|  | ||||
| 					fsCharset = &(buffer[strlen( | ||||
| 							DIRECTORY_FS_CHARSET)]); | ||||
| 					if(getConf()[CONF_FS_CHARSET] &&  | ||||
| 							strcmp(fsCharset, | ||||
| 							getFsCharset()))  | ||||
| 					{ | ||||
| 						ERROR("Using \"%s\" for the " | ||||
| 							"filesystem charset " | ||||
| 							"instead of \"%s\"\n", | ||||
| 							fsCharset, | ||||
| 							getFsCharset()); | ||||
| 						ERROR("maybe you need to " | ||||
| 							"recreate the db?\n"); | ||||
| 						setFsCharset(fsCharset); | ||||
| 					} | ||||
| 				} | ||||
| 				else { | ||||
| 					ERROR("unknown line in db info: %s\n", | ||||
| 						buffer); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			ERROR("db info not found in db file\n"); | ||||
| 			ERROR("you should recreate the db using --create-db\n"); | ||||
| 			fseek(fp,0,SEEK_SET); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	readDirectoryInfo(fp,mp3rootDirectory); | ||||
| 	while(fclose(fp) && errno==EINTR); | ||||
|  | ||||
| 	stats.numberOfSongs = countSongsIn(stderr,NULL); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int updateMp3Directory(FILE * fp) { | ||||
| 	if(updateDirectory(mp3rootDirectory)<0) { | ||||
| 		ERROR("problems updating music db\n"); | ||||
| 		myfprintf(fp,"%s problems updating music db\n",COMMAND_RESPOND_ERROR); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if(writeDirectoryDB()<0) { | ||||
| 		ERROR("problems writing music db file, \"%s\"\n",directorydb); | ||||
| 		myfprintf(fp,"%s problems writing music db\n",COMMAND_RESPOND_ERROR); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int traverseAllInSubDirectory(FILE * fp, Directory * directory, | ||||
|                                 int (*forEachSong)(FILE *, Song *, void *), | ||||
|                                 int (*forEachDir)(FILE *, Directory *, void *), | ||||
| 				void * data) | ||||
| { | ||||
|         ListNode * node = directory->songs->firstNode; | ||||
|         Song * song; | ||||
|         Directory * dir; | ||||
|         int errFlag = 0; | ||||
|  | ||||
|         if(forEachDir) { | ||||
|                 errFlag = forEachDir(fp,directory,data); | ||||
|                 if(errFlag) return errFlag; | ||||
|         } | ||||
|  | ||||
|         if(forEachSong) { | ||||
|                 while(node!=NULL && !errFlag) { | ||||
|                         song = (Song *)node->data; | ||||
|                         errFlag = forEachSong(fp,song,data); | ||||
|                         node = node->nextNode; | ||||
|                 } | ||||
|                 if(errFlag) return errFlag; | ||||
|         } | ||||
|  | ||||
|         node = directory->subDirectories->firstNode; | ||||
|  | ||||
|         while(node!=NULL && !errFlag) { | ||||
|                 dir = (Directory *)node->data; | ||||
|                 errFlag = traverseAllInSubDirectory(fp,dir,forEachSong, | ||||
|                                                         forEachDir,data); | ||||
|                 node = node->nextNode; | ||||
|         } | ||||
|  | ||||
|         return errFlag; | ||||
| } | ||||
|  | ||||
| int traverseAllIn(FILE * fp, char * name,  | ||||
| 			int (*forEachSong)(FILE *, Song *, void *), | ||||
| 			int (*forEachDir)(FILE *, Directory *, void *), | ||||
| 			void * data) { | ||||
| 	Directory * directory; | ||||
|  | ||||
| 	if((directory = getDirectory(name))==NULL) { | ||||
| 		Song * song; | ||||
| 		if((song = getSong(name)) && forEachSong) { | ||||
| 			return forEachSong(fp, song, data); | ||||
| 		} | ||||
| 		myfprintf(fp,"%s: directory or file not found\n",COMMAND_RESPOND_ERROR); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return traverseAllInSubDirectory(fp,directory,forEachSong,forEachDir, | ||||
| 			data); | ||||
| } | ||||
|  | ||||
| int countSongsInDirectory(FILE * fp, Directory * directory, void * data) { | ||||
| 	int * count = (int *)data; | ||||
|  | ||||
| 	*count+=directory->songs->numberOfNodes; | ||||
| 	 | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| int printDirectoryInDirectory(FILE * fp, Directory * directory, void * data) { | ||||
|         if(directory->utf8name) { | ||||
| 		myfprintf(fp,"directory: %s\n",directory->utf8name); | ||||
| 	} | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| int printSongInDirectory(FILE * fp, Song * song, void * data) { | ||||
|         myfprintf(fp,"file: %s\n",song->utf8file); | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| int searchForAlbumInDirectory(FILE * fp, Song * song, void * string) { | ||||
| 	if(song->tag && song->tag->album) { | ||||
| 		char * dup = strDupToUpper(song->tag->album); | ||||
| 		if(strstr(dup,(char *)string)) printSongInfo(fp,song); | ||||
| 		free(dup); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int searchForArtistInDirectory(FILE * fp, Song * song, void * string) { | ||||
| 	if(song->tag && song->tag->artist) { | ||||
| 		char * dup = strDupToUpper(song->tag->artist); | ||||
| 		if(strstr(dup,(char *)string)) printSongInfo(fp,song); | ||||
| 		free(dup); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int searchForTitleInDirectory(FILE * fp, Song * song, void * string) { | ||||
| 	if(song->tag && song->tag->title) { | ||||
| 		char * dup = strDupToUpper(song->tag->title); | ||||
| 		if(strstr(dup,(char *)string)) printSongInfo(fp,song); | ||||
| 		free(dup); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int searchForFilenameInDirectory(FILE * fp, Song * song, void * string) { | ||||
| 	char * dup = strDupToUpper(song->utf8file); | ||||
| 	if(strstr(dup,(char *)string)) printSongInfo(fp,song); | ||||
| 	free(dup); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int searchForSongsIn(FILE * fp, char * name, char * item, char * string) { | ||||
| 	char * dup = strDupToUpper(string); | ||||
| 	int ret = -1; | ||||
|  | ||||
| 	if(strcmp(item,DIRECTORY_SEARCH_ALBUM)==0) { | ||||
| 		ret = traverseAllIn(fp,name,searchForAlbumInDirectory,NULL, | ||||
| 			(void *)dup); | ||||
| 	} | ||||
| 	else if(strcmp(item,DIRECTORY_SEARCH_ARTIST)==0) { | ||||
| 		ret = traverseAllIn(fp,name,searchForArtistInDirectory,NULL, | ||||
| 			(void *)dup); | ||||
| 	} | ||||
| 	else if(strcmp(item,DIRECTORY_SEARCH_TITLE)==0) { | ||||
| 		ret = traverseAllIn(fp,name,searchForTitleInDirectory,NULL, | ||||
| 			(void *)dup); | ||||
| 	} | ||||
| 	else if(strcmp(item,DIRECTORY_SEARCH_FILENAME)==0) { | ||||
| 		ret = traverseAllIn(fp,name,searchForFilenameInDirectory,NULL, | ||||
| 			(void *)dup); | ||||
| 	} | ||||
| 	else myfprintf(fp,"%s unknown table\n",COMMAND_RESPOND_ERROR); | ||||
|  | ||||
| 	free(dup); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int findAlbumInDirectory(FILE * fp, Song * song, void * string) { | ||||
| 	if(song->tag && song->tag->album &&  | ||||
| 			strcmp((char *)string,song->tag->album)==0)  | ||||
| 	{ | ||||
| 		printSongInfo(fp,song); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int findArtistInDirectory(FILE * fp, Song * song, void * string) { | ||||
| 	if(song->tag && song->tag->artist &&  | ||||
| 			strcmp((char *)string,song->tag->artist)==0)  | ||||
| 	{ | ||||
| 		printSongInfo(fp,song); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int findSongsIn(FILE * fp, char * name, char * item, char * string) { | ||||
| 	if(strcmp(item,DIRECTORY_SEARCH_ALBUM)==0) { | ||||
| 		return traverseAllIn(fp,name,findAlbumInDirectory,NULL, | ||||
| 			(void *)string); | ||||
| 	} | ||||
| 	else if(strcmp(item,DIRECTORY_SEARCH_ARTIST)==0) { | ||||
| 		return traverseAllIn(fp,name,findArtistInDirectory,NULL, | ||||
| 			(void *)string); | ||||
| 	} | ||||
|  | ||||
| 	myfprintf(fp,"%s unknown table\n",COMMAND_RESPOND_ERROR); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int printAllIn(FILE * fp, char * name) { | ||||
| 	return traverseAllIn(fp,name,printSongInDirectory, | ||||
| 				printDirectoryInDirectory,NULL); | ||||
| } | ||||
|  | ||||
| int directoryAddSongToPlaylist(FILE * fp, Song * song, void * data) { | ||||
| 	return addSongToPlaylist(fp,song); | ||||
| } | ||||
|  | ||||
| int addAllIn(FILE * fp, char * name) { | ||||
| 	return traverseAllIn(fp,name,directoryAddSongToPlaylist,NULL,NULL); | ||||
| } | ||||
|  | ||||
| int directoryPrintSongInfo(FILE * fp, Song * song, void * data) { | ||||
| 	return printSongInfo(fp,song); | ||||
| } | ||||
|  | ||||
| int printInfoForAllIn(FILE * fp, char * name) { | ||||
|         return traverseAllIn(fp,name,directoryPrintSongInfo,NULL,NULL); | ||||
| } | ||||
|  | ||||
| int countSongsIn(FILE * fp, char * name) { | ||||
| 	int count = 0; | ||||
| 	void * ptr = (void *)&count; | ||||
| 	 | ||||
|         traverseAllIn(fp,name,NULL,countSongsInDirectory,ptr); | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| void initMp3Directory() { | ||||
| 	mp3rootDirectory = newDirectory(NULL,NULL,0); | ||||
| 	exploreDirectory(mp3rootDirectory); | ||||
| } | ||||
|  | ||||
| Song * getSong(char * file) { | ||||
| 	void * song; | ||||
| 	Directory * directory; | ||||
| 	char * dir = NULL; | ||||
| 	char * dup = strdup(file); | ||||
| 	char * shortname = dup; | ||||
| 	char * c = strtok(dup,"/"); | ||||
|  | ||||
| 	DEBUG("get song: %s\n",file); | ||||
|  | ||||
| 	while(c) { | ||||
| 		shortname = c; | ||||
| 		c = strtok(NULL,"/"); | ||||
| 	} | ||||
|  | ||||
| 	if(shortname!=dup) { | ||||
| 		for(c = dup; c < shortname-1; c++) { | ||||
| 			if(*c=='\0') *c = '/'; | ||||
| 		} | ||||
| 		dir = dup; | ||||
| 	} | ||||
|  | ||||
| 	if(!(directory = getSubDirectory(mp3rootDirectory,dir))) { | ||||
| 		free(dup); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if(!findInList(directory->songs,shortname,&song)) { | ||||
| 		free(dup); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	free(dup); | ||||
| 	return (Song *)song; | ||||
| } | ||||
|  | ||||
| time_t getDbModTime() { | ||||
| 	time_t mtime = 0; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if(stat(directorydb,&st)==0) mtime = st.st_mtime; | ||||
|  | ||||
| 	return mtime; | ||||
| } | ||||
							
								
								
									
										57
									
								
								src/directory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/directory.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef DIRECTORY_H | ||||
| #define DIRECTORY_H | ||||
|  | ||||
| #include "song.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <sys/param.h> | ||||
|  | ||||
| extern char directorydb[MAXPATHLEN+1]; | ||||
|  | ||||
| void initMp3Directory(); | ||||
|  | ||||
| void closeMp3Directory(); | ||||
|  | ||||
| int printDirectoryInfo(FILE * fp, char * dirname); | ||||
|  | ||||
| int writeDirectoryDB(); | ||||
|  | ||||
| int readDirectoryDB(); | ||||
|  | ||||
| int updateMp3Directory(FILE * fp); | ||||
|  | ||||
| int printAllIn(FILE * fp, char * name); | ||||
|  | ||||
| int addAllIn(FILE * fp, char * name); | ||||
|  | ||||
| int printInfoForAllIn(FILE * fp, char * name); | ||||
|  | ||||
| int searchForSongsIn(FILE * fp, char * name, char * item, char * string); | ||||
|  | ||||
| int findSongsIn(FILE * fp, char * name, char * item, char * string); | ||||
|  | ||||
| int countSongsIn(FILE * fp, char * name); | ||||
|  | ||||
| Song * getSong(char * file); | ||||
|  | ||||
| time_t getDbModTime(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										292
									
								
								src/flac_decode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								src/flac_decode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,292 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifdef HAVE_FLAC | ||||
| #include "flac_decode.h" | ||||
|  | ||||
| #include "utils.h" | ||||
| #include "log.h" | ||||
| #include "pcm_utils.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <FLAC/file_decoder.h> | ||||
| #include <FLAC/metadata.h> | ||||
|  | ||||
| typedef struct { | ||||
| 	unsigned char chunk[CHUNK_SIZE]; | ||||
| 	int chunk_length; | ||||
| 	float time; | ||||
| 	Buffer * cb; | ||||
| 	AudioFormat * af; | ||||
| 	DecoderControl * dc; | ||||
| 	char * file; | ||||
| } FlacData; | ||||
|  | ||||
| /* this code is based on flac123, from flac-tools */ | ||||
|  | ||||
| int flacSendChunk(FlacData * data); | ||||
| void flacPlayfile(const char * file, Buffer * cb, ao_sample_format * format); | ||||
| void flacError(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *); | ||||
| void flacPrintErroredState(FLAC__FileDecoderState state, char * file); | ||||
| void flacMetadata(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *); | ||||
| FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 * const buf[], void *); | ||||
|  | ||||
| void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,  | ||||
| 	DecoderControl *dc) | ||||
| { | ||||
| 	FLAC__FileDecoder * flacDec; | ||||
| 	FlacData data; | ||||
| 	int status = 1; | ||||
|  | ||||
| 	data.chunk_length = 0; | ||||
| 	data.time = 0; | ||||
| 	data.cb = cb; | ||||
| 	data.af = af; | ||||
| 	data.dc = dc; | ||||
| 	data.file = file; | ||||
| 	 | ||||
| 	if(!(flacDec = FLAC__file_decoder_new())) return; | ||||
| 	/*status&=FLAC__file_decoder_set_md5_checking(flacDec,1);*/ | ||||
| 	status&=FLAC__file_decoder_set_filename(flacDec,file); | ||||
| 	status&=FLAC__file_decoder_set_write_callback(flacDec,flacWrite); | ||||
| 	status&=FLAC__file_decoder_set_metadata_callback(flacDec,flacMetadata); | ||||
| 	status&=FLAC__file_decoder_set_error_callback(flacDec,flacError); | ||||
| 	status&=FLAC__file_decoder_set_client_data(flacDec, (void *)&data); | ||||
| 	if(!status) { | ||||
| 		ERROR("flac problem before init(): %s\n",file); | ||||
| 		flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file); | ||||
| 		FLAC__file_decoder_delete(flacDec); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(FLAC__file_decoder_init(flacDec)!= | ||||
| 			FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)  | ||||
| 	{ | ||||
| 		ERROR("flac problem doing init(): %s\n",file); | ||||
| 		flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file); | ||||
| 		FLAC__file_decoder_delete(flacDec); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(!FLAC__file_decoder_process_until_end_of_metadata(flacDec)) { | ||||
| 		ERROR("flac problem reading metadata: %s\n",file); | ||||
| 		flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file); | ||||
| 		FLAC__file_decoder_delete(flacDec); | ||||
| 		return; | ||||
| 	} | ||||
| 	while(1) { | ||||
| 		FLAC__file_decoder_process_single(flacDec); | ||||
| 		if(FLAC__file_decoder_get_state(flacDec)!= | ||||
| 				FLAC__FILE_DECODER_OK) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 		if(dc->seek) { | ||||
| 			FLAC__uint64 sampleToSeek = dc->seekWhere* | ||||
| 					af->sampleRate+0.5; | ||||
| 			cb->end = 0; | ||||
| 			cb->wrap = 0; | ||||
| 			if(FLAC__file_decoder_seek_absolute(flacDec, | ||||
| 						sampleToSeek)) | ||||
| 			{ | ||||
| 				data.time = ((float)sampleToSeek)/ | ||||
| 					af->sampleRate; | ||||
| 			} | ||||
| 			dc->seek = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	FLAC__file_decoder_process_until_end_of_file(flacDec); | ||||
| 	if(!dc->stop) { | ||||
| 		flacPrintErroredState(FLAC__file_decoder_get_state(flacDec), | ||||
| 				file); | ||||
| 		FLAC__file_decoder_finish(flacDec); | ||||
| 	} | ||||
| 	FLAC__file_decoder_delete(flacDec); | ||||
| 	/* send last little bit */ | ||||
| 	if(data.chunk_length>0 && !dc->stop) flacSendChunk(&data); | ||||
| } | ||||
|  | ||||
| void flacError(const FLAC__FileDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *fdata) { | ||||
| 	FlacData * data = (FlacData *) fdata; | ||||
| 	if(data->dc->stop) return; | ||||
|  | ||||
| 	switch(status) { | ||||
| 	case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC: | ||||
| 		ERROR("flac lost sync: %s\n",data->file); | ||||
| 		break; | ||||
| 	case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: | ||||
| 		ERROR("bad header %s\n",data->file); | ||||
| 		break; | ||||
| 	case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH: | ||||
| 		ERROR("crc mismatch %s\n",data->file); | ||||
| 		break; | ||||
| 	default: | ||||
| 		ERROR("unknow flac error %s\n",data->file); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void flacPrintErroredState(FLAC__FileDecoderState state, char * file) { | ||||
| 	switch(state) { | ||||
| 	case FLAC__FILE_DECODER_ERROR_OPENING_FILE: | ||||
| 		ERROR("error opening flac: %s\n",file); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR: | ||||
| 		ERROR("flac allocation error\n"); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_SEEK_ERROR: | ||||
| 		ERROR("flac seek error: %s\n",file); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR: | ||||
| 		ERROR("flac seekable stream error: %s\n",file); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_ALREADY_INITIALIZED: | ||||
| 		ERROR("flac decoder already initilaized: %s\n",file); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_INVALID_CALLBACK: | ||||
| 		ERROR("invalid flac callback\n"); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_UNINITIALIZED: | ||||
| 		ERROR("flac decoder uninitialized: %s\n",file); | ||||
| 		break; | ||||
| 	case FLAC__FILE_DECODER_OK: | ||||
| 	case FLAC__FILE_DECODER_END_OF_FILE: | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void flacMetadata(const FLAC__FileDecoder *dec, const FLAC__StreamMetadata *meta, void *data) { | ||||
| } | ||||
|  | ||||
| int flacSendChunk(FlacData * data) { | ||||
| 	while(data->cb->begin==data->cb->end && data->cb->wrap &&  | ||||
| 		!data->dc->stop && !data->dc->seek)   | ||||
| 	{ | ||||
| 		usleep(1000); | ||||
| 	} | ||||
|  | ||||
| 	if(data->dc->stop) return -1; | ||||
| 	if(data->dc->seek) return 0; | ||||
|  | ||||
| #ifdef WORDS_BIGENDIAN | ||||
| 	pcm_changeBufferEndianness(chunk,CHUNK_SIZE,data->af->bits); | ||||
| #endif | ||||
| 	memcpy(data->cb->chunks+data->cb->end*CHUNK_SIZE,data->chunk, | ||||
| 			CHUNK_SIZE); | ||||
| 	data->cb->chunkSize[data->cb->end] = data->chunk_length; | ||||
| 	data->cb->times[data->cb->end] = data->time; | ||||
| 	data->cb->bitRate[data->cb->end] = 0; | ||||
|  | ||||
| 	data->cb->end++; | ||||
| 	if(data->cb->end>=BUFFERED_CHUNKS) { | ||||
| 		data->cb->end = 0; | ||||
| 		data->cb->wrap = 1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *dec, const FLAC__Frame *frame, const FLAC__int32 * const buf[], void * vdata) { | ||||
| 	FlacData * data = (FlacData *)vdata; | ||||
| 	FLAC__uint32 samples = frame->header.blocksize; | ||||
| 	FLAC__uint16 u16; | ||||
| 	unsigned char * uc; | ||||
| 	int c_samp, c_chan, d_samp; | ||||
| 	int i; | ||||
| 	 | ||||
| 	data->time+=((float)samples)/frame->header.sample_rate; | ||||
|  | ||||
| 	for(c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) { | ||||
| 		for(c_chan = 0; c_chan < frame->header.channels;  | ||||
| 				c_chan++, d_samp++) { | ||||
| 			u16 = buf[c_chan][c_samp]; | ||||
| 			uc = (unsigned char *)&u16; | ||||
| 			for(i=0;i<(data->af->bits/8);i++) { | ||||
| 				if(data->chunk_length>=CHUNK_SIZE) { | ||||
| 					if(flacSendChunk(data)<0) { | ||||
| 						return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; | ||||
| 					} | ||||
| 					data->chunk_length = 0; | ||||
| 					if(data->dc->seek) { | ||||
| 						return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | ||||
| 					} | ||||
| 				} | ||||
| 				data->chunk[data->chunk_length++] = *(uc++); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | ||||
| } | ||||
|  | ||||
| int flac_getAudioFormatAndTime(char * file, AudioFormat * format, float * time) { | ||||
| 	FLAC__Metadata_SimpleIterator * it; | ||||
| 	FLAC__StreamMetadata * block = NULL; | ||||
| 	int found = 0; | ||||
| 	int ret = -1; | ||||
|  | ||||
| 	if(!(it = FLAC__metadata_simple_iterator_new())) return -1; | ||||
|         if(!FLAC__metadata_simple_iterator_init(it,file,1,0)) { | ||||
|                 FLAC__metadata_simple_iterator_delete(it); | ||||
| 	        return -1; | ||||
| 	} | ||||
|  | ||||
|         do { | ||||
|                 if(block) FLAC__metadata_object_delete(block); | ||||
|                 block = FLAC__metadata_simple_iterator_get_block(it); | ||||
|                 if(block->type == FLAC__METADATA_TYPE_STREAMINFO) found=1; | ||||
|         } while(!found && FLAC__metadata_simple_iterator_next(it)); | ||||
|  | ||||
| 	if(found) { | ||||
| 		format->bits = block->data.stream_info.bits_per_sample; | ||||
| 		format->bits = 16; | ||||
| 		format->sampleRate = block->data.stream_info.sample_rate; | ||||
| 		format->channels = block->data.stream_info.channels; | ||||
| 		*time = ((float)block->data.stream_info.total_samples)/ | ||||
| 			format->sampleRate; | ||||
| 		ret = 0; | ||||
| 	} | ||||
|  | ||||
| 	if(block) FLAC__metadata_object_delete(block); | ||||
| 	FLAC__metadata_simple_iterator_delete(it); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) { | ||||
| 	if(flac_getAudioFormatAndTime(dc->file,af,&(cb->totalTime))<0) { | ||||
| 		ERROR("\"%s\" doesn't seem to be a flac\n",dc->file); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	dc->state = DECODE_STATE_DECODE; | ||||
| 	dc->start = 0; | ||||
|  | ||||
| 	flacPlayFile(dc->file,cb,af,dc); | ||||
|  | ||||
| 	if(dc->seek) dc->seek = 0; | ||||
| 	 | ||||
| 	if(dc->stop) { | ||||
| 		dc->state = DECODE_STATE_STOP; | ||||
| 		dc->stop = 0; | ||||
| 	} | ||||
| 	else dc->state = DECODE_STATE_STOP; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										28
									
								
								src/flac_decode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/flac_decode.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef FLAC_DECODE_H | ||||
| #define FLAC_DECODE_H | ||||
|  | ||||
| #include "playerData.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										624
									
								
								src/interface.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										624
									
								
								src/interface.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,624 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 "interface.h" | ||||
| #include "buffer2array.h" | ||||
| #include "command.h" | ||||
| #include "conf.h" | ||||
| #include "list.h" | ||||
| #include "log.h" | ||||
| #include "listen.h" | ||||
| #include "sig_handlers.h" | ||||
| #include "playlist.h" | ||||
| #include "permission.h" | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/select.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <string.h> | ||||
| #include <fcntl.h> | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
|  | ||||
| #define GREETING 		"MPD" | ||||
|  | ||||
| #define INTERFACE_MAX_BUFFER_LENGTH		MAXPATHLEN+1024 | ||||
| #define INTERFACE_LIST_MODE_BEGIN		"command_list_begin" | ||||
| #define INTERFACE_LIST_MODE_END			"command_list_end" | ||||
| #define INTERFACE_DEFAULT_OUT_BUFFER_SIZE	4096 | ||||
|  | ||||
| int interface_max_connections; | ||||
| int interface_timeout; | ||||
| unsigned long long interface_max_command_list_size; | ||||
| unsigned long long interface_max_output_buffer_size; | ||||
|  | ||||
| typedef struct _Interface { | ||||
| 	char buffer[INTERFACE_MAX_BUFFER_LENGTH+2]; | ||||
| 	int bufferLength; | ||||
| 	int fd; /* file descriptor */ | ||||
| 	FILE * fp; /* file pointer */ | ||||
| 	int open; /* open/used */ | ||||
| 	unsigned int permission; | ||||
| 	time_t lastTime; | ||||
| 	List * commandList; /* for when in list mode */ | ||||
| 	unsigned long long commandListSize; /* mem commandList consumes */ | ||||
| 	List * bufferList; /* for output if client is slow */ | ||||
| 	unsigned long long outputBufferSize; /* mem bufferList consumes */ | ||||
| 	int expired; /* set whether this interface should be closed on next | ||||
| 			check of old interfaces */ | ||||
| 	int num; /* interface number */ | ||||
| 	char * outBuffer; | ||||
| 	int outBuflen; | ||||
| 	int outBufSize; | ||||
| } Interface; | ||||
|  | ||||
| Interface * interfaces = NULL; | ||||
|  | ||||
| void flushInterfaceBuffer(Interface * interface); | ||||
|  | ||||
| void printInterfaceOutBuffer(Interface * interface); | ||||
|  | ||||
| void openInterface(Interface * interface, int fd) { | ||||
| 	int flags; | ||||
| 	 | ||||
| 	assert(interface->open==0); | ||||
|  | ||||
| 	blockSignals(); | ||||
| 	interface->bufferLength = 0; | ||||
| 	interface->fd = fd; | ||||
| 	/* fcntl(interface->fd,F_SETOWN,(int)getpid()); */ | ||||
| 	flags = fcntl(fd,F_GETFL); | ||||
| 	flags|=O_NONBLOCK; | ||||
| 	fcntl(interface->fd,F_SETFL,flags); | ||||
| 	interface->fp = fdopen(fd,"rw"); | ||||
| 	interface->open = 1; | ||||
| 	interface->lastTime = time(NULL); | ||||
| 	interface->commandList = NULL; | ||||
| 	interface->bufferList = NULL; | ||||
| 	interface->expired = 0; | ||||
| 	interface->outputBufferSize = 0; | ||||
| 	interface->outBuflen = 0; | ||||
|  | ||||
| 	interface->permission = getDefaultPermissions(); | ||||
|  | ||||
| 	interface->outBufSize = INTERFACE_DEFAULT_OUT_BUFFER_SIZE; | ||||
| #ifdef SO_SNDBUF | ||||
| 	{ | ||||
| 		int getSize; | ||||
| 		int sockOptLen = sizeof(int); | ||||
|  | ||||
| 		if(getsockopt(interface->fd,SOL_SOCKET,SO_SNDBUF, | ||||
| 					(char *)&getSize,&sockOptLen) < 0) | ||||
| 		{ | ||||
| 			DEBUG("problem getting sockets send buffer size\n"); | ||||
| 		} | ||||
| 		else if(getSize<=0) { | ||||
| 			DEBUG("sockets send buffer size is not positive\n"); | ||||
| 		} | ||||
| 		else interface->outBufSize = getSize; | ||||
| 	} | ||||
| #endif | ||||
| 	interface->outBuffer = malloc(interface->outBufSize); | ||||
| 	 | ||||
| 	unblockSignals(); | ||||
|  | ||||
| 	myfprintf(interface->fp,"%s %s %s\n",COMMAND_RESPOND_OK,GREETING, | ||||
| 			VERSION); | ||||
| 	printInterfaceOutBuffer(interface); | ||||
| } | ||||
|  | ||||
| void closeInterface(Interface * interface) { | ||||
| 	assert(interface->open); | ||||
|  | ||||
| 	interface->open = 0; | ||||
|  | ||||
| 	while(fclose(interface->fp) && errno==EINTR); | ||||
|  | ||||
| 	if(interface->commandList) freeList(interface->commandList); | ||||
| 	if(interface->bufferList) freeList(interface->bufferList); | ||||
|  | ||||
| 	free(interface->outBuffer); | ||||
|  | ||||
| 	SECURE("interface %i: closed\n",interface->num); | ||||
| } | ||||
|  | ||||
| void openAInterface(int fd, struct sockaddr * addr) { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections && interfaces[i].open;i++); | ||||
|  | ||||
| 	if(i==interface_max_connections) { | ||||
| 		ERROR("Max Connections Reached!\n"); | ||||
| 		while(close(fd) && errno==EINTR); | ||||
| 	} | ||||
| 	else { | ||||
| 		SECURE("interface %i: opened from ",i); | ||||
| 		switch(addr->sa_family) { | ||||
| 		case AF_INET: | ||||
| 			SECURE("%s\n",inet_ntoa( | ||||
| 					((struct sockaddr_in *)addr)-> | ||||
| 					sin_addr)); | ||||
| 			break; | ||||
| #ifdef HAVE_IPV6 | ||||
| 		case AF_INET6: | ||||
| 			{ | ||||
| 				char host[INET6_ADDRSTRLEN+1]; | ||||
| 				memset(host,0,INET6_ADDRSTRLEN+1); | ||||
| 				SECURE("%s\n",inet_ntop(AF_INET6,(void *) | ||||
| 					&(((struct sockaddr_in6 *)addr)-> | ||||
| 					sin6_addr),host,INET6_ADDRSTRLEN)); | ||||
| 			} | ||||
| 			break; | ||||
| #endif | ||||
| 		case AF_UNIX: | ||||
| 			SECURE("local connection\n"); | ||||
| 			break; | ||||
| 		default: | ||||
| 			SECURE("unknown\n"); | ||||
| 		} | ||||
| 		openInterface(&(interfaces[i]),fd); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int interfaceReadInput(Interface * interface) { | ||||
| 	blockSignals(); | ||||
| 	if(read(interface->fd,interface->buffer+interface->bufferLength,1)>0) { | ||||
| 		int ret = 1; | ||||
| 		int bytesRead = 1; | ||||
| 		while(bytesRead>0) { | ||||
| 			interface->buffer[interface->bufferLength+1] = '\0'; | ||||
| 			if(interface->buffer[interface->bufferLength]!='\r') { | ||||
| 				interface->bufferLength++; | ||||
| 			} | ||||
| 			if(interface->bufferLength>=INTERFACE_MAX_BUFFER_LENGTH) { | ||||
| 				break; | ||||
| 			} | ||||
| 			if(interface->buffer[interface->bufferLength-1]=='\n') { | ||||
| 				break; | ||||
| 			} | ||||
| 			bytesRead = read(interface->fd,interface->buffer+ | ||||
| 						interface->bufferLength,1); | ||||
| 		} | ||||
| 		unblockSignals(); | ||||
| 		if(interface->bufferLength>=INTERFACE_MAX_BUFFER_LENGTH) { | ||||
| 			ERROR("interface %i: buffer overflow\n", | ||||
| 				interface->num); | ||||
| 			closeInterface(interface); | ||||
| 		} | ||||
| 		else if(interface->buffer[interface->bufferLength-1]=='\n') { | ||||
| 			char ** argArray; | ||||
| 			int argArrayLength; | ||||
|  | ||||
| 			interface->buffer[interface->bufferLength-1] = '\0'; | ||||
| 			interface->bufferLength = 0; | ||||
| 			argArrayLength = buffer2array(interface->buffer,&argArray); | ||||
|  | ||||
| 			if(interface->commandList) { | ||||
| 				if(strcmp(argArray[0],INTERFACE_LIST_MODE_END)==0) { | ||||
| 					ListNode * node = interface->commandList->firstNode; | ||||
| 					ret = 0; | ||||
|  | ||||
| 					while(node!=NULL) { | ||||
| 						char ** argArray; | ||||
| 						int argArrayLength; | ||||
| 						argArrayLength = buffer2array((char *)node->data,&argArray); | ||||
| 						DEBUG("interface %i: process command \"%s\"\n",interface->num,node->data); | ||||
| 						ret = processCommand(interface->fp,&(interface->permission),argArrayLength,argArray); | ||||
| 						DEBUG("interface %i: command returned %i\n",interface->num,ret); | ||||
| 						freeArgArray(argArray,argArrayLength); | ||||
| 						node = node->nextNode; | ||||
| 						if(ret!=0 ||  | ||||
| 							interface->expired) { | ||||
| 							node = NULL; | ||||
| 						} | ||||
| 					} | ||||
| 					if(ret==0) { | ||||
| 						myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK); | ||||
| 					} | ||||
| 					else if(ret==COMMAND_RETURN_CLOSE || | ||||
| 							interface->expired) { | ||||
| 						closeInterface(interface); | ||||
| 					} | ||||
| 					printInterfaceOutBuffer(interface); | ||||
|  | ||||
| 					freeList(interface->commandList); | ||||
| 					interface->commandList = NULL; | ||||
| 				} | ||||
| 				else { | ||||
| 					interface->commandListSize+=sizeof(ListNode); | ||||
| 					interface->commandListSize+=strlen(interface->buffer)+1; | ||||
| 					if(interface->commandListSize>interface_max_command_list_size) { | ||||
| 						ERROR("interface %i: command list size (%lli) is larger than the max (%lli)\n",interface->num,interface->commandListSize,interface_max_command_list_size); | ||||
| 						closeInterface(interface); | ||||
| 						 | ||||
| 					} | ||||
| 					else { | ||||
| 						insertInListWithoutKey(interface->commandList,strdup(interface->buffer)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				if(strcmp(argArray[0],INTERFACE_LIST_MODE_BEGIN)==0) { | ||||
| 					interface->commandList = makeList(free); | ||||
| 					interface->commandListSize =  | ||||
| 						sizeof(List); | ||||
| 					ret = 1; | ||||
| 				} | ||||
| 				else { | ||||
| 					if(strcmp(argArray[0],INTERFACE_LIST_MODE_END)==0) { | ||||
| 						myfprintf(interface->fp,"%s not in command list mode\n",COMMAND_RESPOND_ERROR); | ||||
| 						ret = -1; | ||||
| 					} | ||||
| 					else { | ||||
| 						DEBUG("interface %i: process command \"%s\"\n",interface->num,interface->buffer); | ||||
| 						ret = processCommand(interface->fp,&(interface->permission),argArrayLength,argArray); | ||||
| 						DEBUG("interface %i: command returned %i\n",interface->num,ret); | ||||
| 					} | ||||
| 					if(ret==0) { | ||||
| 						myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK); | ||||
| 					} | ||||
| 					else if(ret==COMMAND_RETURN_CLOSE || | ||||
| 							interface->expired) { | ||||
| 						closeInterface(interface); | ||||
| 					} | ||||
| 					printInterfaceOutBuffer(interface); | ||||
| 				} | ||||
| 			} | ||||
| 			freeArgArray(argArray,argArrayLength); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
| 	else { | ||||
| 		unblockSignals(); | ||||
| 		closeInterface(interface); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds, int * fdmax) { | ||||
| 	int i; | ||||
|  | ||||
| 	FD_ZERO(fds); | ||||
| 	FD_SET(listenSocket,fds); | ||||
| 	if(*fdmax<listenSocket) *fdmax = listenSocket; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open && !interfaces[i].expired && !interfaces[i].bufferList) { | ||||
| 			FD_SET(interfaces[i].fd,fds); | ||||
| 			if(*fdmax<interfaces[i].fd) *fdmax = interfaces[i].fd; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void addInterfacesForBufferFlushToFdSet(fd_set * fds, int * fdmax) { | ||||
| 	int i; | ||||
|  | ||||
| 	FD_ZERO(fds); | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open && !interfaces[i].expired && interfaces[i].bufferList) { | ||||
| 			FD_SET(interfaces[i].fd,fds); | ||||
| 			if(*fdmax<interfaces[i].fd) *fdmax = interfaces[i].fd; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void closeNextErroredInterface() { | ||||
| 	fd_set fds; | ||||
| 	struct timeval tv; | ||||
| 	int i; | ||||
|  | ||||
| 	tv.tv_sec = 0; | ||||
| 	tv.tv_usec = 0; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open) { | ||||
| 			FD_ZERO(&fds); | ||||
| 			FD_SET(interfaces[i].fd,&fds); | ||||
| 			if(select(FD_SETSIZE,&fds,NULL,NULL,&tv)<0) { | ||||
| 				closeInterface(&interfaces[i]); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int doIOForInterfaces() { | ||||
| 	fd_set rfds; | ||||
| 	fd_set wfds; | ||||
| 	struct timeval tv; | ||||
| 	int i; | ||||
| 	int selret; | ||||
| 	int fdmax = 0; | ||||
|  | ||||
| 	tv.tv_sec = 1; | ||||
| 	tv.tv_usec = 0; | ||||
|  | ||||
| 	addInterfacesReadyToReadAndListenSocketToFdSet(&rfds,&fdmax); | ||||
| 	addInterfacesForBufferFlushToFdSet(&wfds,&fdmax); | ||||
|  | ||||
| 	while((selret = select(fdmax+1,&rfds,&wfds,NULL,&tv))) { | ||||
| 		if(FD_ISSET(listenSocket,&rfds)) getConnections(listenSocket); | ||||
| 		if(selret<0 && errno==EINTR) break; | ||||
| 		else if(selret<0) { | ||||
| 			closeNextErroredInterface(); | ||||
| 			continue; | ||||
| 		} | ||||
| 		for(i=0;i<interface_max_connections;i++) { | ||||
| 			if(interfaces[i].open && FD_ISSET(interfaces[i].fd,&rfds)) { | ||||
| 				if(COMMAND_RETURN_KILL==interfaceReadInput(&(interfaces[i]))) { | ||||
| 					return COMMAND_RETURN_KILL; | ||||
| 				} | ||||
| 				interfaces[i].lastTime = time(NULL); | ||||
| 			} | ||||
| 			if(interfaces[i].open && FD_ISSET(interfaces[i].fd,&wfds)) { | ||||
| 				flushInterfaceBuffer(&interfaces[i]); | ||||
| 				interfaces[i].lastTime = time(NULL); | ||||
| 			} | ||||
| 		} | ||||
| 		tv.tv_sec = 0; | ||||
| 		tv.tv_usec = 0; | ||||
| 		fdmax = 0; | ||||
| 		addInterfacesReadyToReadAndListenSocketToFdSet(&rfds,&fdmax); | ||||
| 		addInterfacesForBufferFlushToFdSet(&wfds,&fdmax); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void initInterfaces() { | ||||
| 	int i; | ||||
| 	char * test; | ||||
|  | ||||
| 	interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10); | ||||
| 	if(*test!='\0' || interface_timeout<=0) { | ||||
| 		ERROR("connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10); | ||||
| 	if(*test!='\0' || interface_max_connections<=0) { | ||||
| 		ERROR("max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10); | ||||
| 	if(*test!='\0' || interface_max_command_list_size<=0) { | ||||
| 		ERROR("max command list size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_COMMAND_LIST_SIZE]); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10); | ||||
| 	if(*test!='\0' || interface_max_output_buffer_size<=0) { | ||||
| 		ERROR("max output buffer size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE]); | ||||
| 		exit(-1); | ||||
| 	} | ||||
|  | ||||
| 	interface_max_command_list_size*=1024; | ||||
| 	interface_max_output_buffer_size*=1024; | ||||
|  | ||||
| 	interfaces = malloc(sizeof(Interface)*interface_max_connections); | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		interfaces[i].open = 0; | ||||
| 		interfaces[i].num = i; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void closeAllInterfaces() { | ||||
| 	int i; | ||||
|  | ||||
| 	fflush(NULL); | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open) { | ||||
| 			closeInterface(&(interfaces[i])); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void freeAllInterfaces() { | ||||
| 	closeAllInterfaces(); | ||||
|  | ||||
| 	free(interfaces); | ||||
| } | ||||
|  | ||||
| void closeOldInterfaces() { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open && (interfaces[i].expired || (time(NULL)-interfaces[i].lastTime>interface_timeout))) { | ||||
| 			DEBUG("interface %i: timeout\n",i); | ||||
| 			closeInterface(&(interfaces[i])); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void closeInterfaceWithFD(int fd) { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].fd==fd) { | ||||
| 			closeInterface(&(interfaces[i])); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void flushInterfaceBuffer(Interface * interface) { | ||||
| 	ListNode * node = NULL; | ||||
| 	char * str; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	while((node = interface->bufferList->firstNode)) { | ||||
| 		str = (char *)node->data; | ||||
| 		if((ret = write(interface->fd,str,strlen(str)))<0) break; | ||||
| 		else if(ret<strlen(str)) { | ||||
| 			interface->outputBufferSize-=ret; | ||||
| 			str = strdup(&str[ret]); | ||||
| 			free(node->data); | ||||
| 			node->data = str; | ||||
| 		} | ||||
| 		else { | ||||
| 			interface->outputBufferSize-= strlen(str)+1; | ||||
| 			interface->outputBufferSize-= sizeof(ListNode); | ||||
| 			deleteNodeFromList(interface->bufferList,node); | ||||
| 		} | ||||
| 		interface->lastTime = time(NULL); | ||||
| 	} | ||||
|  | ||||
| 	if(!interface->bufferList->firstNode) { | ||||
| 		DEBUG("interface %i: buffer empty\n",interface->num); | ||||
| 		freeList(interface->bufferList); | ||||
| 		interface->bufferList = NULL; | ||||
| 	} | ||||
| 	else if(ret<0 && errno!=EAGAIN && errno!=EINTR) { | ||||
| 		/* cause interface to close */ | ||||
| 		DEBUG("interface %i: problems flushing buffer\n", | ||||
| 			interface->num); | ||||
| 		freeList(interface->bufferList); | ||||
| 		interface->bufferList = NULL; | ||||
| 		interface->expired = 1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void flushAllInterfaceBuffers() { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open && !interfaces[i].expired && interfaces[i].bufferList) { | ||||
| 			flushInterfaceBuffer(&interfaces[i]); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int interfacePrintWithFD(int fd,char * buffer) { | ||||
| 	int i; | ||||
| 	int buflen; | ||||
| 	int copylen; | ||||
| 	Interface * interface; | ||||
|  | ||||
| 	if(!(buflen = strlen(buffer))) return -1; | ||||
|  | ||||
| 	for(i=0;i<interface_max_connections;i++) { | ||||
| 		if(interfaces[i].open && interfaces[i].fd==fd) break; | ||||
| 	} | ||||
|  | ||||
| 	/* if fd isn't found or interfaces is going to be closed, do nothing */ | ||||
| 	if(i==interface_max_connections) return -1; | ||||
| 	if(interfaces[i].expired) return 0; | ||||
|  | ||||
| 	interface = interfaces+i; | ||||
|  | ||||
| 	while(buflen>0) { | ||||
| 		copylen = buflen> | ||||
| 			interface->outBufSize-interface->outBuflen? | ||||
| 			interface->outBufSize-interface->outBuflen: | ||||
| 			buflen; | ||||
| 		memcpy(interface->outBuffer+interface->outBuflen,buffer, | ||||
| 			copylen); | ||||
| 		buflen-=copylen; | ||||
| 		interface->outBuflen+=copylen; | ||||
| 		buffer+=copylen; | ||||
| 		if(interface->outBuflen>=interface->outBufSize) { | ||||
| 			printInterfaceOutBuffer(interface); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void printInterfaceOutBuffer(Interface * interface) { | ||||
| 	char * buffer; | ||||
| 	int ret; | ||||
|  | ||||
| 	if(!interface->open || interface->expired || !interface->outBuflen) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if(interface->bufferList) { | ||||
| 		interface->outputBufferSize+=sizeof(ListNode); | ||||
| 		interface->outputBufferSize+=interface->outBuflen+1; | ||||
| 		if(interface->outputBufferSize> | ||||
| 				interface_max_output_buffer_size) | ||||
|  		{ | ||||
| 			ERROR("interface %i: output buffer size (%lli) is " | ||||
| 					"larger than the max (%lli)\n", | ||||
| 					interface->num, | ||||
| 					interface->outputBufferSize, | ||||
| 					interface_max_output_buffer_size); | ||||
| 			/* cause interface to close */ | ||||
| 			freeList(interface->bufferList); | ||||
| 			interface->bufferList = NULL; | ||||
| 			interface->expired = 1; | ||||
| 		} | ||||
| 		else { | ||||
| 			buffer = malloc(interface->outBuflen+1); | ||||
| 			memcpy(buffer,interface->outBuffer,interface->outBuflen); | ||||
| 			buffer[interface->outBuflen] = '\0'; | ||||
| 			insertInListWithoutKey(interface->bufferList,(void *)buffer); | ||||
| 			flushInterfaceBuffer(interface); | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		if((ret = write(interface->fd,interface->outBuffer, | ||||
| 				interface->outBuflen))<0)  | ||||
| 		{ | ||||
| 			if(errno==EAGAIN || errno==EINTR) { | ||||
| 				buffer = malloc(interface->outBuflen+1); | ||||
| 				memcpy(buffer,interface->outBuffer, | ||||
| 						interface->outBuflen); | ||||
| 				buffer[interface->outBuflen] = '\0'; | ||||
| 				interface->bufferList = makeList(free); | ||||
| 				insertInListWithoutKey(interface->bufferList, | ||||
| 						(void *)buffer); | ||||
| 			} | ||||
| 			else { | ||||
| 				DEBUG("interface %i: problems writing\n", | ||||
| 						interface->num); | ||||
| 				interface->expired = 1; | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 		else if(ret<interface->outBuflen) { | ||||
| 			buffer = malloc(interface->outBuflen-ret+1); | ||||
| 			memcpy(buffer,interface->outBuffer+ret, | ||||
| 					interface->outBuflen-ret); | ||||
| 			buffer[interface->outBuflen-ret] = '\0'; | ||||
| 			interface->bufferList = makeList(free); | ||||
| 			insertInListWithoutKey(interface->bufferList,buffer); | ||||
| 		} | ||||
| 		/* if we needed to create buffer, initialize bufferSize info */ | ||||
| 		if(interface->bufferList) { | ||||
| 			DEBUG("interface %i: buffer created\n",interface->num); | ||||
| 			interface->outputBufferSize = sizeof(List); | ||||
| 			interface->outputBufferSize+=sizeof(ListNode); | ||||
| 			interface->outputBufferSize+=strlen( | ||||
| 					(char *)interface->bufferList-> | ||||
| 					firstNode->data)+1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	interface->outBuflen = 0; | ||||
| } | ||||
							
								
								
									
										38
									
								
								src/interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/interface.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* the Music Player Daemon (MPD) | ||||
|  * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu) | ||||
|  * This project's homepage is: http://www.musicpd.org | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef INTERFACE_H | ||||
| #define INTERFACE_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
|  | ||||
| void initInterfaces(); | ||||
| void openAInterface(int fd, struct sockaddr * addr); | ||||
| void closeAllInterfaces(); | ||||
| void freeAllInterfaces(); | ||||
| void closeOldInterfaces(); | ||||
| void closeInterfaceWithFD(int fd); | ||||
| void flushAllInterfaceBuffers(); | ||||
| int interfacePrintWithFD(int fd, char * buffer); | ||||
|  | ||||
| int doIOForInterfaces(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										75
									
								
								src/libid3tag/CHANGES
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/libid3tag/CHANGES
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
|  | ||||
|  libid3tag - ID3 tag manipulation library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: CHANGES,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| Version 0.15.0 (beta) | ||||
|  | ||||
|   * Updated to autoconf 2.57, automake 1.7.5, libtool 1.4.3. | ||||
|  | ||||
|   * Added new id3_tag_version(), id3_tag_options(), id3_tag_setlength(), | ||||
|     id3_frame_field(), id3_field_getlatin1(), id3_field_getfulllatin1(), | ||||
|     id3_genre_index(), id3_genre_number(), id3_latin1_ucs4duplicate(), | ||||
|     id3_utf16_ucs4duplicate(), and id3_utf8_ucs4duplicate() API routines. | ||||
|  | ||||
|   * Properly exposed the id3_frame_new(), id3_frame_delete(), and | ||||
|     id3_field_type() API routines. | ||||
|  | ||||
|   * Fixed a possible segmentation fault rendering ID3v1 tags when a tag | ||||
|     field exceeds the field length limit. | ||||
|  | ||||
|   * Fixed a problem whereby the file interface could try to seek and read | ||||
|     data from a non-seekable stream, unrecoverably losing data from the | ||||
|     stream. (N.B. the fix does not work under Win32.) | ||||
|  | ||||
|   * Fixed a problem reading ID3v2.2 frames which corrupted their frame IDs | ||||
|     and caused them not to be re-rendered. | ||||
|  | ||||
|   * Improved rendering of the ID3v1 genre field from ID3v2 genre | ||||
|     names/numbers. The genre "Other" is used in place of non-translatable | ||||
|     genres. | ||||
|  | ||||
|   * Rendering an empty ID3v1 tag now properly returns 0 length even when a | ||||
|     null buffer pointer is passed. | ||||
|  | ||||
|   * Changed the file implementation to maintain information about present | ||||
|     but unparseable tags, instead of ignoring all tags and returning an | ||||
|     error. | ||||
|  | ||||
|   * Added an external dependency on zlib (libz), which is no longer | ||||
|     included. | ||||
|  | ||||
|   * Changed to build a shared library by default. | ||||
|  | ||||
|   * Changed to use native Cygwin build by default; give --host=mingw32 to | ||||
|     `configure' to use MinGW (and avoid a dependency on the Cygwin DLL). | ||||
|  | ||||
| Version 0.14.2 (beta) | ||||
|  | ||||
|   * Changed Cygwin builds to use MinGW; resulting Win32 executables no | ||||
|     longer have a dependency on Cygwin DLLs. | ||||
|  | ||||
| Version 0.14.1 (beta) | ||||
|  | ||||
|   * Updated config.guess and config.sub to latest upstream versions. | ||||
|  | ||||
|   * Enabled libtool versioning rather than release numbering. | ||||
|  | ||||
|   * Renamed `libid3' to `libid3tag' and enabled installation as a separate | ||||
|     library. | ||||
|  | ||||
|   * Several other small fixes. | ||||
|  | ||||
| Version 0.14.0 (beta) | ||||
|  | ||||
|   * Added a new ID3 tag manipulation library (libid3). The required zlib | ||||
|     support is provided either by the host system or by the included static | ||||
|     library implementation (libz). | ||||
|  | ||||
|   * Improved MSVC++ portability and added MSVC++ project files. | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
							
								
								
									
										340
									
								
								src/libid3tag/COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								src/libid3tag/COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||
|      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Library General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
|  | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if you | ||||
| distribute copies of the software, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
|  | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
|  | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| patent must be licensed for everyone's free use or not licensed at all. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
|  | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
|  | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
|  | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
|  | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
|  | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
|  | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
|  | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
|  | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
|  | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  However, as a | ||||
| special exception, the source code distributed need not include | ||||
| anything that is normally distributed (in either source or binary | ||||
| form) with the major components (compiler, kernel, and so on) of the | ||||
| operating system on which the executable runs, unless that component | ||||
| itself accompanies the executable. | ||||
|  | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
|  | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
|  | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program subject to | ||||
| these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
|  | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
|  | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the General Public License from time to time.  Such new versions will | ||||
| be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
|  | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| make exceptions for this.  Our decision will be guided by the two goals | ||||
| of preserving the free status of all derivatives of our free software and | ||||
| of promoting the sharing and reuse of software generally. | ||||
|  | ||||
| 			    NO WARRANTY | ||||
|  | ||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
|  | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
| 	    How to Apply These Terms to Your New Programs | ||||
|  | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     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 | ||||
|  | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
|  | ||||
|     Gnomovision version 69, Copyright (C) year  name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
|  | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Library General | ||||
| Public License instead of this License. | ||||
							
								
								
									
										21
									
								
								src/libid3tag/COPYRIGHT
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/libid3tag/COPYRIGHT
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
|  | ||||
|  libid3tag - ID3 tag manipulation library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  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 | ||||
|  | ||||
|  If you would like to negotiate alternate licensing terms, you may do | ||||
|  so by contacting: Underbit Technologies, Inc. <info@underbit.com> | ||||
|  | ||||
							
								
								
									
										28
									
								
								src/libid3tag/CREDITS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/libid3tag/CREDITS
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
|  | ||||
|  libid3tag - ID3 tag manipulation library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: CREDITS,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| AUTHOR | ||||
|  | ||||
|   Except where otherwise noted, all code was authored by: | ||||
|  | ||||
|       Robert Leslie <rob@underbit.com> | ||||
|  | ||||
| CONTRIBUTORS | ||||
|  | ||||
|   Significant contributions have been incorporated with thanks to: | ||||
|  | ||||
|       Mark Malson <mark@mmalson.com> | ||||
|         2002/10/09: frame.c | ||||
|           - Reported problem reading ID3v2.2 tag frames. | ||||
|  | ||||
|       Brett Paterson <brett@fmod.org> | ||||
|         2001/10/28: global.h | ||||
|           - Reported missing <assert.h> et al. under MS Embedded Visual C. | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
							
								
								
									
										183
									
								
								src/libid3tag/INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/libid3tag/INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| Basic Installation | ||||
| ================== | ||||
|  | ||||
|    These are generic installation instructions. | ||||
|  | ||||
|    The `configure' shell script attempts to guess correct values for | ||||
| various system-dependent variables used during compilation.  It uses | ||||
| those values to create a `Makefile' in each directory of the package. | ||||
| It may also create one or more `.h' files containing system-dependent | ||||
| definitions.  Finally, it creates a shell script `config.status' that | ||||
| you can run in the future to recreate the current configuration, a file | ||||
| `config.cache' that saves the results of its tests to speed up | ||||
| reconfiguring, and a file `config.log' containing compiler output | ||||
| (useful mainly for debugging `configure'). | ||||
|  | ||||
|    If you need to do unusual things to compile the package, please try | ||||
| to figure out how `configure' could check whether to do them, and mail | ||||
| diffs or instructions to the address given in the `README' so they can | ||||
| be considered for the next release.  If at some point `config.cache' | ||||
| contains results you don't want to keep, you may remove or edit it. | ||||
|  | ||||
|    The file `configure.in' is used to create `configure' by a program | ||||
| called `autoconf'.  You only need `configure.in' if you want to change | ||||
| it or regenerate `configure' using a newer version of `autoconf'. | ||||
|  | ||||
| The simplest way to compile this package is: | ||||
|  | ||||
|   1. `cd' to the directory containing the package's source code and type | ||||
|      `./configure' to configure the package for your system.  If you're | ||||
|      using `csh' on an old version of System V, you might need to type | ||||
|      `sh ./configure' instead to prevent `csh' from trying to execute | ||||
|      `configure' itself. | ||||
|  | ||||
|      Running `configure' takes awhile.  While running, it prints some | ||||
|      messages telling which features it is checking for. | ||||
|  | ||||
|   2. Type `make' to compile the package. | ||||
|  | ||||
|   3. Optionally, type `make check' to run any self-tests that come with | ||||
|      the package. | ||||
|  | ||||
|   4. Type `make install' to install the programs and any data files and | ||||
|      documentation. | ||||
|  | ||||
|   5. You can remove the program binaries and object files from the | ||||
|      source code directory by typing `make clean'.  To also remove the | ||||
|      files that `configure' created (so you can compile the package for | ||||
|      a different kind of computer), type `make distclean'.  There is | ||||
|      also a `make maintainer-clean' target, but that is intended mainly | ||||
|      for the package's developers.  If you use it, you may have to get | ||||
|      all sorts of other programs in order to regenerate files that came | ||||
|      with the distribution. | ||||
|  | ||||
| Compilers and Options | ||||
| ===================== | ||||
|  | ||||
|    Some systems require unusual options for compilation or linking that | ||||
| the `configure' script does not know about.  You can give `configure' | ||||
| initial values for variables by setting them in the environment.  Using | ||||
| a Bourne-compatible shell, you can do that on the command line like | ||||
| this: | ||||
|      CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure | ||||
|  | ||||
| Or on systems that have the `env' program, you can do it like this: | ||||
|      env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure | ||||
|  | ||||
| Compiling For Multiple Architectures | ||||
| ==================================== | ||||
|  | ||||
|    You can compile the package for more than one kind of computer at the | ||||
| same time, by placing the object files for each architecture in their | ||||
| own directory.  To do this, you must use a version of `make' that | ||||
| supports the `VPATH' variable, such as GNU `make'.  `cd' to the | ||||
| directory where you want the object files and executables to go and run | ||||
| the `configure' script.  `configure' automatically checks for the | ||||
| source code in the directory that `configure' is in and in `..'. | ||||
|  | ||||
|    If you have to use a `make' that does not supports the `VPATH' | ||||
| variable, you have to compile the package for one architecture at a time | ||||
| in the source code directory.  After you have installed the package for | ||||
| one architecture, use `make distclean' before reconfiguring for another | ||||
| architecture. | ||||
|  | ||||
| Installation Names | ||||
| ================== | ||||
|  | ||||
|    By default, `make install' will install the package's files in | ||||
| `/usr/local/bin', `/usr/local/man', etc.  You can specify an | ||||
| installation prefix other than `/usr/local' by giving `configure' the | ||||
| option `--prefix=PATH'. | ||||
|  | ||||
|    You can specify separate installation prefixes for | ||||
| architecture-specific files and architecture-independent files.  If you | ||||
| give `configure' the option `--exec-prefix=PATH', the package will use | ||||
| PATH as the prefix for installing programs and libraries. | ||||
| Documentation and other data files will still use the regular prefix. | ||||
|  | ||||
|    In addition, if you use an unusual directory layout you can give | ||||
| options like `--bindir=PATH' to specify different values for particular | ||||
| kinds of files.  Run `configure --help' for a list of the directories | ||||
| you can set and what kinds of files go in them. | ||||
|  | ||||
|    If the package supports it, you can cause programs to be installed | ||||
| with an extra prefix or suffix on their names by giving `configure' the | ||||
| option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | ||||
|  | ||||
| Optional Features | ||||
| ================= | ||||
|  | ||||
|    Some packages pay attention to `--enable-FEATURE' options to | ||||
| `configure', where FEATURE indicates an optional part of the package. | ||||
| They may also pay attention to `--with-PACKAGE' options, where PACKAGE | ||||
| is something like `gnu-as' or `x' (for the X Window System).  The | ||||
| `README' should mention any `--enable-' and `--with-' options that the | ||||
| package recognizes. | ||||
|  | ||||
|    For packages that use the X Window System, `configure' can usually | ||||
| find the X include and library files automatically, but if it doesn't, | ||||
| you can use the `configure' options `--x-includes=DIR' and | ||||
| `--x-libraries=DIR' to specify their locations. | ||||
|  | ||||
| Specifying the System Type | ||||
| ========================== | ||||
|  | ||||
|    There may be some features `configure' can not figure out | ||||
| automatically, but needs to determine by the type of host the package | ||||
| will run on.  Usually `configure' can figure that out, but if it prints | ||||
| a message saying it can not guess the host type, give it the | ||||
| `--host=TYPE' option.  TYPE can either be a short name for the system | ||||
| type, such as `sun4', or a canonical name with three fields: | ||||
|      CPU-COMPANY-SYSTEM | ||||
|  | ||||
| See the file `config.sub' for the possible values of each field.  If | ||||
| `config.sub' isn't included in this package, then this package doesn't | ||||
| need to know the host type. | ||||
|  | ||||
|    If you are building compiler tools for cross-compiling, you can also | ||||
| use the `--target=TYPE' option to select the type of system they will | ||||
| produce code for and the `--build=TYPE' option to select the type of | ||||
| system on which you are compiling the package. | ||||
|  | ||||
| Sharing Defaults | ||||
| ================ | ||||
|  | ||||
|    If you want to set default values for `configure' scripts to share, | ||||
| you can create a site shell script called `config.site' that gives | ||||
| default values for variables like `CC', `cache_file', and `prefix'. | ||||
| `configure' looks for `PREFIX/share/config.site' if it exists, then | ||||
| `PREFIX/etc/config.site' if it exists.  Or, you can set the | ||||
| `CONFIG_SITE' environment variable to the location of the site script. | ||||
| A warning: not all `configure' scripts look for a site script. | ||||
|  | ||||
| Operation Controls | ||||
| ================== | ||||
|  | ||||
|    `configure' recognizes the following options to control how it | ||||
| operates. | ||||
|  | ||||
| `--cache-file=FILE' | ||||
|      Use and save the results of the tests in FILE instead of | ||||
|      `./config.cache'.  Set FILE to `/dev/null' to disable caching, for | ||||
|      debugging `configure'. | ||||
|  | ||||
| `--help' | ||||
|      Print a summary of the options to `configure', and exit. | ||||
|  | ||||
| `--quiet' | ||||
| `--silent' | ||||
| `-q' | ||||
|      Do not print messages saying which checks are being made.  To | ||||
|      suppress all normal output, redirect it to `/dev/null' (any error | ||||
|      messages will still be shown). | ||||
|  | ||||
| `--srcdir=DIR' | ||||
|      Look for the package's source code in directory DIR.  Usually | ||||
|      `configure' can determine that directory automatically. | ||||
|  | ||||
| `--version' | ||||
|      Print the version of Autoconf used to generate the `configure' | ||||
|      script, and exit. | ||||
|  | ||||
| `configure' also accepts some other, not widely useful, options. | ||||
|  | ||||
							
								
								
									
										123
									
								
								src/libid3tag/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/libid3tag/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| ## | ||||
| ## libid3tag - ID3 tag manipulation library | ||||
| ## Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
| ## | ||||
| ## 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 | ||||
| ## | ||||
| ## $Id: Makefile.am,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
| ## | ||||
|  | ||||
| ## Process this file with automake to produce Makefile.in | ||||
|  | ||||
| SUBDIRS =		 | ||||
| #DIST_SUBDIRS =		msvc++ | ||||
|  | ||||
| noinst_LTLIBRARIES =	libid3tag.la | ||||
| noinst_HEADERS =	id3tag.h | ||||
|  | ||||
| ## From the libtool documentation on library versioning: | ||||
| ## | ||||
| ## CURRENT | ||||
| ##      The most recent interface number that this library implements. | ||||
| ## | ||||
| ## REVISION | ||||
| ##      The implementation number of the CURRENT interface. | ||||
| ## | ||||
| ## AGE | ||||
| ##      The difference between the newest and oldest interfaces that this | ||||
| ##      library implements.  In other words, the library implements all the | ||||
| ##      interface numbers in the range from number `CURRENT - AGE' to | ||||
| ##      `CURRENT'. | ||||
| ## | ||||
| ##    If two libraries have identical CURRENT and AGE numbers, then the | ||||
| ## dynamic linker chooses the library with the greater REVISION number. | ||||
| ## | ||||
| ##   1. Start with version information of `0:0:0' for each libtool library. | ||||
| ## | ||||
| ##   2. Update the version information only immediately before a public | ||||
| ##      release of your software.  More frequent updates are unnecessary, | ||||
| ##      and only guarantee that the current interface number gets larger | ||||
| ##      faster. | ||||
| ## | ||||
| ##   3. If the library source code has changed at all since the last | ||||
| ##      update, then increment REVISION (`C:R:A' becomes `C:r+1:A'). | ||||
| ## | ||||
| ##   4. If any interfaces have been added, removed, or changed since the | ||||
| ##      last update, increment CURRENT, and set REVISION to 0. | ||||
| ## | ||||
| ##   5. If any interfaces have been added since the last public release, | ||||
| ##      then increment AGE. | ||||
| ## | ||||
| ##   6. If any interfaces have been removed since the last public release, | ||||
| ##      then set AGE to 0. | ||||
|  | ||||
| version_current =	2 | ||||
| version_revision =	0 | ||||
| version_age =		2 | ||||
|  | ||||
| version_info =		$(version_current):$(version_revision):$(version_age) | ||||
|  | ||||
| EXTRA_DIST =		genre.dat.sed  \ | ||||
| 			CHANGES COPYRIGHT CREDITS README TODO VERSION | ||||
|  | ||||
| if DEBUG | ||||
| debug = debug.c debug.h | ||||
| else | ||||
| debug = | ||||
| endif | ||||
|  | ||||
| libid3tag_la_SOURCES =	version.c ucs4.c latin1.c utf16.c utf8.c  \ | ||||
| 			parse.c render.c field.c frametype.c compat.c  \ | ||||
| 			genre.c frame.c crc.c util.c tag.c file.c  \ | ||||
| 			version.h ucs4.h latin1.h utf16.h utf8.h  \ | ||||
| 			parse.h render.h field.h frametype.h compat.h  \ | ||||
| 			genre.h frame.h crc.h util.h tag.h file.h  \ | ||||
| 			id3tag.h global.h genre.dat $(debug) | ||||
|  | ||||
| EXTRA_libid3tag_la_SOURCES =  \ | ||||
| 			frametype.gperf compat.gperf genre.dat.in  \ | ||||
| 			debug.c debug.h | ||||
|  | ||||
| libid3tag_la_LDFLAGS =	-version-info $(version_info) | ||||
|  | ||||
| BUILT_SOURCES =		frametype.c compat.c genre.dat | ||||
|  | ||||
| $(srcdir)/frametype.c: $(srcdir)/frametype.gperf Makefile.am | ||||
| 	cd $(srcdir) &&  \ | ||||
| 	gperf -tCcTonD -K id -N id3_frametype_lookup -s -3 -k '*'  \ | ||||
| 		frametype.gperf |  \ | ||||
| 	sed -e 's/\(struct id3_frametype\);/\1/' |  \ | ||||
| 	sed -e '/\$$''Id: /s/\$$//g' >frametype.c | ||||
|  | ||||
| $(srcdir)/compat.c: $(srcdir)/compat.gperf Makefile.am | ||||
| 	cd $(srcdir) &&  \ | ||||
| 	gperf -tCcTonD -K id -N id3_compat_lookup -s -3 -k '*'  \ | ||||
| 		compat.gperf |  \ | ||||
| 	sed -e 's/\(struct id3_compat\);/\1/' |  \ | ||||
| 	sed -e '/\$$''Id: /s/\$$//g' >compat.c | ||||
|  | ||||
| $(srcdir)/genre.dat: $(srcdir)/genre.dat.in $(srcdir)/genre.dat.sed Makefile.am | ||||
| 	cd $(srcdir) &&  \ | ||||
| 	sed -n -f genre.dat.sed genre.dat.in |  \ | ||||
| 	sed -e '/\$$''Id: /s/\$$//g' >genre.dat | ||||
|  | ||||
| libtool: $(LIBTOOL_DEPS) | ||||
| 	$(SHELL) ./config.status --recheck | ||||
|  | ||||
| again: | ||||
| 	$(MAKE) clean | ||||
| 	$(MAKE) | ||||
|  | ||||
| .PHONY: again | ||||
							
								
								
									
										102
									
								
								src/libid3tag/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/libid3tag/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
|  | ||||
|  libid3tag - ID3 tag manipulation library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: README,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| INTRODUCTION | ||||
|  | ||||
|   libid3tag is a library for reading and (eventually) writing ID3 tags, both | ||||
|   ID3v1 and the various versions of ID3v2. | ||||
|  | ||||
|   See the file `id3tag.h' for the current library interface. | ||||
|  | ||||
|   This package uses GNU libtool to arrange for zlib to be linked | ||||
|   automatically when you link your programs with this library. If you aren't | ||||
|   using GNU libtool, in some cases you may need to link with zlib | ||||
|   explicitly: | ||||
|  | ||||
|       ${link_command} ... -lid3tag -lz | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| BUILDING AND INSTALLING | ||||
|  | ||||
|   Note that this library depends on zlib 1.1.4 or later. If you don't have | ||||
|   zlib already, you can obtain it from: | ||||
|  | ||||
|       http://www.gzip.org/zlib/ | ||||
|  | ||||
|   You must have zlib installed before you can build this package. | ||||
|  | ||||
| Windows Platforms | ||||
|  | ||||
|   libid3tag can be built under Windows using either MSVC++ or Cygwin. A | ||||
|   MSVC++ project file can be found under the `msvc++' subdirectory. | ||||
|  | ||||
|   To build libid3tag using Cygwin, you will first need to install the Cygwin | ||||
|   tools: | ||||
|  | ||||
|       http://www.cygwin.com/ | ||||
|  | ||||
|   You may then proceed with the following POSIX instructions within the | ||||
|   Cygwin shell. | ||||
|  | ||||
|   Note that by default Cygwin will build a library that depends on the | ||||
|   Cygwin DLL. You can use MinGW to build a library that does not depend on | ||||
|   the Cygwin DLL. To do so, give the option --host=mingw32 to `configure'. | ||||
|   Be certain you also link with a MinGW version of zlib. | ||||
|  | ||||
| POSIX Platforms (including Cygwin) | ||||
|  | ||||
|   The code is distributed with a `configure' script that will generate for | ||||
|   you a `Makefile' and a `config.h' for your platform. See the file | ||||
|   `INSTALL' for generic instructions. | ||||
|  | ||||
|   The specific options you may want to give `configure' are: | ||||
|  | ||||
|       --disable-debugging       do not compile with debugging support, and | ||||
|                                 use more optimizations | ||||
|  | ||||
|       --disable-shared          do not build a shared library | ||||
|  | ||||
|   By default the package will build a shared library if possible for your | ||||
|   platform. If you want only a static library, use --disable-shared. | ||||
|  | ||||
|   If zlib is installed in an unusual place or `configure' can't find it, you | ||||
|   may need to indicate where it is: | ||||
|  | ||||
|       ./configure ... CPPFLAGS="-I${include_dir}" LDFLAGS="-L${lib_dir}" | ||||
|  | ||||
|   where ${include_dir} and ${lib_dir} are the locations of the installed | ||||
|   header and library files, respectively. | ||||
|  | ||||
| Experimenting and Developing | ||||
|  | ||||
|   Further options for `configure' that may be useful to developers and | ||||
|   experimenters are: | ||||
|  | ||||
|       --enable-debugging        enable diagnostic debugging support and | ||||
|                                 debugging symbols | ||||
|  | ||||
|       --enable-profiling        generate `gprof' profiling code | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| COPYRIGHT | ||||
|  | ||||
|   Please read the `COPYRIGHT' file for copyright and warranty information. | ||||
|   Also, the file `COPYING' contains the full text of the GNU GPL. | ||||
|  | ||||
|   Send inquiries, comments, bug reports, suggestions, patches, etc. to: | ||||
|  | ||||
|       Underbit Technologies, Inc. <support@underbit.com> | ||||
|  | ||||
|   See also the MAD home page on the Web: | ||||
|  | ||||
|       http://www.underbit.com/products/mad/ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/libid3tag/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/libid3tag/TODO
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
|  | ||||
|  libid3tag - ID3 tag manipulation library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: TODO,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| libid3tag: | ||||
|   - finish file API | ||||
|   - fix API headers | ||||
|  | ||||
							
								
								
									
										6
									
								
								src/libid3tag/VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/libid3tag/VERSION
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| 0.15.0b | ||||
| configure.ac:24 | ||||
| id3tag.h:334-337 | ||||
| msvc++/config.h:57 | ||||
|  | ||||
| Makefile.am:63-65 | ||||
							
								
								
									
										297
									
								
								src/libid3tag/compat.gperf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								src/libid3tag/compat.gperf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,297 @@ | ||||
| %{ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: compat.gperf,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
| # include <string.h> | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "compat.h" | ||||
| # include "frame.h" | ||||
| # include "field.h" | ||||
| # include "parse.h" | ||||
| # include "ucs4.h" | ||||
|  | ||||
| # define EQ(id)    #id, 0 | ||||
| # define OBSOLETE    0, 0 | ||||
| # define TX(id)    #id, translate_##id | ||||
|  | ||||
| static id3_compat_func_t translate_TCON; | ||||
| %} | ||||
| struct id3_compat; | ||||
| %% | ||||
| # | ||||
| # ID3v2.2 and ID3v2.3 frames | ||||
| # | ||||
| # Only obsolete frames or frames with an equivalent ID3v2.4 frame ID are | ||||
| # listed here. If a frame ID is not listed, it is assumed that the same | ||||
| # frame ID is itself the equivalent ID3v2.4 frame ID. | ||||
| # | ||||
| # This list may also include frames with new content interpretations; the | ||||
| # translation function will rewrite the contents to comply with ID3v2.4. | ||||
| # | ||||
| BUF,  EQ(RBUF)  /* Recommended buffer size */ | ||||
| CNT,  EQ(PCNT)  /* Play counter */ | ||||
| COM,  EQ(COMM)  /* Comments */ | ||||
| CRA,  EQ(AENC)  /* Audio encryption */ | ||||
| CRM,  OBSOLETE  /* Encrypted meta frame [obsolete] */ | ||||
| EQU,  OBSOLETE  /* Equalization [obsolete] */ | ||||
| EQUA, OBSOLETE  /* Equalization [obsolete] */ | ||||
| ETC,  EQ(ETCO)  /* Event timing codes */ | ||||
| GEO,  EQ(GEOB)  /* General encapsulated object */ | ||||
| IPL,  EQ(TIPL)  /* Involved people list */ | ||||
| IPLS, EQ(TIPL)  /* Involved people list */ | ||||
| LNK,  EQ(LINK)  /* Linked information */ | ||||
| MCI,  EQ(MCDI)  /* Music CD identifier */ | ||||
| MLL,  EQ(MLLT)  /* MPEG location lookup table */ | ||||
| PIC,  EQ(APIC)  /* Attached picture */ | ||||
| POP,  EQ(POPM)  /* Popularimeter */ | ||||
| REV,  EQ(RVRB)  /* Reverb */ | ||||
| RVA,  OBSOLETE  /* Relative volume adjustment [obsolete] */ | ||||
| RVAD, OBSOLETE  /* Relative volume adjustment [obsolete] */ | ||||
| SLT,  EQ(SYLT)  /* Synchronised lyric/text */ | ||||
| STC,  EQ(SYTC)  /* Synchronised tempo codes */ | ||||
| TAL,  EQ(TALB)  /* Album/movie/show title */ | ||||
| TBP,  EQ(TBPM)  /* BPM (beats per minute) */ | ||||
| TCM,  EQ(TCOM)  /* Composer */ | ||||
| TCO,  TX(TCON)  /* Content type */ | ||||
| TCON, TX(TCON)  /* Content type */ | ||||
| TCR,  EQ(TCOP)  /* Copyright message */ | ||||
| TDA,  OBSOLETE  /* Date [obsolete] */ | ||||
| TDAT, OBSOLETE  /* Date [obsolete] */ | ||||
| TDY,  EQ(TDLY)  /* Playlist delay */ | ||||
| TEN,  EQ(TENC)  /* Encoded by */ | ||||
| TFT,  EQ(TFLT)  /* File type */ | ||||
| TIM,  OBSOLETE  /* Time [obsolete] */ | ||||
| TIME, OBSOLETE  /* Time [obsolete] */ | ||||
| TKE,  EQ(TKEY)  /* Initial key */ | ||||
| TLA,  EQ(TLAN)  /* Language(s) */ | ||||
| TLE,  EQ(TLEN)  /* Length */ | ||||
| TMT,  EQ(TMED)  /* Media type */ | ||||
| TOA,  EQ(TOPE)  /* Original artist(s)/performer(s) */ | ||||
| TOF,  EQ(TOFN)  /* Original filename */ | ||||
| TOL,  EQ(TOLY)  /* Original lyricist(s)/text writer(s) */ | ||||
| TOR,  EQ(TDOR)  /* Original release year [obsolete] */ | ||||
| TORY, EQ(TDOR)  /* Original release year [obsolete] */ | ||||
| TOT,  EQ(TOAL)  /* Original album/movie/show title */ | ||||
| TP1,  EQ(TPE1)  /* Lead performer(s)/soloist(s) */ | ||||
| TP2,  EQ(TPE2)  /* Band/orchestra/accompaniment */ | ||||
| TP3,  EQ(TPE3)  /* Conductor/performer refinement */ | ||||
| TP4,  EQ(TPE4)  /* Interpreted, remixed, or otherwise modified by */ | ||||
| TPA,  EQ(TPOS)  /* Part of a set */ | ||||
| TPB,  EQ(TPUB)  /* Publisher */ | ||||
| TRC,  EQ(TSRC)  /* ISRC (international standard recording code) */ | ||||
| TRD,  OBSOLETE  /* Recording dates [obsolete] */ | ||||
| TRDA, OBSOLETE  /* Recording dates [obsolete] */ | ||||
| TRK,  EQ(TRCK)  /* Track number/position in set */ | ||||
| TSI,  OBSOLETE  /* Size [obsolete] */ | ||||
| TSIZ, OBSOLETE  /* Size [obsolete] */ | ||||
| TSS,  EQ(TSSE)  /* Software/hardware and settings used for encoding */ | ||||
| TT1,  EQ(TIT1)  /* Content group description */ | ||||
| TT2,  EQ(TIT2)  /* Title/songname/content description */ | ||||
| TT3,  EQ(TIT3)  /* Subtitle/description refinement */ | ||||
| TXT,  EQ(TEXT)  /* Lyricist/text writer */ | ||||
| TXX,  EQ(TXXX)  /* User defined text information frame */ | ||||
| TYE,  OBSOLETE  /* Year [obsolete] */ | ||||
| TYER, OBSOLETE  /* Year [obsolete] */ | ||||
| UFI,  EQ(UFID)  /* Unique file identifier */ | ||||
| ULT,  EQ(USLT)  /* Unsynchronised lyric/text transcription */ | ||||
| WAF,  EQ(WOAF)  /* Official audio file webpage */ | ||||
| WAR,  EQ(WOAR)  /* Official artist/performer webpage */ | ||||
| WAS,  EQ(WOAS)  /* Official audio source webpage */ | ||||
| WCM,  EQ(WCOM)  /* Commercial information */ | ||||
| WCP,  EQ(WCOP)  /* Copyright/legal information */ | ||||
| WPB,  EQ(WPUB)  /* Publishers official webpage */ | ||||
| WXX,  EQ(WXXX)  /* User defined URL link frame */ | ||||
| %% | ||||
|  | ||||
| static | ||||
| int translate_TCON(struct id3_frame *frame, char const *oldid, | ||||
| 		   id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t const *end; | ||||
|   enum id3_field_textencoding encoding; | ||||
|   id3_ucs4_t *string = 0, *ptr, *endptr; | ||||
|   int result = 0; | ||||
|  | ||||
|   /* translate old TCON syntax into multiple strings */ | ||||
|  | ||||
|   assert(frame->nfields == 2); | ||||
|  | ||||
|   encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; | ||||
|  | ||||
|   end = data + length; | ||||
|  | ||||
|   if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   string = id3_parse_string(&data, end - data, encoding, 0); | ||||
|   if (string == 0) | ||||
|     goto fail; | ||||
|  | ||||
|   ptr = string; | ||||
|   while (*ptr == '(') { | ||||
|     if (*++ptr == '(') | ||||
|       break; | ||||
|  | ||||
|     endptr = ptr; | ||||
|     while (*endptr && *endptr != ')') | ||||
|       ++endptr; | ||||
|  | ||||
|     if (*endptr) | ||||
|       *endptr++ = 0; | ||||
|  | ||||
|     if (id3_field_addstring(&frame->fields[1], ptr) == -1) | ||||
|       goto fail; | ||||
|  | ||||
|     ptr = endptr; | ||||
|   } | ||||
|  | ||||
|   if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     result = -1; | ||||
|   } | ||||
|  | ||||
|   if (string) | ||||
|     free(string); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	compat->fixup() | ||||
|  * DESCRIPTION:	finish compatibility translations | ||||
|  */ | ||||
| int id3_compat_fixup(struct id3_tag *tag) | ||||
| { | ||||
|   struct id3_frame *frame; | ||||
|   unsigned int index; | ||||
|   id3_ucs4_t timestamp[17] = { 0 }; | ||||
|   int result = 0; | ||||
|  | ||||
|   /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ | ||||
|  | ||||
|   /* | ||||
|    * TYE/TYER: YYYY | ||||
|    * TDA/TDAT: DDMM | ||||
|    * TIM/TIME: HHMM | ||||
|    * | ||||
|    * TDRC: yyyy-MM-ddTHH:mm | ||||
|    */ | ||||
|  | ||||
|   index = 0; | ||||
|   while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { | ||||
|     char const *id; | ||||
|     id3_byte_t const *data, *end; | ||||
|     id3_length_t length; | ||||
|     enum id3_field_textencoding encoding; | ||||
|     id3_ucs4_t *string; | ||||
|  | ||||
|     id = id3_field_getframeid(&frame->fields[0]); | ||||
|     assert(id); | ||||
|  | ||||
|     if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && | ||||
| 	strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && | ||||
| 	strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) | ||||
|       continue; | ||||
|  | ||||
|     data = id3_field_getbinarydata(&frame->fields[1], &length); | ||||
|     assert(data); | ||||
|  | ||||
|     if (length < 1) | ||||
|       continue; | ||||
|  | ||||
|     end = data + length; | ||||
|  | ||||
|     encoding = id3_parse_uint(&data, 1); | ||||
|     string   = id3_parse_string(&data, end - data, encoding, 0); | ||||
|  | ||||
|     if (id3_ucs4_length(string) < 4) { | ||||
|       free(string); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (strcmp(id, "TYER") == 0 || | ||||
| 	strcmp(id, "YTYE") == 0) { | ||||
|       timestamp[0] = string[0]; | ||||
|       timestamp[1] = string[1]; | ||||
|       timestamp[2] = string[2]; | ||||
|       timestamp[3] = string[3]; | ||||
|     } | ||||
|     else if (strcmp(id, "TDAT") == 0 || | ||||
| 	     strcmp(id, "YTDA") == 0) { | ||||
|       timestamp[4] = '-'; | ||||
|       timestamp[5] = string[2]; | ||||
|       timestamp[6] = string[3]; | ||||
|       timestamp[7] = '-'; | ||||
|       timestamp[8] = string[0]; | ||||
|       timestamp[9] = string[1]; | ||||
|     } | ||||
|     else {  /* TIME or YTIM */ | ||||
|       timestamp[10] = 'T'; | ||||
|       timestamp[11] = string[0]; | ||||
|       timestamp[12] = string[1]; | ||||
|       timestamp[13] = ':'; | ||||
|       timestamp[14] = string[2]; | ||||
|       timestamp[15] = string[3]; | ||||
|     } | ||||
|  | ||||
|     free(string); | ||||
|   } | ||||
|  | ||||
|   if (timestamp[0]) { | ||||
|     id3_ucs4_t *strings; | ||||
|  | ||||
|     frame = id3_frame_new("TDRC"); | ||||
|     if (frame == 0) | ||||
|       goto fail; | ||||
|  | ||||
|     strings = timestamp; | ||||
|  | ||||
|     if (id3_field_settextencoding(&frame->fields[0], | ||||
| 				  ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || | ||||
| 	id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || | ||||
| 	id3_tag_attachframe(tag, frame) == -1) { | ||||
|       id3_frame_delete(frame); | ||||
|       goto fail; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     result = -1; | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/libid3tag/compat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/libid3tag/compat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: compat.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_COMPAT_H | ||||
| # define LIBID3TAG_COMPAT_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| typedef int id3_compat_func_t(struct id3_frame *, char const *, | ||||
| 			      id3_byte_t const *, id3_length_t); | ||||
|  | ||||
| struct id3_compat { | ||||
|   char const *id; | ||||
|   char const *equiv; | ||||
|   id3_compat_func_t *translate; | ||||
| }; | ||||
|  | ||||
| struct id3_compat const *id3_compat_lookup(register char const *, | ||||
| 					   register unsigned int); | ||||
|  | ||||
| int id3_compat_fixup(struct id3_tag *); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										77
									
								
								src/libid3tag/config.h.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/libid3tag/config.h.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| /* config.h.in.  Generated from configure.ac by autoheader.  */ | ||||
|  | ||||
| /* Define to enable diagnostic debugging support. */ | ||||
| #undef DEBUG | ||||
|  | ||||
| /* Define to 1 if you have the <assert.h> header file. */ | ||||
| #undef HAVE_ASSERT_H | ||||
|  | ||||
| /* Define to 1 if you have the <dlfcn.h> header file. */ | ||||
| #undef HAVE_DLFCN_H | ||||
|  | ||||
| /* Define to 1 if you have the `ftruncate' function. */ | ||||
| #undef HAVE_FTRUNCATE | ||||
|  | ||||
| /* Define to 1 if you have the <inttypes.h> header file. */ | ||||
| #undef HAVE_INTTYPES_H | ||||
|  | ||||
| /* Define to 1 if you have the `z' library (-lz). */ | ||||
| #undef HAVE_LIBZ | ||||
|  | ||||
| /* Define to 1 if you have the <memory.h> header file. */ | ||||
| #undef HAVE_MEMORY_H | ||||
|  | ||||
| /* Define to 1 if you have the <stdint.h> header file. */ | ||||
| #undef HAVE_STDINT_H | ||||
|  | ||||
| /* Define to 1 if you have the <stdlib.h> header file. */ | ||||
| #undef HAVE_STDLIB_H | ||||
|  | ||||
| /* Define to 1 if you have the <strings.h> header file. */ | ||||
| #undef HAVE_STRINGS_H | ||||
|  | ||||
| /* Define to 1 if you have the <string.h> header file. */ | ||||
| #undef HAVE_STRING_H | ||||
|  | ||||
| /* Define to 1 if you have the <sys/stat.h> header file. */ | ||||
| #undef HAVE_SYS_STAT_H | ||||
|  | ||||
| /* Define to 1 if you have the <sys/types.h> header file. */ | ||||
| #undef HAVE_SYS_TYPES_H | ||||
|  | ||||
| /* Define to 1 if you have the <unistd.h> header file. */ | ||||
| #undef HAVE_UNISTD_H | ||||
|  | ||||
| /* Define to disable debugging assertions. */ | ||||
| #undef NDEBUG | ||||
|  | ||||
| /* Name of package */ | ||||
| #undef PACKAGE | ||||
|  | ||||
| /* Define to the address where bug reports for this package should be sent. */ | ||||
| #undef PACKAGE_BUGREPORT | ||||
|  | ||||
| /* Define to the full name of this package. */ | ||||
| #undef PACKAGE_NAME | ||||
|  | ||||
| /* Define to the full name and version of this package. */ | ||||
| #undef PACKAGE_STRING | ||||
|  | ||||
| /* Define to the one symbol short name of this package. */ | ||||
| #undef PACKAGE_TARNAME | ||||
|  | ||||
| /* Define to the version of this package. */ | ||||
| #undef PACKAGE_VERSION | ||||
|  | ||||
| /* Define to 1 if you have the ANSI C header files. */ | ||||
| #undef STDC_HEADERS | ||||
|  | ||||
| /* Version number of package */ | ||||
| #undef VERSION | ||||
|  | ||||
| /* Define to empty if `const' does not conform to ANSI C. */ | ||||
| #undef const | ||||
|  | ||||
| /* Define as `__inline' if that's what the C compiler calls it, or to nothing | ||||
|    if it is not supported. */ | ||||
| #undef inline | ||||
							
								
								
									
										205
									
								
								src/libid3tag/configure.ac
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								src/libid3tag/configure.ac
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | ||||
| dnl -*- m4 -*- | ||||
| dnl | ||||
| dnl libid3tag - ID3 tag manipulation library | ||||
| dnl Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
| dnl | ||||
| dnl This program is free software; you can redistribute it and/or modify | ||||
| dnl it under the terms of the GNU General Public License as published by | ||||
| dnl the Free Software Foundation; either version 2 of the License, or | ||||
| dnl (at your option) any later version. | ||||
| dnl | ||||
| dnl This program is distributed in the hope that it will be useful, | ||||
| dnl but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| dnl GNU General Public License for more details. | ||||
| dnl | ||||
| dnl You should have received a copy of the GNU General Public License | ||||
| dnl along with this program; if not, write to the Free Software | ||||
| dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| dnl | ||||
| AC_REVISION([$Id: configure.ac,v 1.1 2003/08/14 03:57:13 shank Exp $])dnl | ||||
|  | ||||
| dnl Process this file with autoconf to produce a configure script. | ||||
|  | ||||
| AC_INIT([ID3 Tag], [0.15.0b], [support@underbit.com], [libid3tag]) | ||||
| AC_PREREQ(2.53) | ||||
|  | ||||
| AC_CONFIG_SRCDIR([id3tag.h]) | ||||
|  | ||||
| AM_INIT_AUTOMAKE | ||||
|  | ||||
| AM_CONFIG_HEADER([config.h]) | ||||
|  | ||||
| dnl System type. | ||||
|  | ||||
| AC_CANONICAL_HOST | ||||
|  | ||||
| dnl Checks for programs. | ||||
|  | ||||
| AC_PROG_CC | ||||
|  | ||||
| if test "$GCC" = yes | ||||
| then | ||||
|     case "$host" in | ||||
| 	*-*-mingw*) | ||||
| 	    case "$build" in | ||||
| 		*-*-cygwin*) | ||||
| 		    CPPFLAGS="$CPPFLAGS -mno-cygwin" | ||||
| 		    LDFLAGS="$LDFLAGS -mno-cygwin" | ||||
| 		    ;; | ||||
| 	    esac | ||||
|     esac | ||||
|  | ||||
| dnl    case "$host" in | ||||
| dnl	*-*-cygwin* | *-*-mingw*) | ||||
| dnl	    LDFLAGS="$LDFLAGS -no-undefined -mdll" | ||||
| dnl	    ;; | ||||
| dnl    esac | ||||
| fi | ||||
|  | ||||
| dnl Support for libtool. | ||||
|  | ||||
| AC_DISABLE_SHARED | ||||
| dnl AC_LIBTOOL_WIN32_DLL | ||||
| AC_PROG_LIBTOOL | ||||
|  | ||||
| AC_SUBST(LIBTOOL_DEPS) | ||||
|  | ||||
| dnl Compiler options. | ||||
|  | ||||
| arch="" | ||||
| debug="" | ||||
| optimize="" | ||||
| profile="" | ||||
|  | ||||
| set -- $CFLAGS | ||||
| CFLAGS="" | ||||
|  | ||||
| if test "$GCC" = yes | ||||
| then | ||||
|     CFLAGS="-Wall" | ||||
| fi | ||||
|  | ||||
| while test $# -gt 0 | ||||
| do | ||||
|     case "$1" in | ||||
| 	-Wall) | ||||
| 	    if test "$GCC" = yes | ||||
| 	    then | ||||
| 		: | ||||
| 	    else | ||||
| 		CFLAGS="$CFLAGS $1" | ||||
| 	    fi | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-g) | ||||
| 	    debug="-g" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-mno-cygwin) | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-m*) | ||||
| 	    arch="$arch $1" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-fomit-frame-pointer) | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-O*|-f*) | ||||
| 	    optimize="$1" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	*) | ||||
| 	    CFLAGS="$CFLAGS $1" | ||||
| 	    shift | ||||
| 	    ;; | ||||
|     esac | ||||
| done | ||||
|  | ||||
| dnl Checks for header files. | ||||
|  | ||||
| AC_HEADER_STDC | ||||
| AC_CHECK_HEADERS(assert.h unistd.h) | ||||
|  | ||||
| AC_CHECK_HEADER(zlib.h, [], [ | ||||
| 	AC_MSG_ERROR([zlib.h was not found | ||||
| *** You must first install zlib (libz) before you can build this package. | ||||
| *** If zlib is already installed, you may need to use the CPPFLAGS | ||||
| *** environment variable to specify its installed location, e.g. -I<dir>.]) | ||||
| ]) | ||||
|  | ||||
| dnl Checks for typedefs, structures, and compiler characteristics. | ||||
|  | ||||
| AC_C_CONST | ||||
| AC_C_INLINE | ||||
|  | ||||
| dnl Checks for library functions. | ||||
|  | ||||
| AC_CHECK_FUNCS(ftruncate) | ||||
|  | ||||
| AC_CHECK_LIB(z, compress2, [], [ | ||||
| 	AC_MSG_ERROR([libz was not found | ||||
| *** You must first install zlib (libz) before you can build this package. | ||||
| *** If zlib is already installed, you may need to use the LDFLAGS | ||||
| *** environment variable to specify its installed location, e.g. -L<dir>.]) | ||||
| ]) | ||||
|  | ||||
| dnl handle --enable and --disable options | ||||
|  | ||||
| AC_CACHE_SAVE | ||||
|  | ||||
| AC_MSG_CHECKING([whether to enable profiling]) | ||||
| AC_ARG_ENABLE(profiling, AC_HELP_STRING([--enable-profiling], | ||||
| 			 [generate profiling code]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) profile="-pg" ;; | ||||
|     esac | ||||
| ]) | ||||
| AC_MSG_RESULT(${enable_profiling-no}) | ||||
|  | ||||
| AC_MSG_CHECKING([whether to enable debugging]) | ||||
| AC_ARG_ENABLE(debugging, AC_HELP_STRING([--enable-debugging], | ||||
| 			 [enable diagnostic debugging support]) | ||||
| AC_HELP_STRING([--disable-debugging], | ||||
| 	       [do not enable debugging and use more optimization]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    AC_DEFINE(DEBUG, 1, | ||||
| 		[Define to enable diagnostic debugging support.]) | ||||
| 	    optimize="" | ||||
| 	    ;; | ||||
| 	no) | ||||
| 	    if test -n "$profile" | ||||
| 	    then | ||||
|     AC_MSG_ERROR(--enable-profiling and --disable-debugging are incompatible) | ||||
| 	    fi | ||||
|  | ||||
| 	    AC_DEFINE(NDEBUG, 1, | ||||
| 		[Define to disable debugging assertions.]) | ||||
| 	    debug="" | ||||
| 	    if test "$GCC" = yes | ||||
| 	    then | ||||
| 		optimize="$optimize -fomit-frame-pointer" | ||||
| 	    fi | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
| AC_MSG_RESULT(${enable_debugging-default}) | ||||
| AM_CONDITIONAL(DEBUG, test ${enable_debugging-default} = yes) | ||||
|  | ||||
| dnl Create output files. | ||||
|  | ||||
| test -n "$arch"     && CFLAGS="$CFLAGS $arch" | ||||
| test -n "$debug"    && CFLAGS="$CFLAGS $debug" | ||||
| test -n "$optimize" && CFLAGS="$CFLAGS $optimize" | ||||
| test -n "$profile"  && CFLAGS="$CFLAGS $profile" LDFLAGS="$LDFLAGS $profile" | ||||
|  | ||||
| dnl LTLIBOBJS=`echo "$LIBOBJS" | sed -e 's/\.o/.lo/g'` | ||||
| dnl AC_SUBST(LTLIBOBJS) | ||||
|  | ||||
| AC_CONFIG_FILES([Makefile \ | ||||
| 	libid3tag.list]) | ||||
| AC_OUTPUT | ||||
							
								
								
									
										137
									
								
								src/libid3tag/crc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/libid3tag/crc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: crc.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "crc.h" | ||||
|  | ||||
| static | ||||
| unsigned long const crc_table[256] = { | ||||
|   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, | ||||
|   0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, | ||||
|   0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, | ||||
|   0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, | ||||
|   0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, | ||||
|   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, | ||||
|   0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, | ||||
|   0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, | ||||
|  | ||||
|   0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, | ||||
|   0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, | ||||
|   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, | ||||
|   0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, | ||||
|   0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, | ||||
|   0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, | ||||
|   0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, | ||||
|   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, | ||||
|  | ||||
|   0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, | ||||
|   0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, | ||||
|   0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, | ||||
|   0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, | ||||
|   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, | ||||
|   0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, | ||||
|   0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, | ||||
|   0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, | ||||
|  | ||||
|   0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, | ||||
|   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, | ||||
|   0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, | ||||
|   0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, | ||||
|   0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, | ||||
|   0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, | ||||
|   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, | ||||
|   0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, | ||||
|  | ||||
|   0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, | ||||
|   0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, | ||||
|   0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, | ||||
|   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, | ||||
|   0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, | ||||
|   0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, | ||||
|   0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, | ||||
|   0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, | ||||
|  | ||||
|   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, | ||||
|   0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, | ||||
|   0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, | ||||
|   0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, | ||||
|   0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, | ||||
|   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, | ||||
|   0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, | ||||
|   0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, | ||||
|  | ||||
|   0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, | ||||
|   0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, | ||||
|   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, | ||||
|   0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, | ||||
|   0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, | ||||
|   0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, | ||||
|   0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, | ||||
|   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, | ||||
|  | ||||
|   0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, | ||||
|   0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, | ||||
|   0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, | ||||
|   0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, | ||||
|   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, | ||||
|   0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, | ||||
|   0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, | ||||
|   0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * NAME:	crc->calculate() | ||||
|  * DESCRIPTION:	compute CRC-32 value (ISO 3309) | ||||
|  */ | ||||
| unsigned long id3_crc_calculate(id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   register unsigned long crc; | ||||
|  | ||||
|   for (crc = 0xffffffffL; length >= 8; length -= 8) { | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|     crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   } | ||||
|  | ||||
|   switch (length) { | ||||
|   case 7: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 6: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 5: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 4: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 3: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 2: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 1: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); | ||||
|   case 0: break; | ||||
|   } | ||||
|  | ||||
|   return crc ^ 0xffffffffL; | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/libid3tag/crc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/libid3tag/crc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: crc.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_CRC_H | ||||
| # define LIBID3TAG_CRC_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| unsigned long id3_crc_calculate(id3_byte_t const *, id3_length_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										222
									
								
								src/libid3tag/debug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								src/libid3tag/debug.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: debug.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # undef malloc | ||||
| # undef calloc | ||||
| # undef realloc | ||||
| # undef free | ||||
|  | ||||
| # include <stdio.h> | ||||
| # include <stdlib.h> | ||||
| # include <string.h> | ||||
|  | ||||
| # include "debug.h" | ||||
|  | ||||
| # if defined(DEBUG) | ||||
|  | ||||
| # define DEBUG_MAGIC  0xdeadbeefL | ||||
|  | ||||
| struct debug { | ||||
|   char const *file; | ||||
|   unsigned int line; | ||||
|   size_t size; | ||||
|   struct debug *next; | ||||
|   struct debug *prev; | ||||
|   long int magic; | ||||
| }; | ||||
|  | ||||
| static struct debug *allocated; | ||||
| static int registered; | ||||
|  | ||||
| static | ||||
| void check(void) | ||||
| { | ||||
|   struct debug *debug; | ||||
|  | ||||
|   for (debug = allocated; debug; debug = debug->next) { | ||||
|     if (debug->magic != DEBUG_MAGIC) { | ||||
|       fprintf(stderr, "memory corruption\n"); | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     fprintf(stderr, "%s:%u: leaked %lu bytes\n", | ||||
| 	    debug->file, debug->line, debug->size); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void *id3_debug_malloc(size_t size, char const *file, unsigned int line) | ||||
| { | ||||
|   struct debug *debug; | ||||
|  | ||||
|   if (!registered) { | ||||
|     atexit(check); | ||||
|     registered = 1; | ||||
|   } | ||||
|  | ||||
|   if (size == 0) | ||||
|     fprintf(stderr, "%s:%u: malloc(0)\n", file, line); | ||||
|  | ||||
|   debug = malloc(sizeof(*debug) + size); | ||||
|   if (debug == 0) { | ||||
|     fprintf(stderr, "%s:%u: malloc(%lu) failed\n", file, line, size); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   debug->magic = DEBUG_MAGIC; | ||||
|  | ||||
|   debug->file = file; | ||||
|   debug->line = line; | ||||
|   debug->size = size; | ||||
|  | ||||
|   debug->next = allocated; | ||||
|   debug->prev = 0; | ||||
|  | ||||
|   if (allocated) | ||||
|     allocated->prev = debug; | ||||
|  | ||||
|   allocated = debug; | ||||
|  | ||||
|   return ++debug; | ||||
| } | ||||
|  | ||||
| void *id3_debug_calloc(size_t nmemb, size_t size, | ||||
| 		       char const *file, unsigned int line) | ||||
| { | ||||
|   void *ptr; | ||||
|  | ||||
|   ptr = id3_debug_malloc(nmemb * size, file, line); | ||||
|   if (ptr) | ||||
|     memset(ptr, 0, nmemb * size); | ||||
|  | ||||
|   return ptr; | ||||
| } | ||||
|  | ||||
| void *id3_debug_realloc(void *ptr, size_t size, | ||||
| 			char const *file, unsigned int line) | ||||
| { | ||||
|   struct debug *debug, *new; | ||||
|  | ||||
|   if (size == 0) { | ||||
|     id3_debug_free(ptr, file, line); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (ptr == 0) | ||||
|     return id3_debug_malloc(size, file, line); | ||||
|  | ||||
|   debug = ptr; | ||||
|   --debug; | ||||
|  | ||||
|   if (debug->magic != DEBUG_MAGIC) { | ||||
|     fprintf(stderr, "%s:%u: realloc(%p, %lu) memory not allocated\n", | ||||
| 	    file, line, ptr, size); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   new = realloc(debug, sizeof(*debug) + size); | ||||
|   if (new == 0) { | ||||
|     fprintf(stderr, "%s:%u: realloc(%p, %lu) failed\n", file, line, ptr, size); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (allocated == debug) | ||||
|     allocated = new; | ||||
|  | ||||
|   debug = new; | ||||
|  | ||||
|   debug->file = file; | ||||
|   debug->line = line; | ||||
|   debug->size = size; | ||||
|  | ||||
|   if (debug->next) | ||||
|     debug->next->prev = debug; | ||||
|   if (debug->prev) | ||||
|     debug->prev->next = debug; | ||||
|  | ||||
|   return ++debug; | ||||
| } | ||||
|  | ||||
| void id3_debug_free(void *ptr, char const *file, unsigned int line) | ||||
| { | ||||
|   struct debug *debug; | ||||
|  | ||||
|   if (ptr == 0) { | ||||
|     fprintf(stderr, "%s:%u: free(0)\n", file, line); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   debug = ptr; | ||||
|   --debug; | ||||
|  | ||||
|   if (debug->magic != DEBUG_MAGIC) { | ||||
|     fprintf(stderr, "%s:%u: free(%p) memory not allocated\n", file, line, ptr); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   debug->magic = 0; | ||||
|  | ||||
|   if (debug->next) | ||||
|     debug->next->prev = debug->prev; | ||||
|   if (debug->prev) | ||||
|     debug->prev->next = debug->next; | ||||
|  | ||||
|   if (allocated == debug) | ||||
|     allocated = debug->next; | ||||
|  | ||||
|   free(debug); | ||||
| } | ||||
|  | ||||
| void *id3_debug_release(void *ptr, char const *file, unsigned int line) | ||||
| { | ||||
|   struct debug *debug; | ||||
|  | ||||
|   if (ptr == 0) | ||||
|     return 0; | ||||
|  | ||||
|   debug = ptr; | ||||
|   --debug; | ||||
|  | ||||
|   if (debug->magic != DEBUG_MAGIC) { | ||||
|     fprintf(stderr, "%s:%u: release(%p) memory not allocated\n", | ||||
| 	    file, line, ptr); | ||||
|     return ptr; | ||||
|   } | ||||
|  | ||||
|   if (debug->next) | ||||
|     debug->next->prev = debug->prev; | ||||
|   if (debug->prev) | ||||
|     debug->prev->next = debug->next; | ||||
|  | ||||
|   if (allocated == debug) | ||||
|     allocated = debug->next; | ||||
|  | ||||
|   memmove(debug, debug + 1, debug->size); | ||||
|  | ||||
|   return debug; | ||||
| } | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										35
									
								
								src/libid3tag/debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/libid3tag/debug.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: debug.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_DEBUG_H | ||||
| # define LIBID3TAG_DEBUG_H | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| void *id3_debug_malloc(size_t, char const *, unsigned int); | ||||
| void *id3_debug_calloc(size_t, size_t, | ||||
| 		       char const *file, unsigned int line); | ||||
| void *id3_debug_realloc(void *, size_t, char const *, unsigned int); | ||||
| void id3_debug_free(void *, char const *, unsigned int); | ||||
|  | ||||
| void *id3_debug_release(void *, char const *, unsigned int); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										875
									
								
								src/libid3tag/field.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										875
									
								
								src/libid3tag/field.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,875 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: field.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
| # include <string.h> | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "field.h" | ||||
| # include "frame.h" | ||||
| # include "render.h" | ||||
| # include "ucs4.h" | ||||
| # include "latin1.h" | ||||
| # include "parse.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->init() | ||||
|  * DESCRIPTION:	initialize a field to a default value for the given type | ||||
|  */ | ||||
| void id3_field_init(union id3_field *field, enum id3_field_type type) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   switch (field->type = type) { | ||||
|   case ID3_FIELD_TYPE_TEXTENCODING: | ||||
|   case ID3_FIELD_TYPE_INT8: | ||||
|   case ID3_FIELD_TYPE_INT16: | ||||
|   case ID3_FIELD_TYPE_INT24: | ||||
|   case ID3_FIELD_TYPE_INT32: | ||||
|     field->number.value = 0; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1: | ||||
|   case ID3_FIELD_TYPE_LATIN1FULL: | ||||
|     field->latin1.ptr = 0; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1LIST: | ||||
|     field->latin1list.nstrings = 0; | ||||
|     field->latin1list.strings  = 0; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRING: | ||||
|   case ID3_FIELD_TYPE_STRINGFULL: | ||||
|     field->string.ptr = 0; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRINGLIST: | ||||
|     field->stringlist.nstrings = 0; | ||||
|     field->stringlist.strings  = 0; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LANGUAGE: | ||||
|     strcpy(field->immediate.value, "XXX"); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_FRAMEID: | ||||
|     strcpy(field->immediate.value, "XXXX"); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_DATE: | ||||
|     memset(field->immediate.value, 0, sizeof(field->immediate.value)); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT32PLUS: | ||||
|   case ID3_FIELD_TYPE_BINARYDATA: | ||||
|     field->binary.data   = 0; | ||||
|     field->binary.length = 0; | ||||
|     break; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->finish() | ||||
|  * DESCRIPTION:	reset a field, deallocating memory if necessary | ||||
|  */ | ||||
| void id3_field_finish(union id3_field *field) | ||||
| { | ||||
|   unsigned int i; | ||||
|  | ||||
|   assert(field); | ||||
|  | ||||
|   switch (field->type) { | ||||
|   case ID3_FIELD_TYPE_TEXTENCODING: | ||||
|   case ID3_FIELD_TYPE_INT8: | ||||
|   case ID3_FIELD_TYPE_INT16: | ||||
|   case ID3_FIELD_TYPE_INT24: | ||||
|   case ID3_FIELD_TYPE_INT32: | ||||
|   case ID3_FIELD_TYPE_LANGUAGE: | ||||
|   case ID3_FIELD_TYPE_FRAMEID: | ||||
|   case ID3_FIELD_TYPE_DATE: | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1: | ||||
|   case ID3_FIELD_TYPE_LATIN1FULL: | ||||
|     if (field->latin1.ptr) | ||||
|       free(field->latin1.ptr); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1LIST: | ||||
|     for (i = 0; i < field->latin1list.nstrings; ++i) | ||||
|       free(field->latin1list.strings[i]); | ||||
|  | ||||
|     if (field->latin1list.strings) | ||||
|       free(field->latin1list.strings); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRING: | ||||
|   case ID3_FIELD_TYPE_STRINGFULL: | ||||
|     if (field->string.ptr) | ||||
|       free(field->string.ptr); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRINGLIST: | ||||
|     for (i = 0; i < field->stringlist.nstrings; ++i) | ||||
|       free(field->stringlist.strings[i]); | ||||
|  | ||||
|     if (field->stringlist.strings) | ||||
|       free(field->stringlist.strings); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT32PLUS: | ||||
|   case ID3_FIELD_TYPE_BINARYDATA: | ||||
|     if (field->binary.data) | ||||
|       free(field->binary.data); | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   id3_field_init(field, field->type); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->type() | ||||
|  * DESCRIPTION:	return the value type of a field | ||||
|  */ | ||||
| enum id3_field_type id3_field_type(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   return field->type; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->parse() | ||||
|  * DESCRIPTION:	parse a field value | ||||
|  */ | ||||
| int id3_field_parse(union id3_field *field, id3_byte_t const **ptr, | ||||
| 		    id3_length_t length, enum id3_field_textencoding *encoding) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   switch (field->type) { | ||||
|   case ID3_FIELD_TYPE_INT32: | ||||
|     if (length < 4) | ||||
|       goto fail; | ||||
|  | ||||
|     field->number.value = id3_parse_uint(ptr, 4); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT24: | ||||
|     if (length < 3) | ||||
|       goto fail; | ||||
|  | ||||
|     field->number.value = id3_parse_uint(ptr, 3); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT16: | ||||
|     if (length < 2) | ||||
|       goto fail; | ||||
|  | ||||
|     field->number.value = id3_parse_uint(ptr, 2); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT8: | ||||
|   case ID3_FIELD_TYPE_TEXTENCODING: | ||||
|     if (length < 1) | ||||
|       goto fail; | ||||
|  | ||||
|     field->number.value = id3_parse_uint(ptr, 1); | ||||
|  | ||||
|     if (field->type == ID3_FIELD_TYPE_TEXTENCODING) | ||||
|       *encoding = field->number.value; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LANGUAGE: | ||||
|     if (length < 3) | ||||
|       goto fail; | ||||
|  | ||||
|     id3_parse_immediate(ptr, 3, field->immediate.value); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_FRAMEID: | ||||
|     if (length < 4) | ||||
|       goto fail; | ||||
|  | ||||
|     id3_parse_immediate(ptr, 4, field->immediate.value); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_DATE: | ||||
|     if (length < 8) | ||||
|       goto fail; | ||||
|  | ||||
|     id3_parse_immediate(ptr, 8, field->immediate.value); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1: | ||||
|   case ID3_FIELD_TYPE_LATIN1FULL: | ||||
|     { | ||||
|       id3_latin1_t *latin1; | ||||
|  | ||||
|       latin1 = id3_parse_latin1(ptr, length, | ||||
| 				field->type == ID3_FIELD_TYPE_LATIN1FULL); | ||||
|       if (latin1 == 0) | ||||
| 	goto fail; | ||||
|  | ||||
|       field->latin1.ptr = latin1; | ||||
|     } | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1LIST: | ||||
|     { | ||||
|       id3_byte_t const *end; | ||||
|       id3_latin1_t *latin1, **strings; | ||||
|  | ||||
|       end = *ptr + length; | ||||
|  | ||||
|       while (end - *ptr > 0) { | ||||
| 	latin1 = id3_parse_latin1(ptr, end - *ptr, 0); | ||||
| 	if (latin1 == 0) | ||||
| 	  goto fail; | ||||
|  | ||||
| 	strings = realloc(field->latin1list.strings, | ||||
| 			  (field->latin1list.nstrings + 1) * sizeof(*strings)); | ||||
| 	if (strings == 0) { | ||||
| 	  free(latin1); | ||||
| 	  goto fail; | ||||
| 	} | ||||
|  | ||||
| 	field->latin1list.strings = strings; | ||||
| 	field->latin1list.strings[field->latin1list.nstrings++] = latin1; | ||||
|       } | ||||
|     } | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRING: | ||||
|   case ID3_FIELD_TYPE_STRINGFULL: | ||||
|     { | ||||
|       id3_ucs4_t *ucs4; | ||||
|  | ||||
|       ucs4 = id3_parse_string(ptr, length, *encoding, | ||||
| 			      field->type == ID3_FIELD_TYPE_STRINGFULL); | ||||
|       if (ucs4 == 0) | ||||
| 	goto fail; | ||||
|  | ||||
|       field->string.ptr = ucs4; | ||||
|     } | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRINGLIST: | ||||
|     { | ||||
|       id3_byte_t const *end; | ||||
|       id3_ucs4_t *ucs4, **strings; | ||||
|  | ||||
|       end = *ptr + length; | ||||
|  | ||||
|       while (end - *ptr > 0) { | ||||
| 	ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); | ||||
| 	if (ucs4 == 0) | ||||
| 	  goto fail; | ||||
|  | ||||
| 	strings = realloc(field->stringlist.strings, | ||||
| 			  (field->stringlist.nstrings + 1) * sizeof(*strings)); | ||||
| 	if (strings == 0) { | ||||
| 	  free(ucs4); | ||||
| 	  goto fail; | ||||
| 	} | ||||
|  | ||||
| 	field->stringlist.strings = strings; | ||||
| 	field->stringlist.strings[field->stringlist.nstrings++] = ucs4; | ||||
|       } | ||||
|     } | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT32PLUS: | ||||
|   case ID3_FIELD_TYPE_BINARYDATA: | ||||
|     { | ||||
|       id3_byte_t *data; | ||||
|  | ||||
|       data = id3_parse_binary(ptr, length); | ||||
|       if (data == 0) | ||||
| 	goto fail; | ||||
|  | ||||
|       field->binary.data   = data; | ||||
|       field->binary.length = length; | ||||
|     } | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
|  | ||||
|  fail: | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->render() | ||||
|  * DESCRIPTION:	render a field value | ||||
|  */ | ||||
| id3_length_t id3_field_render(union id3_field const *field, id3_byte_t **ptr, | ||||
| 			      enum id3_field_textencoding *encoding, | ||||
| 			      int terminate) | ||||
| { | ||||
|   id3_length_t size; | ||||
|   unsigned int i; | ||||
|  | ||||
|   assert(field && encoding); | ||||
|  | ||||
|   switch (field->type) { | ||||
|   case ID3_FIELD_TYPE_INT32: | ||||
|     return id3_render_int(ptr, field->number.value, 4); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT24: | ||||
|     return id3_render_int(ptr, field->number.value, 3); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT16: | ||||
|     return id3_render_int(ptr, field->number.value, 2); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_TEXTENCODING: | ||||
|     *encoding = field->number.value; | ||||
|   case ID3_FIELD_TYPE_INT8: | ||||
|     return id3_render_int(ptr, field->number.value, 1); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1: | ||||
|   case ID3_FIELD_TYPE_LATIN1FULL: | ||||
|     return id3_render_latin1(ptr, field->latin1.ptr, terminate); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LATIN1LIST: | ||||
|     size = 0; | ||||
|     for (i = 0; i < field->latin1list.nstrings; ++i) { | ||||
|       size += id3_render_latin1(ptr, field->latin1list.strings[i], | ||||
| 				(i < field->latin1list.nstrings - 1) || | ||||
| 				terminate); | ||||
|     } | ||||
|     return size; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRING: | ||||
|   case ID3_FIELD_TYPE_STRINGFULL: | ||||
|     return id3_render_string(ptr, field->string.ptr, *encoding, terminate); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_STRINGLIST: | ||||
|     size = 0; | ||||
|     for (i = 0; i < field->stringlist.nstrings; ++i) { | ||||
|       size += id3_render_string(ptr, field->stringlist.strings[i], *encoding, | ||||
| 				(i < field->stringlist.nstrings - 1) || | ||||
| 				terminate); | ||||
|     } | ||||
|     return size; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_LANGUAGE: | ||||
|     return id3_render_immediate(ptr, field->immediate.value, 3); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_FRAMEID: | ||||
|     return id3_render_immediate(ptr, field->immediate.value, 4); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_DATE: | ||||
|     return id3_render_immediate(ptr, field->immediate.value, 8); | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT32PLUS: | ||||
|   case ID3_FIELD_TYPE_BINARYDATA: | ||||
|     return id3_render_binary(ptr, field->binary.data, field->binary.length); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setint() | ||||
|  * DESCRIPTION:	set the value of an int field | ||||
|  */ | ||||
| int id3_field_setint(union id3_field *field, signed long number) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   switch (field->type) { | ||||
|   case ID3_FIELD_TYPE_INT8: | ||||
|     if (number > 0x7f || number < -0x80) | ||||
|       return -1; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT16: | ||||
|     if (number > 0x7fff || number < -0x8000) | ||||
|       return -1; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT24: | ||||
|     if (number > 0x7fffffL || number < -0x800000L) | ||||
|       return -1; | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TYPE_INT32: | ||||
|     if (number > 0x7fffffffL || number < -0x80000000L) | ||||
|       return -1; | ||||
|     break; | ||||
|  | ||||
|   default: | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   field->number.value = number; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->settextencoding() | ||||
|  * DESCRIPTION:	set the value of a textencoding field | ||||
|  */ | ||||
| int id3_field_settextencoding(union id3_field *field, | ||||
| 			      enum id3_field_textencoding encoding) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_TEXTENCODING) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   field->number.value = encoding; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| int set_latin1(union id3_field *field, id3_latin1_t const *latin1) | ||||
| { | ||||
|   id3_latin1_t *data; | ||||
|  | ||||
|   if (latin1 == 0 || *latin1 == 0) | ||||
|     data = 0; | ||||
|   else { | ||||
|     data = id3_latin1_duplicate(latin1); | ||||
|     if (data == 0) | ||||
|       return -1; | ||||
|   } | ||||
|  | ||||
|   field->latin1.ptr = data; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setlatin1() | ||||
|  * DESCRIPTION:	set the value of a latin1 field | ||||
|  */ | ||||
| int id3_field_setlatin1(union id3_field *field, id3_latin1_t const *latin1) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_LATIN1) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   if (latin1) { | ||||
|     id3_latin1_t const *ptr; | ||||
|  | ||||
|     for (ptr = latin1; *ptr; ++ptr) { | ||||
|       if (*ptr == '\n') | ||||
| 	return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return set_latin1(field, latin1); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setfulllatin1() | ||||
|  * DESCRIPTION:	set the value of a full latin1 field | ||||
|  */ | ||||
| int id3_field_setfulllatin1(union id3_field *field, id3_latin1_t const *latin1) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_LATIN1FULL) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   return set_latin1(field, latin1); | ||||
| } | ||||
|  | ||||
| static | ||||
| int set_string(union id3_field *field, id3_ucs4_t const *string) | ||||
| { | ||||
|   id3_ucs4_t *data; | ||||
|  | ||||
|   if (string == 0 || *string == 0) | ||||
|     data = 0; | ||||
|   else { | ||||
|     data = id3_ucs4_duplicate(string); | ||||
|     if (data == 0) | ||||
|       return -1; | ||||
|   } | ||||
|  | ||||
|   field->string.ptr = data; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setstring() | ||||
|  * DESCRIPTION:	set the value of a string field | ||||
|  */ | ||||
| int id3_field_setstring(union id3_field *field, id3_ucs4_t const *string) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRING) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   if (string) { | ||||
|     id3_ucs4_t const *ptr; | ||||
|  | ||||
|     for (ptr = string; *ptr; ++ptr) { | ||||
|       if (*ptr == '\n') | ||||
| 	return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return set_string(field, string); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setfullstring() | ||||
|  * DESCRIPTION:	set the value of a full string field | ||||
|  */ | ||||
| int id3_field_setfullstring(union id3_field *field, id3_ucs4_t const *string) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRINGFULL) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   return set_string(field, string); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setstrings() | ||||
|  * DESCRIPTION:	set the value of a stringlist field | ||||
|  */ | ||||
| int id3_field_setstrings(union id3_field *field, | ||||
| 			 unsigned int length, id3_ucs4_t **ptrs) | ||||
| { | ||||
|   id3_ucs4_t **strings; | ||||
|   unsigned int i; | ||||
|  | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRINGLIST) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   if (length == 0) | ||||
|     return 0; | ||||
|  | ||||
|   strings = malloc(length * sizeof(*strings)); | ||||
|   if (strings == 0) | ||||
|     return -1; | ||||
|  | ||||
|   for (i = 0; i < length; ++i) { | ||||
|     strings[i] = id3_ucs4_duplicate(ptrs[i]); | ||||
|     if (strings[i] == 0) { | ||||
|       while (i--) | ||||
| 	free(strings[i]); | ||||
|  | ||||
|       free(strings); | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   field->stringlist.strings  = strings; | ||||
|   field->stringlist.nstrings = length; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->addstring() | ||||
|  * DESCRIPTION:	add a string to a stringlist field | ||||
|  */ | ||||
| int id3_field_addstring(union id3_field *field, id3_ucs4_t const *string) | ||||
| { | ||||
|   id3_ucs4_t *new, **strings; | ||||
|  | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRINGLIST) | ||||
|     return -1; | ||||
|  | ||||
|   if (string == 0) | ||||
|     string = id3_ucs4_empty; | ||||
|  | ||||
|   new = id3_ucs4_duplicate(string); | ||||
|   if (new == 0) | ||||
|     return -1; | ||||
|  | ||||
|   strings = realloc(field->stringlist.strings, | ||||
| 		    (field->stringlist.nstrings + 1) * sizeof(*strings)); | ||||
|   if (strings == 0) { | ||||
|     free(new); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   field->stringlist.strings = strings; | ||||
|   field->stringlist.strings[field->stringlist.nstrings++] = new; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setlanguage() | ||||
|  * DESCRIPTION:	set the value of a language field | ||||
|  */ | ||||
| int id3_field_setlanguage(union id3_field *field, char const *language) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_LANGUAGE) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   if (language) { | ||||
|     if (strlen(language) != 3) | ||||
|       return -1; | ||||
|  | ||||
|     strcpy(field->immediate.value, language); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setframeid() | ||||
|  * DESCRIPTION:	set the value of a frameid field | ||||
|  */ | ||||
| int id3_field_setframeid(union id3_field *field, char const *id) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_FRAMEID || | ||||
|       !id3_frame_validid(id)) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   field->immediate.value[0] = id[0]; | ||||
|   field->immediate.value[1] = id[1]; | ||||
|   field->immediate.value[2] = id[2]; | ||||
|   field->immediate.value[3] = id[3]; | ||||
|   field->immediate.value[4] = 0; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->setbinarydata() | ||||
|  * DESCRIPTION:	set the value of a binarydata field | ||||
|  */ | ||||
| int id3_field_setbinarydata(union id3_field *field, | ||||
| 			    id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t *mem; | ||||
|  | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_BINARYDATA) | ||||
|     return -1; | ||||
|  | ||||
|   id3_field_finish(field); | ||||
|  | ||||
|   if (length == 0) | ||||
|     mem = 0; | ||||
|   else { | ||||
|     mem = malloc(length); | ||||
|     if (mem == 0) | ||||
|       return -1; | ||||
|  | ||||
|     assert(data); | ||||
|  | ||||
|     memcpy(mem, data, length); | ||||
|   } | ||||
|  | ||||
|   field->binary.data   = mem; | ||||
|   field->binary.length = length; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getint() | ||||
|  * DESCRIPTION:	return the value of an integer field | ||||
|  */ | ||||
| signed long id3_field_getint(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_INT8 && | ||||
|       field->type != ID3_FIELD_TYPE_INT16 && | ||||
|       field->type != ID3_FIELD_TYPE_INT24 && | ||||
|       field->type != ID3_FIELD_TYPE_INT32) | ||||
|     return -1; | ||||
|  | ||||
|   return field->number.value; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getlatin1() | ||||
|  * DESCRIPTION:	return the value of a latin1 field | ||||
|  */ | ||||
| id3_latin1_t const *id3_field_getlatin1(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_LATIN1) | ||||
|     return 0; | ||||
|  | ||||
|   return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getfulllatin1() | ||||
|  * DESCRIPTION:	return the value of a full latin1 field | ||||
|  */ | ||||
| id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_LATIN1FULL) | ||||
|     return 0; | ||||
|  | ||||
|   return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getstring() | ||||
|  * DESCRIPTION:	return the value of a string field | ||||
|  */ | ||||
| id3_ucs4_t const *id3_field_getstring(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRING) | ||||
|     return 0; | ||||
|  | ||||
|   return field->string.ptr ? field->string.ptr : id3_ucs4_empty; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getfullstring() | ||||
|  * DESCRIPTION:	return the value of a fullstring field | ||||
|  */ | ||||
| id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRINGFULL) | ||||
|     return 0; | ||||
|  | ||||
|   return field->string.ptr ? field->string.ptr : id3_ucs4_empty; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getnstrings() | ||||
|  * DESCRIPTION:	return the number of strings in a stringlist field | ||||
|  */ | ||||
| unsigned int id3_field_getnstrings(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRINGLIST) | ||||
|     return 0; | ||||
|  | ||||
|   return field->stringlist.nstrings; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getstrings() | ||||
|  * DESCRIPTION:	return one value of a stringlist field | ||||
|  */ | ||||
| id3_ucs4_t const *id3_field_getstrings(union id3_field const *field, | ||||
| 				       unsigned int index) | ||||
| { | ||||
|   id3_ucs4_t const *string; | ||||
|  | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_STRINGLIST || | ||||
|       index >= field->stringlist.nstrings) | ||||
|     return 0; | ||||
|  | ||||
|   string = field->stringlist.strings[index]; | ||||
|  | ||||
|   return string ? string : id3_ucs4_empty; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getframeid() | ||||
|  * DESCRIPTION:	return the value of a frameid field | ||||
|  */ | ||||
| char const *id3_field_getframeid(union id3_field const *field) | ||||
| { | ||||
|   assert(field); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_FRAMEID) | ||||
|     return 0; | ||||
|  | ||||
|   return field->immediate.value; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	field->getbinarydata() | ||||
|  * DESCRIPTION:	return the value of a binarydata field | ||||
|  */ | ||||
| id3_byte_t const *id3_field_getbinarydata(union id3_field const *field, | ||||
| 					  id3_length_t *length) | ||||
| { | ||||
|   static id3_byte_t const empty; | ||||
|  | ||||
|   assert(field && length); | ||||
|  | ||||
|   if (field->type != ID3_FIELD_TYPE_BINARYDATA) | ||||
|     return 0; | ||||
|  | ||||
|   assert(field->binary.length == 0 || field->binary.data); | ||||
|  | ||||
|   *length = field->binary.length; | ||||
|  | ||||
|   return field->binary.data ? field->binary.data : ∅ | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/libid3tag/field.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/libid3tag/field.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: field.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_FIELD_H | ||||
| # define LIBID3TAG_FIELD_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| void id3_field_init(union id3_field *, enum id3_field_type); | ||||
| void id3_field_finish(union id3_field *); | ||||
|  | ||||
| int id3_field_parse(union id3_field *, id3_byte_t const **, | ||||
| 		    id3_length_t, enum id3_field_textencoding *); | ||||
|  | ||||
| id3_length_t id3_field_render(union id3_field const *, id3_byte_t **, | ||||
| 			      enum id3_field_textencoding *, int); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										673
									
								
								src/libid3tag/file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										673
									
								
								src/libid3tag/file.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,673 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: file.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdio.h> | ||||
| # include <stdlib.h> | ||||
| # include <string.h> | ||||
|  | ||||
| # ifdef HAVE_UNISTD_H | ||||
| #  include <unistd.h> | ||||
| # endif | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "file.h" | ||||
| # include "tag.h" | ||||
| # include "field.h" | ||||
|  | ||||
| struct filetag { | ||||
|   struct id3_tag *tag; | ||||
|   unsigned long location; | ||||
|   id3_length_t length; | ||||
| }; | ||||
|  | ||||
| struct id3_file { | ||||
|   FILE *iofile; | ||||
|   enum id3_file_mode mode; | ||||
|   char *path; | ||||
|  | ||||
|   int flags; | ||||
|  | ||||
|   struct id3_tag *primary; | ||||
|  | ||||
|   unsigned int ntags; | ||||
|   struct filetag *tags; | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   ID3_FILE_FLAG_ID3V1 = 0x0001 | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * NAME:	query_tag() | ||||
|  * DESCRIPTION:	check for a tag at a file's current position | ||||
|  */ | ||||
| static | ||||
| signed long query_tag(FILE *iofile) | ||||
| { | ||||
|   fpos_t save_position; | ||||
|   id3_byte_t query[ID3_TAG_QUERYSIZE]; | ||||
|   signed long size; | ||||
|  | ||||
|   if (fgetpos(iofile, &save_position) == -1) | ||||
|     return 0; | ||||
|  | ||||
|   size = id3_tag_query(query, fread(query, 1, sizeof(query), iofile)); | ||||
|  | ||||
|   if (fsetpos(iofile, &save_position) == -1) | ||||
|     return 0; | ||||
|  | ||||
|   return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	read_tag() | ||||
|  * DESCRIPTION:	read and parse a tag at a file's current position | ||||
|  */ | ||||
| static | ||||
| struct id3_tag *read_tag(FILE *iofile, id3_length_t size) | ||||
| { | ||||
|   id3_byte_t *data; | ||||
|   struct id3_tag *tag = 0; | ||||
|  | ||||
|   data = malloc(size); | ||||
|   if (data) { | ||||
|     if (fread(data, size, 1, iofile) == 1) | ||||
|       tag = id3_tag_parse(data, size); | ||||
|  | ||||
|     free(data); | ||||
|   } | ||||
|  | ||||
|   return tag; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	update_primary() | ||||
|  * DESCRIPTION:	update the primary tag with data from a new tag | ||||
|  */ | ||||
| static | ||||
| int update_primary(struct id3_tag *tag, struct id3_tag const *new) | ||||
| { | ||||
|   unsigned int i; | ||||
|   struct id3_frame *frame; | ||||
|  | ||||
|   if (new) { | ||||
|     if (!(new->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) | ||||
|       id3_tag_clearframes(tag); | ||||
|  | ||||
|     i = 0; | ||||
|     while ((frame = id3_tag_findframe(new, 0, i++))) { | ||||
|       if (id3_tag_attachframe(tag, frame) == -1) | ||||
| 	return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag_compare() | ||||
|  * DESCRIPTION:	tag sort function for qsort() | ||||
|  */ | ||||
| static | ||||
| int tag_compare(const void *a, const void *b) | ||||
| { | ||||
|   struct filetag const *tag1 = a, *tag2 = b; | ||||
|  | ||||
|   if (tag1->location < tag2->location) | ||||
|     return -1; | ||||
|   else if (tag1->location > tag2->location) | ||||
|     return +1; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	add_filetag() | ||||
|  * DESCRIPTION:	add a new file tag entry | ||||
|  */ | ||||
| static | ||||
| int add_filetag(struct id3_file *file, struct filetag const *filetag) | ||||
| { | ||||
|   struct filetag *tags; | ||||
|  | ||||
|   tags = realloc(file->tags, (file->ntags + 1) * sizeof(*tags)); | ||||
|   if (tags == 0) | ||||
|     return -1; | ||||
|  | ||||
|   file->tags = tags; | ||||
|   file->tags[file->ntags++] = *filetag; | ||||
|  | ||||
|   /* sort tags by location */ | ||||
|  | ||||
|   if (file->ntags > 1) | ||||
|     qsort(file->tags, file->ntags, sizeof(file->tags[0]), tag_compare); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	del_filetag() | ||||
|  * DESCRIPTION:	delete a file tag entry | ||||
|  */ | ||||
| static | ||||
| void del_filetag(struct id3_file *file, unsigned int index) | ||||
| { | ||||
|   assert(index < file->ntags); | ||||
|  | ||||
|   while (index < file->ntags - 1) { | ||||
|     file->tags[index] = file->tags[index + 1]; | ||||
|     ++index; | ||||
|   } | ||||
|  | ||||
|   --file->ntags; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	add_tag() | ||||
|  * DESCRIPTION:	read, parse, and add a tag to a file structure | ||||
|  */ | ||||
| static | ||||
| struct id3_tag *add_tag(struct id3_file *file, id3_length_t length) | ||||
| { | ||||
|   long location; | ||||
|   unsigned int i; | ||||
|   struct filetag filetag; | ||||
|   struct id3_tag *tag; | ||||
|  | ||||
|   location = ftell(file->iofile); | ||||
|   if (location == -1) | ||||
|     return 0; | ||||
|  | ||||
|   /* check for duplication/overlap */ | ||||
|   { | ||||
|     unsigned long begin1, end1, begin2, end2; | ||||
|  | ||||
|     begin1 = location; | ||||
|     end1   = begin1 + length; | ||||
|  | ||||
|     for (i = 0; i < file->ntags; ++i) { | ||||
|       begin2 = file->tags[i].location; | ||||
|       end2   = begin2 + file->tags[i].length; | ||||
|  | ||||
|       if (begin1 == begin2 && end1 == end2) | ||||
| 	return file->tags[i].tag;  /* duplicate */ | ||||
|  | ||||
|       if (begin1 < end2 && end1 > begin2) | ||||
| 	return 0;  /* overlap */ | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   tag = read_tag(file->iofile, length); | ||||
|  | ||||
|   filetag.tag      = tag; | ||||
|   filetag.location = location; | ||||
|   filetag.length   = length; | ||||
|  | ||||
|   if (add_filetag(file, &filetag) == -1 || | ||||
|       update_primary(file->primary, tag) == -1) { | ||||
|     if (tag) | ||||
|       id3_tag_delete(tag); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (tag) | ||||
|     id3_tag_addref(tag); | ||||
|  | ||||
|   return tag; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	search_tags() | ||||
|  * DESCRIPTION:	search for tags in a file | ||||
|  */ | ||||
| static | ||||
| int search_tags(struct id3_file *file) | ||||
| { | ||||
|   fpos_t save_position; | ||||
|   signed long size; | ||||
|  | ||||
|   /* | ||||
|    * save the current seek position | ||||
|    * | ||||
|    * We also verify the stream is seekable by calling fsetpos(), since | ||||
|    * fgetpos() alone is not reliable enough for this purpose. | ||||
|    * | ||||
|    * [Apparently not even fsetpos() is sufficient under Win32.] | ||||
|    */ | ||||
|  | ||||
|   if (fgetpos(file->iofile, &save_position) == -1 || | ||||
|       fsetpos(file->iofile, &save_position) == -1) | ||||
|     return -1; | ||||
|  | ||||
|   /* look for an ID3v1 tag */ | ||||
|  | ||||
|   if (fseek(file->iofile, -128, SEEK_END) == 0) { | ||||
|     size = query_tag(file->iofile); | ||||
|     if (size > 0) { | ||||
|       struct id3_tag const *tag; | ||||
|  | ||||
|       tag = add_tag(file, size); | ||||
|  | ||||
|       /* if this is indeed an ID3v1 tag, mark the file so */ | ||||
|  | ||||
|       if (tag && (ID3_TAG_VERSION_MAJOR(id3_tag_version(tag)) == 1)) | ||||
| 	file->flags |= ID3_FILE_FLAG_ID3V1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* look for a tag at the beginning of the file */ | ||||
|  | ||||
|   rewind(file->iofile); | ||||
|  | ||||
|   size = query_tag(file->iofile); | ||||
|   if (size > 0) { | ||||
|     struct id3_tag const *tag; | ||||
|     struct id3_frame const *frame; | ||||
|  | ||||
|     tag = add_tag(file, size); | ||||
|  | ||||
|     /* locate tags indicated by SEEK frames */ | ||||
|  | ||||
|     while (tag && (frame = id3_tag_findframe(tag, "SEEK", 0))) { | ||||
|       long seek; | ||||
|  | ||||
|       seek = id3_field_getint(id3_frame_field(frame, 0)); | ||||
|       if (seek < 0 || fseek(file->iofile, seek, SEEK_CUR) == -1) | ||||
| 	break; | ||||
|  | ||||
|       size = query_tag(file->iofile); | ||||
|       tag  = (size > 0) ? add_tag(file, size) : 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* look for a tag at the end of the file (before any ID3v1 tag) */ | ||||
|  | ||||
|   if (fseek(file->iofile, ((file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0) + | ||||
| 	    -10, SEEK_END) == 0) { | ||||
|     size = query_tag(file->iofile); | ||||
|     if (size < 0 && fseek(file->iofile, size, SEEK_CUR) == 0) { | ||||
|       size = query_tag(file->iofile); | ||||
|       if (size > 0) | ||||
| 	add_tag(file, size); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   clearerr(file->iofile); | ||||
|  | ||||
|   /* restore seek position */ | ||||
|  | ||||
|   if (fsetpos(file->iofile, &save_position) == -1) | ||||
|     return -1; | ||||
|  | ||||
|   /* set primary tag options and target padded length for convenience */ | ||||
|  | ||||
|   if ((file->ntags > 0 && !(file->flags & ID3_FILE_FLAG_ID3V1)) || | ||||
|       (file->ntags > 1 &&  (file->flags & ID3_FILE_FLAG_ID3V1))) { | ||||
|     if (file->tags[0].location == 0) | ||||
|       id3_tag_setlength(file->primary, file->tags[0].length); | ||||
|     else | ||||
|       id3_tag_options(file->primary, ID3_TAG_OPTION_APPENDEDTAG, ~0); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	finish_file() | ||||
|  * DESCRIPTION:	release memory associated with a file | ||||
|  */ | ||||
| static | ||||
| void finish_file(struct id3_file *file) | ||||
| { | ||||
|   unsigned int i; | ||||
|  | ||||
|   if (file->path) | ||||
|     free(file->path); | ||||
|  | ||||
|   if (file->primary) { | ||||
|     id3_tag_delref(file->primary); | ||||
|     id3_tag_delete(file->primary); | ||||
|   } | ||||
|  | ||||
|   for (i = 0; i < file->ntags; ++i) { | ||||
|     struct id3_tag *tag; | ||||
|  | ||||
|     tag = file->tags[i].tag; | ||||
|     if (tag) { | ||||
|       id3_tag_delref(tag); | ||||
|       id3_tag_delete(tag); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (file->tags) | ||||
|     free(file->tags); | ||||
|  | ||||
|   free(file); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	new_file() | ||||
|  * DESCRIPTION:	create a new file structure and load tags | ||||
|  */ | ||||
| static | ||||
| struct id3_file *new_file(FILE *iofile, enum id3_file_mode mode, | ||||
| 			  char const *path) | ||||
| { | ||||
|   struct id3_file *file; | ||||
|  | ||||
|   file = malloc(sizeof(*file)); | ||||
|   if (file == 0) | ||||
|     goto fail; | ||||
|  | ||||
|   file->iofile  = iofile; | ||||
|   file->mode    = mode; | ||||
|   file->path    = path ? strdup(path) : 0; | ||||
|  | ||||
|   file->flags   = 0; | ||||
|  | ||||
|   file->ntags   = 0; | ||||
|   file->tags    = 0; | ||||
|  | ||||
|   file->primary = id3_tag_new(); | ||||
|   if (file->primary == 0) | ||||
|     goto fail; | ||||
|  | ||||
|   id3_tag_addref(file->primary); | ||||
|  | ||||
|   /* load tags from the file */ | ||||
|  | ||||
|   if (search_tags(file) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, | ||||
| 		  (file->flags & ID3_FILE_FLAG_ID3V1) ? ~0 : 0); | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     if (file) { | ||||
|       finish_file(file); | ||||
|       file = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return file; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	file->open() | ||||
|  * DESCRIPTION:	open a file given its pathname | ||||
|  */ | ||||
| struct id3_file *id3_file_open(char const *path, enum id3_file_mode mode) | ||||
| { | ||||
|   FILE *iofile; | ||||
|   struct id3_file *file; | ||||
|  | ||||
|   assert(path); | ||||
|  | ||||
|   iofile = fopen(path, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb"); | ||||
|   if (iofile == 0) | ||||
|     return 0; | ||||
|  | ||||
|   file = new_file(iofile, mode, path); | ||||
|   if (file == 0) | ||||
|     fclose(iofile); | ||||
|  | ||||
|   return file; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	file->fdopen() | ||||
|  * DESCRIPTION:	open a file using an existing file descriptor | ||||
|  */ | ||||
| struct id3_file *id3_file_fdopen(int fd, enum id3_file_mode mode) | ||||
| { | ||||
| # if 1 || defined(HAVE_UNISTD_H) | ||||
|   FILE *iofile; | ||||
|   struct id3_file *file; | ||||
|  | ||||
|   iofile = fdopen(fd, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb"); | ||||
|   if (iofile == 0) | ||||
|     return 0; | ||||
|  | ||||
|   file = new_file(iofile, mode, 0); | ||||
|   if (file == 0) { | ||||
|     int save_fd; | ||||
|  | ||||
|     /* close iofile without closing fd */ | ||||
|  | ||||
|     save_fd = dup(fd); | ||||
|  | ||||
|     fclose(iofile); | ||||
|  | ||||
|     dup2(save_fd, fd); | ||||
|     close(save_fd); | ||||
|   } | ||||
|  | ||||
|   return file; | ||||
| # else | ||||
|   return 0; | ||||
| # endif | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	file->close() | ||||
|  * DESCRIPTION:	close a file and delete its associated tags | ||||
|  */ | ||||
| int id3_file_close(struct id3_file *file) | ||||
| { | ||||
|   int result = 0; | ||||
|  | ||||
|   assert(file); | ||||
|  | ||||
|   if (fclose(file->iofile) == EOF) | ||||
|     result = -1; | ||||
|  | ||||
|   finish_file(file); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	file->tag() | ||||
|  * DESCRIPTION:	return the primary tag structure for a file | ||||
|  */ | ||||
| struct id3_tag *id3_file_tag(struct id3_file const *file) | ||||
| { | ||||
|   assert(file); | ||||
|  | ||||
|   return file->primary; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	v1_write() | ||||
|  * DESCRIPTION:	write ID3v1 tag modifications to a file | ||||
|  */ | ||||
| static | ||||
| int v1_write(struct id3_file *file, | ||||
| 	     id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   assert(!data || length == 128); | ||||
|  | ||||
|   if (data) { | ||||
|     long location; | ||||
|  | ||||
|     if (fseek(file->iofile, (file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0, | ||||
| 	      SEEK_END) == -1 || | ||||
| 	(location = ftell(file->iofile)) == -1 || | ||||
| 	fwrite(data, 128, 1, file->iofile) == 0 || | ||||
| 	fflush(file->iofile) == EOF) | ||||
|       return -1; | ||||
|  | ||||
|     /* add file tag reference */ | ||||
|  | ||||
|     if (!(file->flags & ID3_FILE_FLAG_ID3V1)) { | ||||
|       struct filetag filetag; | ||||
|  | ||||
|       filetag.tag      = 0; | ||||
|       filetag.location = location; | ||||
|       filetag.length   = 128; | ||||
|  | ||||
|       if (add_filetag(file, &filetag) == -1) | ||||
| 	return -1; | ||||
|  | ||||
|       file->flags |= ID3_FILE_FLAG_ID3V1; | ||||
|     } | ||||
|   } | ||||
| # if defined(HAVE_FTRUNCATE) | ||||
|   else if (file->flags & ID3_FILE_FLAG_ID3V1) { | ||||
|     long length; | ||||
|  | ||||
|     if (fseek(file->iofile, 0, SEEK_END) == -1) | ||||
|       return -1; | ||||
|  | ||||
|     length = ftell(file->iofile); | ||||
|     if (length == -1 || | ||||
| 	(length >= 0 && length < 128)) | ||||
|       return -1; | ||||
|  | ||||
|     if (ftruncate(fileno(file->iofile), length - 128) == -1) | ||||
|       return -1; | ||||
|  | ||||
|     /* delete file tag reference */ | ||||
|  | ||||
|     del_filetag(file, file->ntags - 1); | ||||
|  | ||||
|     file->flags &= ~ID3_FILE_FLAG_ID3V1; | ||||
|   } | ||||
| # endif | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	v2_write() | ||||
|  * DESCRIPTION:	write ID3v2 tag modifications to a file | ||||
|  */ | ||||
| static | ||||
| int v2_write(struct id3_file *file, | ||||
| 	     id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   assert(!data || length > 0); | ||||
|  | ||||
|   if (((file->ntags == 1 && !(file->flags & ID3_FILE_FLAG_ID3V1)) || | ||||
|        (file->ntags == 2 &&  (file->flags & ID3_FILE_FLAG_ID3V1))) && | ||||
|       file->tags[0].length == length) { | ||||
|     /* easy special case: rewrite existing tag in-place */ | ||||
|  | ||||
|     if (fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 || | ||||
| 	fwrite(data, length, 1, file->iofile) == 0 || | ||||
| 	fflush(file->iofile) == EOF) | ||||
|       return -1; | ||||
|  | ||||
|     goto done; | ||||
|   } | ||||
|  | ||||
|   /* hard general case: rewrite entire file */ | ||||
|  | ||||
|   /* ... */ | ||||
|  | ||||
|  done: | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	file->update() | ||||
|  * DESCRIPTION:	rewrite tag(s) to a file | ||||
|  */ | ||||
| int id3_file_update(struct id3_file *file) | ||||
| { | ||||
|   int options, result = 0; | ||||
|   id3_length_t v1size = 0, v2size = 0; | ||||
|   id3_byte_t id3v1_data[128], *id3v1 = 0, *id3v2 = 0; | ||||
|  | ||||
|   assert(file); | ||||
|  | ||||
|   if (file->mode != ID3_FILE_MODE_READWRITE) | ||||
|     return -1; | ||||
|  | ||||
|   options = id3_tag_options(file->primary, 0, 0); | ||||
|  | ||||
|   /* render ID3v1 */ | ||||
|  | ||||
|   if (options & ID3_TAG_OPTION_ID3V1) { | ||||
|     v1size = id3_tag_render(file->primary, 0); | ||||
|     if (v1size) { | ||||
|       assert(v1size == sizeof(id3v1_data)); | ||||
|  | ||||
|       v1size = id3_tag_render(file->primary, id3v1_data); | ||||
|       if (v1size) { | ||||
| 	assert(v1size == sizeof(id3v1_data)); | ||||
| 	id3v1 = id3v1_data; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* render ID3v2 */ | ||||
|  | ||||
|   id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, 0); | ||||
|  | ||||
|   v2size = id3_tag_render(file->primary, 0); | ||||
|   if (v2size) { | ||||
|     id3v2 = malloc(v2size); | ||||
|     if (id3v2 == 0) | ||||
|       goto fail; | ||||
|  | ||||
|     v2size = id3_tag_render(file->primary, id3v2); | ||||
|     if (v2size == 0) { | ||||
|       free(id3v2); | ||||
|       id3v2 = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* write tags */ | ||||
|  | ||||
|   if (v2_write(file, id3v2, v2size) == -1 || | ||||
|       v1_write(file, id3v1, v1size) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   rewind(file->iofile); | ||||
|  | ||||
|   /* update file tags array? ... */ | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     result = -1; | ||||
|   } | ||||
|  | ||||
|   /* clean up; restore tag options */ | ||||
|  | ||||
|   if (id3v2) | ||||
|     free(id3v2); | ||||
|  | ||||
|   id3_tag_options(file->primary, ~0, options); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
							
								
								
									
										25
									
								
								src/libid3tag/file.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/libid3tag/file.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: file.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_FILE_H | ||||
| # define LIBID3TAG_FILE_H | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										626
									
								
								src/libid3tag/frame.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								src/libid3tag/frame.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,626 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: frame.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
| # include <string.h> | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "frame.h" | ||||
| # include "frametype.h" | ||||
| # include "compat.h" | ||||
| # include "field.h" | ||||
| # include "render.h" | ||||
| # include "parse.h" | ||||
| # include "util.h" | ||||
|  | ||||
| static | ||||
| int valid_idchar(char c) | ||||
| { | ||||
|   return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->validid() | ||||
|  * DESCRIPTION:	return true if the parameter string is a legal frame ID | ||||
|  */ | ||||
| int id3_frame_validid(char const *id) | ||||
| { | ||||
|   return id && | ||||
|     valid_idchar(id[0]) && | ||||
|     valid_idchar(id[1]) && | ||||
|     valid_idchar(id[2]) && | ||||
|     valid_idchar(id[3]); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->new() | ||||
|  * DESCRIPTION:	allocate and return a new frame | ||||
|  */ | ||||
| struct id3_frame *id3_frame_new(char const *id) | ||||
| { | ||||
|   struct id3_frametype const *frametype; | ||||
|   struct id3_frame *frame; | ||||
|   unsigned int i; | ||||
|  | ||||
|   if (!id3_frame_validid(id)) | ||||
|     return 0; | ||||
|  | ||||
|   frametype = id3_frametype_lookup(id, 4); | ||||
|   if (frametype == 0) { | ||||
|     switch (id[0]) { | ||||
|     case 'T': | ||||
|       frametype = &id3_frametype_text; | ||||
|       break; | ||||
|  | ||||
|     case 'W': | ||||
|       frametype = &id3_frametype_url; | ||||
|       break; | ||||
|  | ||||
|     case 'X': | ||||
|     case 'Y': | ||||
|     case 'Z': | ||||
|       frametype = &id3_frametype_experimental; | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       frametype = &id3_frametype_unknown; | ||||
|       if (id3_compat_lookup(id, 4)) | ||||
| 	frametype = &id3_frametype_obsolete; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields)); | ||||
|   if (frame) { | ||||
|     frame->id[0] = id[0]; | ||||
|     frame->id[1] = id[1]; | ||||
|     frame->id[2] = id[2]; | ||||
|     frame->id[3] = id[3]; | ||||
|     frame->id[4] = 0; | ||||
|  | ||||
|     frame->description       = frametype->description; | ||||
|     frame->refcount          = 0; | ||||
|     frame->flags             = frametype->defaultflags; | ||||
|     frame->group_id          = 0; | ||||
|     frame->encryption_method = 0; | ||||
|     frame->encoded           = 0; | ||||
|     frame->encoded_length    = 0; | ||||
|     frame->decoded_length    = 0; | ||||
|     frame->nfields           = frametype->nfields; | ||||
|     frame->fields            = (union id3_field *) &frame[1]; | ||||
|  | ||||
|     for (i = 0; i < frame->nfields; ++i) | ||||
|       id3_field_init(&frame->fields[i], frametype->fields[i]); | ||||
|   } | ||||
|  | ||||
|   return frame; | ||||
| } | ||||
|  | ||||
| void id3_frame_delete(struct id3_frame *frame) | ||||
| { | ||||
|   assert(frame); | ||||
|  | ||||
|   if (frame->refcount == 0) { | ||||
|     unsigned int i; | ||||
|  | ||||
|     for (i = 0; i < frame->nfields; ++i) | ||||
|       id3_field_finish(&frame->fields[i]); | ||||
|  | ||||
|     if (frame->encoded) | ||||
|       free(frame->encoded); | ||||
|  | ||||
|     free(frame); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->addref() | ||||
|  * DESCRIPTION:	add an external reference to a frame | ||||
|  */ | ||||
| void id3_frame_addref(struct id3_frame *frame) | ||||
| { | ||||
|   assert(frame); | ||||
|  | ||||
|   ++frame->refcount; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->delref() | ||||
|  * DESCRIPTION:	remove an external reference to a frame | ||||
|  */ | ||||
| void id3_frame_delref(struct id3_frame *frame) | ||||
| { | ||||
|   assert(frame && frame->refcount > 0); | ||||
|  | ||||
|   --frame->refcount; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->field() | ||||
|  * DESCRIPTION:	return a pointer to a field in a frame | ||||
|  */ | ||||
| union id3_field *id3_frame_field(struct id3_frame const *frame, | ||||
| 				 unsigned int index) | ||||
| { | ||||
|   assert(frame); | ||||
|  | ||||
|   return (index < frame->nfields) ? &frame->fields[index] : 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| struct id3_frame *obsolete(char const *id, id3_byte_t const *data, | ||||
| 			   id3_length_t length) | ||||
| { | ||||
|   struct id3_frame *frame; | ||||
|  | ||||
|   frame = id3_frame_new(ID3_FRAME_OBSOLETE); | ||||
|   if (frame) { | ||||
|     if (id3_field_setframeid(&frame->fields[0], id) == -1 || | ||||
| 	id3_field_setbinarydata(&frame->fields[1], data, length) == -1) | ||||
|       goto fail; | ||||
|   } | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     if (frame) { | ||||
|       id3_frame_delete(frame); | ||||
|       frame = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return frame; | ||||
| } | ||||
|  | ||||
| static | ||||
| struct id3_frame *unparseable(char const *id, id3_byte_t const **ptr, | ||||
| 			      id3_length_t length, int flags, | ||||
| 			      int group_id, int encryption_method, | ||||
| 			      id3_length_t decoded_length) | ||||
| { | ||||
|   struct id3_frame *frame = 0; | ||||
|   id3_byte_t *mem; | ||||
|  | ||||
|   mem = malloc(length ? length : 1); | ||||
|   if (mem == 0) | ||||
|     goto fail; | ||||
|  | ||||
|   frame = id3_frame_new(id); | ||||
|   if (frame == 0) | ||||
|     free(mem); | ||||
|   else { | ||||
|     memcpy(mem, *ptr, length); | ||||
|  | ||||
|     frame->flags             = flags; | ||||
|     frame->group_id          = group_id; | ||||
|     frame->encryption_method = encryption_method; | ||||
|     frame->encoded           = mem; | ||||
|     frame->encoded_length    = length; | ||||
|     frame->decoded_length    = decoded_length; | ||||
|   } | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     ; | ||||
|   } | ||||
|  | ||||
|   *ptr += length; | ||||
|  | ||||
|   return frame; | ||||
| } | ||||
|  | ||||
| static | ||||
| int parse_data(struct id3_frame *frame, | ||||
| 	       id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   enum id3_field_textencoding encoding; | ||||
|   id3_byte_t const *end; | ||||
|   unsigned int i; | ||||
|  | ||||
|   encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; | ||||
|  | ||||
|   end = data + length; | ||||
|  | ||||
|   for (i = 0; i < frame->nfields; ++i) { | ||||
|     if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1) | ||||
|       return -1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->parse() | ||||
|  * DESCRIPTION:	parse raw frame data according to the specified ID3 tag version | ||||
|  */ | ||||
| struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length, | ||||
| 				  unsigned int version) | ||||
| { | ||||
|   struct id3_frame *frame = 0; | ||||
|   id3_byte_t const *id, *end, *data; | ||||
|   id3_length_t size, decoded_length = 0; | ||||
|   int flags = 0, group_id = 0, encryption_method = 0; | ||||
|   struct id3_compat const *compat = 0; | ||||
|   id3_byte_t *mem = 0; | ||||
|   char xid[4]; | ||||
|  | ||||
|   id  = *ptr; | ||||
|   end = *ptr + length; | ||||
|  | ||||
|   if (ID3_TAG_VERSION_MAJOR(version) < 4) { | ||||
|     switch (ID3_TAG_VERSION_MAJOR(version)) { | ||||
|     case 2: | ||||
|       if (length < 6) | ||||
| 	goto fail; | ||||
|  | ||||
|       compat = id3_compat_lookup(id, 3); | ||||
|  | ||||
|       *ptr += 3; | ||||
|       size  = id3_parse_uint(ptr, 3); | ||||
|  | ||||
|       if (size > end - *ptr) | ||||
| 	goto fail; | ||||
|  | ||||
|       end = *ptr + size; | ||||
|  | ||||
|       break; | ||||
|  | ||||
|     case 3: | ||||
|       if (length < 10) | ||||
| 	goto fail; | ||||
|  | ||||
|       compat = id3_compat_lookup(id, 4); | ||||
|  | ||||
|       *ptr += 4; | ||||
|       size  = id3_parse_uint(ptr, 4); | ||||
|       flags = id3_parse_uint(ptr, 2); | ||||
|  | ||||
|       if (size > end - *ptr) | ||||
| 	goto fail; | ||||
|  | ||||
|       end = *ptr + size; | ||||
|  | ||||
|       if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) { | ||||
| 	frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0); | ||||
| 	goto done; | ||||
|       } | ||||
|  | ||||
|       flags = | ||||
| 	((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) | | ||||
| 	((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION | | ||||
| 			 ID3_FRAME_FLAG_ENCRYPTION)) | | ||||
| 	((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY); | ||||
|  | ||||
|       if (flags & ID3_FRAME_FLAG_COMPRESSION) { | ||||
| 	if (end - *ptr < 4) | ||||
| 	  goto fail; | ||||
|  | ||||
| 	decoded_length = id3_parse_uint(ptr, 4); | ||||
|       } | ||||
|  | ||||
|       if (flags & ID3_FRAME_FLAG_ENCRYPTION) { | ||||
| 	if (end - *ptr < 1) | ||||
| 	  goto fail; | ||||
|  | ||||
| 	encryption_method = id3_parse_uint(ptr, 1); | ||||
|       } | ||||
|  | ||||
|       if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) { | ||||
| 	if (end - *ptr < 1) | ||||
| 	  goto fail; | ||||
|  | ||||
| 	group_id = id3_parse_uint(ptr, 1); | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       goto fail; | ||||
|     } | ||||
|  | ||||
|     /* canonicalize frame ID for ID3v2.4 */ | ||||
|  | ||||
|     if (compat && compat->equiv) | ||||
|       id = compat->equiv; | ||||
|     else if (ID3_TAG_VERSION_MAJOR(version) == 2) { | ||||
|       xid[0] = 'Y'; | ||||
|       xid[1] = id[0]; | ||||
|       xid[2] = id[1]; | ||||
|       xid[3] = id[2]; | ||||
|  | ||||
|       id = xid; | ||||
|  | ||||
|       flags |= | ||||
| 	ID3_FRAME_FLAG_TAGALTERPRESERVATION | | ||||
| 	ID3_FRAME_FLAG_FILEALTERPRESERVATION; | ||||
|     } | ||||
|   } | ||||
|   else {  /* ID3v2.4 */ | ||||
|     if (length < 10) | ||||
|       goto fail; | ||||
|  | ||||
|     *ptr += 4; | ||||
|     size  = id3_parse_syncsafe(ptr, 4); | ||||
|     flags = id3_parse_uint(ptr, 2); | ||||
|  | ||||
|     if (size > end - *ptr) | ||||
|       goto fail; | ||||
|  | ||||
|     end = *ptr + size; | ||||
|  | ||||
|     if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) { | ||||
|       frame = unparseable(id, ptr, end - *ptr, flags, 0, 0, 0); | ||||
|       goto done; | ||||
|     } | ||||
|  | ||||
|     if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) { | ||||
|       if (end - *ptr < 1) | ||||
| 	goto fail; | ||||
|  | ||||
|       group_id = id3_parse_uint(ptr, 1); | ||||
|     } | ||||
|  | ||||
|     if ((flags & ID3_FRAME_FLAG_COMPRESSION) && | ||||
| 	!(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR)) | ||||
|       goto fail; | ||||
|  | ||||
|     if (flags & ID3_FRAME_FLAG_ENCRYPTION) { | ||||
|       if (end - *ptr < 1) | ||||
| 	goto fail; | ||||
|  | ||||
|       encryption_method = id3_parse_uint(ptr, 1); | ||||
|     } | ||||
|  | ||||
|     if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) { | ||||
|       if (end - *ptr < 4) | ||||
| 	goto fail; | ||||
|  | ||||
|       decoded_length = id3_parse_syncsafe(ptr, 4); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   data = *ptr; | ||||
|   *ptr = end; | ||||
|  | ||||
|   /* undo frame encodings */ | ||||
|  | ||||
|   if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) { | ||||
|     mem = malloc(end - data); | ||||
|     if (mem == 0) | ||||
|       goto fail; | ||||
|  | ||||
|     memcpy(mem, data, end - data); | ||||
|  | ||||
|     end  = mem + id3_util_deunsynchronise(mem, end - data); | ||||
|     data = mem; | ||||
|   } | ||||
|  | ||||
|   if (flags & ID3_FRAME_FLAG_ENCRYPTION) { | ||||
|     frame = unparseable(id, &data, end - data, flags, | ||||
| 			group_id, encryption_method, decoded_length); | ||||
|     goto done; | ||||
|   } | ||||
|  | ||||
|   if (flags & ID3_FRAME_FLAG_COMPRESSION) { | ||||
|     id3_byte_t *decomp; | ||||
|  | ||||
|     decomp = id3_util_decompress(data, end - data, decoded_length); | ||||
|     if (decomp == 0) | ||||
|       goto fail; | ||||
|  | ||||
|     if (mem) | ||||
|       free(mem); | ||||
|  | ||||
|     data = mem = decomp; | ||||
|     end  = data + decoded_length; | ||||
|   } | ||||
|  | ||||
|   /* check for obsolescence */ | ||||
|  | ||||
|   if (compat && !compat->equiv) { | ||||
|     frame = obsolete(id, data, end - data); | ||||
|     goto done; | ||||
|   } | ||||
|  | ||||
|   /* generate the internal frame structure */ | ||||
|  | ||||
|   frame = id3_frame_new(id); | ||||
|   if (frame) { | ||||
|     frame->flags    = flags; | ||||
|     frame->group_id = group_id; | ||||
|  | ||||
|     if (compat && compat->translate) { | ||||
|       if (compat->translate(frame, compat->id, data, end - data) == -1) | ||||
| 	goto fail; | ||||
|     } | ||||
|     else { | ||||
|       if (parse_data(frame, data, end - data) == -1) | ||||
| 	goto fail; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     if (frame) { | ||||
|       id3_frame_delete(frame); | ||||
|       frame = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  done: | ||||
|   if (mem) | ||||
|     free(mem); | ||||
|  | ||||
|   return frame; | ||||
| } | ||||
|  | ||||
| static | ||||
| id3_length_t render_data(id3_byte_t **ptr, | ||||
| 			 union id3_field *fields, unsigned int length) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|   enum id3_field_textencoding encoding; | ||||
|   unsigned int i; | ||||
|  | ||||
|   encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; | ||||
|  | ||||
|   for (i = 0; i < length; ++i) | ||||
|     size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1); | ||||
|  | ||||
|   return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->render() | ||||
|  * DESCRIPTION:	render a single, complete frame | ||||
|  */ | ||||
| id3_length_t id3_frame_render(struct id3_frame const *frame, | ||||
| 			      id3_byte_t **ptr, int options) | ||||
| { | ||||
|   id3_length_t size = 0, decoded_length, datalen; | ||||
|   id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0; | ||||
|   int flags; | ||||
|  | ||||
|   assert(frame); | ||||
|  | ||||
|   if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) || | ||||
|       ((options & ID3_TAG_OPTION_FILEALTERED) && | ||||
|        (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION))) | ||||
|     return 0; | ||||
|  | ||||
|   /* a frame must be at least 1 byte big, excluding the header */ | ||||
|  | ||||
|   decoded_length = render_data(0, frame->fields, frame->nfields); | ||||
|   if (decoded_length == 0 && frame->encoded == 0) | ||||
|     return 0; | ||||
|  | ||||
|   /* header */ | ||||
|  | ||||
|   size += id3_render_immediate(ptr, frame->id, 4); | ||||
|  | ||||
|   if (ptr) | ||||
|     size_ptr = *ptr; | ||||
|  | ||||
|   size += id3_render_syncsafe(ptr, 0, 4); | ||||
|  | ||||
|   if (ptr) | ||||
|     flags_ptr = *ptr; | ||||
|  | ||||
|   flags = frame->flags; | ||||
|  | ||||
|   size += id3_render_int(ptr, flags, 2); | ||||
|  | ||||
|   if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) { | ||||
|     size += id3_render_binary(ptr, frame->encoded, frame->encoded_length); | ||||
|     if (size_ptr) | ||||
|       id3_render_syncsafe(&size_ptr, size - 10, 4); | ||||
|  | ||||
|     return size; | ||||
|   } | ||||
|  | ||||
|   flags &= ID3_FRAME_FLAG_KNOWNFLAGS; | ||||
|  | ||||
|   flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION; | ||||
|   if (options & ID3_TAG_OPTION_UNSYNCHRONISATION) | ||||
|     flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION; | ||||
|  | ||||
|   if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) { | ||||
|     flags &= ~ID3_FRAME_FLAG_COMPRESSION; | ||||
|     if (options & ID3_TAG_OPTION_COMPRESSION) | ||||
|       flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR; | ||||
|   } | ||||
|  | ||||
|   if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) | ||||
|     size += id3_render_int(ptr, frame->group_id, 1); | ||||
|   if (flags & ID3_FRAME_FLAG_ENCRYPTION) | ||||
|     size += id3_render_int(ptr, frame->encryption_method, 1); | ||||
|   if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) { | ||||
|     if (flags & ID3_FRAME_FLAG_ENCRYPTION) | ||||
|       decoded_length = frame->decoded_length; | ||||
|     size += id3_render_syncsafe(ptr, decoded_length, 4); | ||||
|   } | ||||
|  | ||||
|   if (ptr) | ||||
|     data = *ptr; | ||||
|  | ||||
|   if (flags & ID3_FRAME_FLAG_ENCRYPTION) | ||||
|     datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length); | ||||
|   else { | ||||
|     if (ptr == 0) | ||||
|       datalen = decoded_length; | ||||
|     else { | ||||
|       datalen = render_data(ptr, frame->fields, frame->nfields); | ||||
|  | ||||
|       if (flags & ID3_FRAME_FLAG_COMPRESSION) { | ||||
| 	id3_byte_t *comp; | ||||
| 	id3_length_t complen; | ||||
|  | ||||
| 	comp = id3_util_compress(data, datalen, &complen); | ||||
| 	if (comp == 0) | ||||
| 	  flags &= ~ID3_FRAME_FLAG_COMPRESSION; | ||||
| 	else { | ||||
| 	  *ptr = data; | ||||
| 	  datalen = id3_render_binary(ptr, comp, complen); | ||||
|  | ||||
| 	  free(comp); | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* unsynchronisation */ | ||||
|  | ||||
|   if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) { | ||||
|     if (data == 0) | ||||
|       datalen *= 2; | ||||
|     else { | ||||
|       id3_length_t newlen; | ||||
|  | ||||
|       newlen = id3_util_unsynchronise(data, datalen); | ||||
|       if (newlen == datalen) | ||||
| 	flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION; | ||||
|       else { | ||||
| 	*ptr   += newlen - datalen; | ||||
| 	datalen = newlen; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   size += datalen; | ||||
|  | ||||
|   /* patch size and flags */ | ||||
|  | ||||
|   if (size_ptr) | ||||
|     id3_render_syncsafe(&size_ptr, size - 10, 4); | ||||
|   if (flags_ptr) | ||||
|     id3_render_int(&flags_ptr, flags, 2); | ||||
|  | ||||
|   return size; | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/libid3tag/frame.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/libid3tag/frame.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: frame.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_FRAME_H | ||||
| # define LIBID3TAG_FRAME_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| int id3_frame_validid(char const *); | ||||
|  | ||||
| void id3_frame_addref(struct id3_frame *); | ||||
| void id3_frame_delref(struct id3_frame *); | ||||
|  | ||||
| struct id3_frame *id3_frame_parse(id3_byte_t const **, id3_length_t, | ||||
| 				  unsigned int); | ||||
| id3_length_t id3_frame_render(struct id3_frame const *, id3_byte_t **, int); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										363
									
								
								src/libid3tag/frametype.gperf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								src/libid3tag/frametype.gperf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,363 @@ | ||||
| %{ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: frametype.gperf,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <string.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "frametype.h" | ||||
|  | ||||
| # define FIELDS(id)  static enum id3_field_type const fields_##id[] | ||||
|  | ||||
| /* frame field descriptions */ | ||||
|  | ||||
| FIELDS(UFID) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(TXXX) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_STRING | ||||
| }; | ||||
|  | ||||
| FIELDS(WXXX) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_LATIN1 | ||||
| }; | ||||
|  | ||||
| FIELDS(MCDI) = { | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(ETCO) = { | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(MLLT) = { | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_INT24, | ||||
|   ID3_FIELD_TYPE_INT24, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(SYTC) = { | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(USLT) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LANGUAGE, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_STRINGFULL | ||||
| }; | ||||
|  | ||||
| FIELDS(SYLT) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LANGUAGE, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(COMM) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LANGUAGE, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_STRINGFULL | ||||
| }; | ||||
|  | ||||
| FIELDS(RVA2) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(EQU2) = { | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(RVRB) = { | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT8 | ||||
| }; | ||||
|  | ||||
| FIELDS(APIC) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(GEOB) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(PCNT) = { | ||||
|   ID3_FIELD_TYPE_INT32PLUS | ||||
| }; | ||||
|  | ||||
| FIELDS(POPM) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT32PLUS | ||||
| }; | ||||
|  | ||||
| FIELDS(RBUF) = { | ||||
|   ID3_FIELD_TYPE_INT24, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT32 | ||||
| }; | ||||
|  | ||||
| FIELDS(AENC) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(LINK) = { | ||||
|   ID3_FIELD_TYPE_FRAMEID, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_LATIN1LIST | ||||
| }; | ||||
|  | ||||
| FIELDS(POSS) = { | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(USER) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LANGUAGE, | ||||
|   ID3_FIELD_TYPE_STRING | ||||
| }; | ||||
|  | ||||
| FIELDS(OWNE) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_DATE, | ||||
|   ID3_FIELD_TYPE_STRING | ||||
| }; | ||||
|  | ||||
| FIELDS(COMR) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_DATE, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(ENCR) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(GRID) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(PRIV) = { | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(SIGN) = { | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(SEEK) = { | ||||
|   ID3_FIELD_TYPE_INT32 | ||||
| }; | ||||
|  | ||||
| FIELDS(ASPI) = { | ||||
|   ID3_FIELD_TYPE_INT32, | ||||
|   ID3_FIELD_TYPE_INT32, | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(text) = { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_STRINGLIST | ||||
| }; | ||||
|  | ||||
| FIELDS(url) = { | ||||
|   ID3_FIELD_TYPE_LATIN1 | ||||
| }; | ||||
|  | ||||
| FIELDS(unknown) = { | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| FIELDS(ZOBS) = { | ||||
|   ID3_FIELD_TYPE_FRAMEID, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| # define FRAME(id)  \ | ||||
|   sizeof(fields_##id) / sizeof(fields_##id[0]), fields_##id | ||||
|  | ||||
| # define PRESERVE  0 | ||||
| # define DISCARD   ID3_FRAME_FLAG_FILEALTERPRESERVATION | ||||
| # define OBSOLETE  (DISCARD | ID3_FRAME_FLAG_TAGALTERPRESERVATION) | ||||
|  | ||||
| # define FRAMETYPE(type, id, flags, desc)  \ | ||||
|   struct id3_frametype const id3_frametype_##type = {  \ | ||||
|     0, FRAME(id), flags, desc  \ | ||||
|   } | ||||
|  | ||||
| /* static frame types */ | ||||
|  | ||||
| FRAMETYPE(text,         text,    PRESERVE, "Unknown text information frame"); | ||||
| FRAMETYPE(url,          url,     PRESERVE, "Unknown URL link frame"); | ||||
| FRAMETYPE(experimental, unknown, PRESERVE, "Experimental frame"); | ||||
| FRAMETYPE(unknown,      unknown, PRESERVE, "Unknown frame"); | ||||
| FRAMETYPE(obsolete,     unknown, OBSOLETE, "Obsolete frame"); | ||||
| %} | ||||
| struct id3_frametype; | ||||
| %% | ||||
| # | ||||
| # ID3v2.4 frames | ||||
| # | ||||
| AENC, FRAME(AENC), DISCARD,  "Audio encryption" | ||||
| APIC, FRAME(APIC), PRESERVE, "Attached picture" | ||||
| ASPI, FRAME(ASPI), DISCARD,  "Audio seek point index" | ||||
| COMM, FRAME(COMM), PRESERVE, "Comments" | ||||
| COMR, FRAME(COMR), PRESERVE, "Commercial frame" | ||||
| ENCR, FRAME(ENCR), PRESERVE, "Encryption method registration" | ||||
| EQU2, FRAME(EQU2), DISCARD,  "Equalisation (2)" | ||||
| ETCO, FRAME(ETCO), DISCARD,  "Event timing codes" | ||||
| GEOB, FRAME(GEOB), PRESERVE, "General encapsulated object" | ||||
| GRID, FRAME(GRID), PRESERVE, "Group identification registration" | ||||
| LINK, FRAME(LINK), PRESERVE, "Linked information" | ||||
| MCDI, FRAME(MCDI), PRESERVE, "Music CD identifier" | ||||
| MLLT, FRAME(MLLT), DISCARD,  "MPEG location lookup table" | ||||
| OWNE, FRAME(OWNE), PRESERVE, "Ownership frame" | ||||
| PCNT, FRAME(PCNT), PRESERVE, "Play counter" | ||||
| POPM, FRAME(POPM), PRESERVE, "Popularimeter" | ||||
| POSS, FRAME(POSS), DISCARD,  "Position synchronisation frame" | ||||
| PRIV, FRAME(PRIV), PRESERVE, "Private frame" | ||||
| RBUF, FRAME(RBUF), PRESERVE, "Recommended buffer size" | ||||
| RVA2, FRAME(RVA2), DISCARD,  "Relative volume adjustment (2)" | ||||
| RVRB, FRAME(RVRB), PRESERVE, "Reverb" | ||||
| SEEK, FRAME(SEEK), DISCARD,  "Seek frame" | ||||
| SIGN, FRAME(SIGN), PRESERVE, "Signature frame" | ||||
| SYLT, FRAME(SYLT), DISCARD,  "Synchronised lyric/text" | ||||
| SYTC, FRAME(SYTC), DISCARD,  "Synchronised tempo codes" | ||||
| TALB, FRAME(text), PRESERVE, "Album/movie/show title" | ||||
| TBPM, FRAME(text), PRESERVE, "BPM (beats per minute)" | ||||
| TCOM, FRAME(text), PRESERVE, "Composer" | ||||
| TCON, FRAME(text), PRESERVE, "Content type" | ||||
| TCOP, FRAME(text), PRESERVE, "Copyright message" | ||||
| TDEN, FRAME(text), PRESERVE, "Encoding time" | ||||
| TDLY, FRAME(text), PRESERVE, "Playlist delay" | ||||
| TDOR, FRAME(text), PRESERVE, "Original release time" | ||||
| TDRC, FRAME(text), PRESERVE, "Recording time" | ||||
| TDRL, FRAME(text), PRESERVE, "Release time" | ||||
| TDTG, FRAME(text), PRESERVE, "Tagging time" | ||||
| TENC, FRAME(text), DISCARD,  "Encoded by" | ||||
| TEXT, FRAME(text), PRESERVE, "Lyricist/text writer" | ||||
| TFLT, FRAME(text), PRESERVE, "File type" | ||||
| TIPL, FRAME(text), PRESERVE, "Involved people list" | ||||
| TIT1, FRAME(text), PRESERVE, "Content group description" | ||||
| TIT2, FRAME(text), PRESERVE, "Title/songname/content description" | ||||
| TIT3, FRAME(text), PRESERVE, "Subtitle/description refinement" | ||||
| TKEY, FRAME(text), PRESERVE, "Initial key" | ||||
| TLAN, FRAME(text), PRESERVE, "Language(s)" | ||||
| TLEN, FRAME(text), DISCARD,  "Length" | ||||
| TMCL, FRAME(text), PRESERVE, "Musician credits list" | ||||
| TMED, FRAME(text), PRESERVE, "Media type" | ||||
| TMOO, FRAME(text), PRESERVE, "Mood" | ||||
| TOAL, FRAME(text), PRESERVE, "Original album/movie/show title" | ||||
| TOFN, FRAME(text), PRESERVE, "Original filename" | ||||
| TOLY, FRAME(text), PRESERVE, "Original lyricist(s)/text writer(s)" | ||||
| TOPE, FRAME(text), PRESERVE, "Original artist(s)/performer(s)" | ||||
| TOWN, FRAME(text), PRESERVE, "File owner/licensee" | ||||
| TPE1, FRAME(text), PRESERVE, "Lead performer(s)/soloist(s)" | ||||
| TPE2, FRAME(text), PRESERVE, "Band/orchestra/accompaniment" | ||||
| TPE3, FRAME(text), PRESERVE, "Conductor/performer refinement" | ||||
| TPE4, FRAME(text), PRESERVE, "Interpreted, remixed, or otherwise modified by" | ||||
| TPOS, FRAME(text), PRESERVE, "Part of a set" | ||||
| TPRO, FRAME(text), PRESERVE, "Produced notice" | ||||
| TPUB, FRAME(text), PRESERVE, "Publisher" | ||||
| TRCK, FRAME(text), PRESERVE, "Track number/position in set" | ||||
| TRSN, FRAME(text), PRESERVE, "Internet radio station name" | ||||
| TRSO, FRAME(text), PRESERVE, "Internet radio station owner" | ||||
| TSOA, FRAME(text), PRESERVE, "Album sort order" | ||||
| TSOP, FRAME(text), PRESERVE, "Performer sort order" | ||||
| TSOT, FRAME(text), PRESERVE, "Title sort order" | ||||
| TSRC, FRAME(text), PRESERVE, "ISRC (international standard recording code)" | ||||
| TSSE, FRAME(text), PRESERVE, "Software/hardware and settings used for encoding" | ||||
| TSST, FRAME(text), PRESERVE, "Set subtitle" | ||||
| TXXX, FRAME(TXXX), PRESERVE, "User defined text information frame" | ||||
| UFID, FRAME(UFID), PRESERVE, "Unique file identifier" | ||||
| USER, FRAME(USER), PRESERVE, "Terms of use" | ||||
| USLT, FRAME(USLT), PRESERVE, "Unsynchronised lyric/text transcription" | ||||
| WCOM, FRAME(url),  PRESERVE, "Commercial information" | ||||
| WCOP, FRAME(url),  PRESERVE, "Copyright/legal information" | ||||
| WOAF, FRAME(url),  PRESERVE, "Official audio file webpage" | ||||
| WOAR, FRAME(url),  PRESERVE, "Official artist/performer webpage" | ||||
| WOAS, FRAME(url),  PRESERVE, "Official audio source webpage" | ||||
| WORS, FRAME(url),  PRESERVE, "Official Internet radio station homepage" | ||||
| WPAY, FRAME(url),  PRESERVE, "Payment" | ||||
| WPUB, FRAME(url),  PRESERVE, "Publishers official webpage" | ||||
| WXXX, FRAME(WXXX), PRESERVE, "User defined URL link frame" | ||||
| # | ||||
| # Special frames | ||||
| # | ||||
| ZOBS, FRAME(ZOBS), OBSOLETE, "Obsolete frame" | ||||
							
								
								
									
										42
									
								
								src/libid3tag/frametype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/libid3tag/frametype.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: frametype.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_FRAMETYPE_H | ||||
| # define LIBID3TAG_FRAMETYPE_H | ||||
|  | ||||
| struct id3_frametype { | ||||
|   char const *id; | ||||
|   unsigned int nfields; | ||||
|   enum id3_field_type const *fields; | ||||
|   int defaultflags; | ||||
|   char const *description; | ||||
| }; | ||||
|  | ||||
| extern struct id3_frametype const id3_frametype_text; | ||||
| extern struct id3_frametype const id3_frametype_url; | ||||
| extern struct id3_frametype const id3_frametype_experimental; | ||||
| extern struct id3_frametype const id3_frametype_unknown; | ||||
| extern struct id3_frametype const id3_frametype_obsolete; | ||||
|  | ||||
| struct id3_frametype const *id3_frametype_lookup(register char const *, | ||||
| 						 register unsigned int); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										151
									
								
								src/libid3tag/genre.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/libid3tag/genre.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: genre.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "ucs4.h" | ||||
|  | ||||
| /* genres are stored in ucs4 format */ | ||||
| # include "genre.dat" | ||||
|  | ||||
| # define NGENRES  (sizeof(genre_table) / sizeof(genre_table[0])) | ||||
|  | ||||
| /* | ||||
|  * NAME:	genre->index() | ||||
|  * DESCRIPTION:	return an ID3v1 genre string indexed by number | ||||
|  */ | ||||
| id3_ucs4_t const *id3_genre_index(unsigned int index) | ||||
| { | ||||
|   return (index < NGENRES) ? genre_table[index] : 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	genre->name() | ||||
|  * DESCRIPTION:	translate an ID3v2 genre number/keyword to its full name | ||||
|  */ | ||||
| id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *string) | ||||
| { | ||||
|   id3_ucs4_t const *ptr; | ||||
|   static id3_ucs4_t const genre_remix[] = { 'R', 'e', 'm', 'i', 'x', 0 }; | ||||
|   static id3_ucs4_t const genre_cover[] = { 'C', 'o', 'v', 'e', 'r', 0 }; | ||||
|   unsigned long number; | ||||
|  | ||||
|   if (string == 0 || *string == 0) | ||||
|     return id3_ucs4_empty; | ||||
|  | ||||
|   if (string[0] == 'R' && string[1] == 'X' && string[2] == 0) | ||||
|     return genre_remix; | ||||
|   if (string[0] == 'C' && string[1] == 'R' && string[2] == 0) | ||||
|     return genre_cover; | ||||
|  | ||||
|   for (ptr = string; *ptr; ++ptr) { | ||||
|     if (*ptr < '0' || *ptr > '9') | ||||
|       return string; | ||||
|   } | ||||
|  | ||||
|   number = id3_ucs4_getnumber(string); | ||||
|  | ||||
|   return (number < NGENRES) ? genre_table[number] : string; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	translate() | ||||
|  * DESCRIPTION:	return a canonicalized character for testing genre equivalence | ||||
|  */ | ||||
| static | ||||
| id3_ucs4_t translate(id3_ucs4_t ch) | ||||
| { | ||||
|   if (ch) { | ||||
|     if (ch >= 'A' && ch <= 'Z') | ||||
|       ch += 'a' - 'A'; | ||||
|  | ||||
|     if (ch < 'a' || ch > 'z') | ||||
|       ch = ID3_UCS4_REPLACEMENTCHAR; | ||||
|   } | ||||
|  | ||||
|   return ch; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	compare() | ||||
|  * DESCRIPTION:	test two ucs4 genre strings for equivalence | ||||
|  */ | ||||
| static | ||||
| int compare(id3_ucs4_t const *str1, id3_ucs4_t const *str2) | ||||
| { | ||||
|   id3_ucs4_t c1, c2; | ||||
|  | ||||
|   if (str1 == str2) | ||||
|     return 1; | ||||
|  | ||||
|   do { | ||||
|     do | ||||
|       c1 = translate(*str1++); | ||||
|     while (c1 == ID3_UCS4_REPLACEMENTCHAR); | ||||
|  | ||||
|     do | ||||
|       c2 = translate(*str2++); | ||||
|     while (c2 == ID3_UCS4_REPLACEMENTCHAR); | ||||
|   } | ||||
|   while (c1 && c1 == c2); | ||||
|  | ||||
|   return c1 == c2; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	genre->number() | ||||
|  * DESCRIPTION:	translate an ID3v2 genre name/number to its ID3v1 index number | ||||
|  */ | ||||
| int id3_genre_number(id3_ucs4_t const *string) | ||||
| { | ||||
|   id3_ucs4_t const *ptr; | ||||
|   int i; | ||||
|  | ||||
|   if (string == 0 || *string == 0) | ||||
|     return -1; | ||||
|  | ||||
|   for (ptr = string; *ptr; ++ptr) { | ||||
|     if (*ptr < '0' || *ptr > '9') | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   if (*ptr == 0) { | ||||
|     unsigned long number; | ||||
|  | ||||
|     number = id3_ucs4_getnumber(string); | ||||
|  | ||||
|     return (number <= 0xff) ? number : -1; | ||||
|   } | ||||
|  | ||||
|   for (i = 0; i < NGENRES; ++i) { | ||||
|     if (compare(string, genre_table[i])) | ||||
|       return i; | ||||
|   } | ||||
|  | ||||
|   /* no equivalent */ | ||||
|  | ||||
|   return -1; | ||||
| } | ||||
							
								
								
									
										180
									
								
								src/libid3tag/genre.dat.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								src/libid3tag/genre.dat.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: genre.dat.in,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * These are the ID3 genre names, taken as a combination of names from ID3v1 | ||||
|  * (listed in Appendix A of the ID3 tag version 2.4.0 informal standard) and | ||||
|  * the extensions made by Winamp as of version 2.80. | ||||
|  */ | ||||
|  | ||||
| /* ID3v1 names (0-79) */ | ||||
|  | ||||
| Blues | ||||
| Classic Rock | ||||
| Country | ||||
| Dance | ||||
| Disco | ||||
| Funk | ||||
| Grunge | ||||
| Hip-Hop | ||||
| Jazz | ||||
| Metal | ||||
| New Age | ||||
| Oldies | ||||
| Other | ||||
| Pop | ||||
| R&B | ||||
| Rap | ||||
| Reggae | ||||
| Rock | ||||
| Techno | ||||
| Industrial | ||||
| Alternative | ||||
| Ska | ||||
| Death Metal | ||||
| Pranks | ||||
| Soundtrack | ||||
| Euro-Techno | ||||
| Ambient | ||||
| Trip-Hop | ||||
| Vocal | ||||
| Jazz+Funk | ||||
| Fusion | ||||
| Trance | ||||
| Classical | ||||
| Instrumental | ||||
| Acid | ||||
| House | ||||
| Game | ||||
| Sound Clip | ||||
| Gospel | ||||
| Noise | ||||
| AlternRock | ||||
| Bass | ||||
| Soul | ||||
| Punk | ||||
| Space | ||||
| Meditative | ||||
| Instrumental Pop | ||||
| Instrumental Rock | ||||
| Ethnic | ||||
| Gothic | ||||
| Darkwave | ||||
| Techno-Industrial | ||||
| Electronic | ||||
| Pop-Folk | ||||
| Eurodance | ||||
| Dream | ||||
| Southern Rock | ||||
| Comedy | ||||
| Cult | ||||
| Gangsta | ||||
| Top 40 | ||||
| Christian Rap | ||||
| Pop/Funk | ||||
| Jungle | ||||
| Native American | ||||
| Cabaret | ||||
| New Wave | ||||
| Psychedelic | ||||
| Rave | ||||
| Showtunes | ||||
| Trailer | ||||
| Lo-Fi | ||||
| Tribal | ||||
| Acid Punk | ||||
| Acid Jazz | ||||
| Polka | ||||
| Retro | ||||
| Musical | ||||
| Rock & Roll | ||||
| Hard Rock | ||||
|  | ||||
| /* Winamp extensions (80-147) */ | ||||
|  | ||||
| Folk | ||||
| Folk/Rock | ||||
| National Folk | ||||
| Swing | ||||
| Fast-Fusion | ||||
| Bebob | ||||
| Latin | ||||
| Revival | ||||
| Celtic | ||||
| Bluegrass | ||||
| Avantgarde | ||||
| Gothic Rock | ||||
| Progressive Rock | ||||
| Psychedelic Rock | ||||
| Symphonic Rock | ||||
| Slow Rock | ||||
| Big Band | ||||
| Chorus | ||||
| Easy Listening | ||||
| Acoustic | ||||
| Humour | ||||
| Speech | ||||
| Chanson | ||||
| Opera | ||||
| Chamber Music | ||||
| Sonata | ||||
| Symphony | ||||
| Booty Bass | ||||
| Primus | ||||
| Porn Groove | ||||
| Satire | ||||
| Slow Jam | ||||
| Club | ||||
| Tango | ||||
| Samba | ||||
| Folklore | ||||
| Ballad | ||||
| Power Ballad | ||||
| Rhythmic Soul | ||||
| Freestyle | ||||
| Duet | ||||
| Punk Rock | ||||
| Drum Solo | ||||
| A Cappella | ||||
| Euro-House | ||||
| Dance Hall | ||||
| Goa | ||||
| Drum & Bass | ||||
| Club-House | ||||
| Hardcore | ||||
| Terror | ||||
| Indie | ||||
| BritPop | ||||
| Negerpunk | ||||
| Polsk Punk | ||||
| Beat | ||||
| Christian Gangsta Rap | ||||
| Heavy Metal | ||||
| Black Metal | ||||
| Crossover | ||||
| Contemporary Christian | ||||
| Christian Rock | ||||
| Merengue | ||||
| Salsa | ||||
| Thrash Metal | ||||
| Anime | ||||
| JPop | ||||
| Synthpop | ||||
							
								
								
									
										54
									
								
								src/libid3tag/genre.dat.sed
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/libid3tag/genre.dat.sed
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| # | ||||
| # libid3tag - ID3 tag manipulation library | ||||
| # Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
| # | ||||
| # 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 | ||||
| # | ||||
| # $Id: genre.dat.sed,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
| # | ||||
|  | ||||
| 1i\ | ||||
| /* Automatically generated from genre.dat.in */ | ||||
|  | ||||
| # generate an array from a string | ||||
| /^[A-Za-z]/{ | ||||
| H | ||||
| y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ | ||||
| s/[^A-Z0-9]/_/g | ||||
| s/.*/static id3_ucs4_t const genre_&[] =/p | ||||
| g | ||||
| s/.*\n// | ||||
| s/./'&', /g | ||||
| s/.*/  { &0 };/ | ||||
| } | ||||
|  | ||||
| # write the final table of arrays | ||||
| ${ | ||||
| p | ||||
| i\ | ||||
| \ | ||||
| static id3_ucs4_t const *const genre_table[] = { | ||||
| g | ||||
| s/^\(\n\)\(.*\)$/\2\1/ | ||||
| y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ | ||||
| s/[^A-Z0-9\n]/_/g | ||||
| s/\([^\n]*\)\(\n\)/  genre_\1,\2/g | ||||
| s/,\n$// | ||||
| a\ | ||||
| }; | ||||
| } | ||||
|  | ||||
| # print the pattern space (assumes -n) | ||||
| p | ||||
							
								
								
									
										27
									
								
								src/libid3tag/genre.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/libid3tag/genre.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: genre.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_GENRE_H | ||||
| # define LIBID3TAG_GENRE_H | ||||
|  | ||||
| # define ID3_GENRE_OTHER  12 | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										53
									
								
								src/libid3tag/global.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/libid3tag/global.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: global.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_GLOBAL_H | ||||
| # define LIBID3TAG_GLOBAL_H | ||||
|  | ||||
| /* conditional debugging */ | ||||
|  | ||||
| # if defined(DEBUG) && defined(NDEBUG) | ||||
| #  error "cannot define both DEBUG and NDEBUG" | ||||
| # endif | ||||
|  | ||||
| # if defined(DEBUG) | ||||
| #  include <stdio.h> | ||||
| #  include "debug.h" | ||||
| #  define malloc(sz)        id3_debug_malloc(sz,       __FILE__, __LINE__) | ||||
| #  define calloc(n, sz)     id3_debug_calloc(n, sz,    __FILE__, __LINE__) | ||||
| #  define realloc(ptr, sz)  id3_debug_realloc(ptr, sz, __FILE__, __LINE__) | ||||
| #  define free(ptr)         id3_debug_free(ptr,        __FILE__, __LINE__) | ||||
| #  define release(ptr)      id3_debug_release(ptr,     __FILE__, __LINE__) | ||||
| # else | ||||
| #  define release(ptr)  (ptr) | ||||
| # endif | ||||
|  | ||||
| /* conditional features */ | ||||
|  | ||||
| # if !defined(HAVE_ASSERT_H) | ||||
| #  if defined(NDEBUG) | ||||
| #   define assert(x)	/* nothing */ | ||||
| #  else | ||||
| #   define assert(x)	do { if (!(x)) abort(); } while (0) | ||||
| #  endif | ||||
| # endif | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										363
									
								
								src/libid3tag/id3tag.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								src/libid3tag/id3tag.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,363 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * If you would like to negotiate alternate licensing terms, you may do | ||||
|  * so by contacting: Underbit Technologies, Inc. <info@underbit.com> | ||||
|  * | ||||
|  * $Id: id3tag.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_ID3TAG_H | ||||
| # define LIBID3TAG_ID3TAG_H | ||||
|  | ||||
| # ifdef __cplusplus | ||||
| extern "C" { | ||||
| # endif | ||||
|  | ||||
| # define ID3_TAG_VERSION		0x0400 | ||||
| # define ID3_TAG_VERSION_MAJOR(x)	(((x) >> 8) & 0xff) | ||||
| # define ID3_TAG_VERSION_MINOR(x)	(((x) >> 0) & 0xff) | ||||
|  | ||||
| typedef unsigned char id3_byte_t; | ||||
| typedef unsigned long id3_length_t; | ||||
|  | ||||
| typedef unsigned long id3_ucs4_t; | ||||
|  | ||||
| typedef unsigned char id3_latin1_t; | ||||
| typedef unsigned short id3_utf16_t; | ||||
| typedef signed char id3_utf8_t; | ||||
|  | ||||
| struct id3_tag { | ||||
|   unsigned int refcount; | ||||
|   unsigned int version; | ||||
|   int flags; | ||||
|   int extendedflags; | ||||
|   int restrictions; | ||||
|   int options; | ||||
|   unsigned int nframes; | ||||
|   struct id3_frame **frames; | ||||
|   id3_length_t paddedsize; | ||||
| }; | ||||
|  | ||||
| # define ID3_TAG_QUERYSIZE	10 | ||||
|  | ||||
| /* ID3v1 field frames */ | ||||
|  | ||||
| # define ID3_FRAME_TITLE	"TIT2" | ||||
| # define ID3_FRAME_ARTIST	"TPE1" | ||||
| # define ID3_FRAME_ALBUM	"TALB" | ||||
| # define ID3_FRAME_TRACK	"TRCK" | ||||
| # define ID3_FRAME_YEAR		"TDRC" | ||||
| # define ID3_FRAME_GENRE	"TCON" | ||||
| # define ID3_FRAME_COMMENT	"COMM" | ||||
|  | ||||
| /* special frames */ | ||||
|  | ||||
| # define ID3_FRAME_OBSOLETE	"ZOBS"	/* with apologies to the French */ | ||||
|  | ||||
| /* tag flags */ | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_FLAG_UNSYNCHRONISATION     = 0x80, | ||||
|   ID3_TAG_FLAG_EXTENDEDHEADER        = 0x40, | ||||
|   ID3_TAG_FLAG_EXPERIMENTALINDICATOR = 0x20, | ||||
|   ID3_TAG_FLAG_FOOTERPRESENT         = 0x10, | ||||
|  | ||||
|   ID3_TAG_FLAG_KNOWNFLAGS            = 0xf0 | ||||
| }; | ||||
|  | ||||
| /* tag extended flags */ | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE   = 0x40, | ||||
|   ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT  = 0x20, | ||||
|   ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS = 0x10, | ||||
|  | ||||
|   ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS      = 0x70 | ||||
| }; | ||||
|  | ||||
| /* tag restrictions */ | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_RESTRICTION_TAGSIZE_MASK             = 0xc0, | ||||
|   ID3_TAG_RESTRICTION_TAGSIZE_128_FRAMES_1_MB  = 0x00, | ||||
|   ID3_TAG_RESTRICTION_TAGSIZE_64_FRAMES_128_KB = 0x40, | ||||
|   ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_40_KB  = 0x80, | ||||
|   ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_4_KB   = 0xc0 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_RESTRICTION_TEXTENCODING_MASK        = 0x20, | ||||
|   ID3_TAG_RESTRICTION_TEXTENCODING_NONE        = 0x00, | ||||
|   ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 = 0x20 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_RESTRICTION_TEXTSIZE_MASK            = 0x18, | ||||
|   ID3_TAG_RESTRICTION_TEXTSIZE_NONE            = 0x00, | ||||
|   ID3_TAG_RESTRICTION_TEXTSIZE_1024_CHARS      = 0x08, | ||||
|   ID3_TAG_RESTRICTION_TEXTSIZE_128_CHARS       = 0x10, | ||||
|   ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS        = 0x18 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_RESTRICTION_IMAGEENCODING_MASK       = 0x04, | ||||
|   ID3_TAG_RESTRICTION_IMAGEENCODING_NONE       = 0x00, | ||||
|   ID3_TAG_RESTRICTION_IMAGEENCODING_PNG_JPEG   = 0x04 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_RESTRICTION_IMAGESIZE_MASK           = 0x03, | ||||
|   ID3_TAG_RESTRICTION_IMAGESIZE_NONE           = 0x00, | ||||
|   ID3_TAG_RESTRICTION_IMAGESIZE_256_256        = 0x01, | ||||
|   ID3_TAG_RESTRICTION_IMAGESIZE_64_64          = 0x02, | ||||
|   ID3_TAG_RESTRICTION_IMAGESIZE_64_64_EXACT    = 0x03 | ||||
| }; | ||||
|  | ||||
| /* library options */ | ||||
|  | ||||
| enum { | ||||
|   ID3_TAG_OPTION_UNSYNCHRONISATION = 0x0001,	/* use unsynchronisation */ | ||||
|   ID3_TAG_OPTION_COMPRESSION       = 0x0002,	/* use compression */ | ||||
|   ID3_TAG_OPTION_CRC               = 0x0004,	/* use CRC */ | ||||
|  | ||||
|   ID3_TAG_OPTION_APPENDEDTAG       = 0x0010,	/* tag will be appended */ | ||||
|   ID3_TAG_OPTION_FILEALTERED       = 0x0020,	/* audio data was altered */ | ||||
|  | ||||
|   ID3_TAG_OPTION_ID3V1             = 0x0100	/* render ID3v1/ID3v1.1 tag */ | ||||
| }; | ||||
|  | ||||
| struct id3_frame { | ||||
|   char id[5]; | ||||
|   char const *description; | ||||
|   unsigned int refcount; | ||||
|   int flags; | ||||
|   int group_id; | ||||
|   int encryption_method; | ||||
|   id3_byte_t *encoded; | ||||
|   id3_length_t encoded_length; | ||||
|   id3_length_t decoded_length; | ||||
|   unsigned int nfields; | ||||
|   union id3_field *fields; | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   /* frame status flags */ | ||||
|   ID3_FRAME_FLAG_TAGALTERPRESERVATION	= 0x4000, | ||||
|   ID3_FRAME_FLAG_FILEALTERPRESERVATION	= 0x2000, | ||||
|   ID3_FRAME_FLAG_READONLY		= 0x1000, | ||||
|  | ||||
|   ID3_FRAME_FLAG_STATUSFLAGS            = 0xff00, | ||||
|  | ||||
|   /* frame format flags */ | ||||
|   ID3_FRAME_FLAG_GROUPINGIDENTITY	= 0x0040, | ||||
|   ID3_FRAME_FLAG_COMPRESSION		= 0x0008, | ||||
|   ID3_FRAME_FLAG_ENCRYPTION		= 0x0004, | ||||
|   ID3_FRAME_FLAG_UNSYNCHRONISATION	= 0x0002, | ||||
|   ID3_FRAME_FLAG_DATALENGTHINDICATOR	= 0x0001, | ||||
|  | ||||
|   ID3_FRAME_FLAG_FORMATFLAGS            = 0x00ff, | ||||
|  | ||||
|   ID3_FRAME_FLAG_KNOWNFLAGS             = 0x704f | ||||
| }; | ||||
|  | ||||
| enum id3_field_type { | ||||
|   ID3_FIELD_TYPE_TEXTENCODING, | ||||
|   ID3_FIELD_TYPE_LATIN1, | ||||
|   ID3_FIELD_TYPE_LATIN1FULL, | ||||
|   ID3_FIELD_TYPE_LATIN1LIST, | ||||
|   ID3_FIELD_TYPE_STRING, | ||||
|   ID3_FIELD_TYPE_STRINGFULL, | ||||
|   ID3_FIELD_TYPE_STRINGLIST, | ||||
|   ID3_FIELD_TYPE_LANGUAGE, | ||||
|   ID3_FIELD_TYPE_FRAMEID, | ||||
|   ID3_FIELD_TYPE_DATE, | ||||
|   ID3_FIELD_TYPE_INT8, | ||||
|   ID3_FIELD_TYPE_INT16, | ||||
|   ID3_FIELD_TYPE_INT24, | ||||
|   ID3_FIELD_TYPE_INT32, | ||||
|   ID3_FIELD_TYPE_INT32PLUS, | ||||
|   ID3_FIELD_TYPE_BINARYDATA | ||||
| }; | ||||
|  | ||||
| enum id3_field_textencoding { | ||||
|   ID3_FIELD_TEXTENCODING_ISO_8859_1 = 0x00, | ||||
|   ID3_FIELD_TEXTENCODING_UTF_16     = 0x01, | ||||
|   ID3_FIELD_TEXTENCODING_UTF_16BE   = 0x02, | ||||
|   ID3_FIELD_TEXTENCODING_UTF_8      = 0x03 | ||||
| }; | ||||
|  | ||||
| union id3_field { | ||||
|   enum id3_field_type type; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     signed long value; | ||||
|   } number; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     id3_latin1_t *ptr; | ||||
|   } latin1; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     unsigned int nstrings; | ||||
|     id3_latin1_t **strings; | ||||
|   } latin1list; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     id3_ucs4_t *ptr; | ||||
|   } string; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     unsigned int nstrings; | ||||
|     id3_ucs4_t **strings; | ||||
|   } stringlist; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     char value[9]; | ||||
|   } immediate; | ||||
|   struct { | ||||
|     enum id3_field_type type; | ||||
|     id3_byte_t *data; | ||||
|     id3_length_t length; | ||||
|   } binary; | ||||
| }; | ||||
|  | ||||
| /* file interface */ | ||||
|  | ||||
| enum id3_file_mode { | ||||
|   ID3_FILE_MODE_READONLY = 0, | ||||
|   ID3_FILE_MODE_READWRITE | ||||
| }; | ||||
|  | ||||
| struct id3_file *id3_file_open(char const *, enum id3_file_mode); | ||||
| struct id3_file *id3_file_fdopen(int, enum id3_file_mode); | ||||
| int id3_file_close(struct id3_file *); | ||||
|  | ||||
| struct id3_tag *id3_file_tag(struct id3_file const *); | ||||
|  | ||||
| int id3_file_update(struct id3_file *); | ||||
|  | ||||
| /* tag interface */ | ||||
|  | ||||
| struct id3_tag *id3_tag_new(void); | ||||
| void id3_tag_delete(struct id3_tag *); | ||||
|  | ||||
| unsigned int id3_tag_version(struct id3_tag const *); | ||||
|  | ||||
| int id3_tag_options(struct id3_tag *, int, int); | ||||
| void id3_tag_setlength(struct id3_tag *, id3_length_t); | ||||
|  | ||||
| void id3_tag_clearframes(struct id3_tag *); | ||||
|  | ||||
| int id3_tag_attachframe(struct id3_tag *, struct id3_frame *); | ||||
| int id3_tag_detachframe(struct id3_tag *, struct id3_frame *); | ||||
|  | ||||
| struct id3_frame *id3_tag_findframe(struct id3_tag const *, | ||||
| 				    char const *, unsigned int); | ||||
|  | ||||
| signed long id3_tag_query(id3_byte_t const *, id3_length_t); | ||||
|  | ||||
| struct id3_tag *id3_tag_parse(id3_byte_t const *, id3_length_t); | ||||
| id3_length_t id3_tag_render(struct id3_tag const *, id3_byte_t *); | ||||
|  | ||||
| /* frame interface */ | ||||
|  | ||||
| struct id3_frame *id3_frame_new(char const *); | ||||
| void id3_frame_delete(struct id3_frame *); | ||||
|  | ||||
| union id3_field *id3_frame_field(struct id3_frame const *, unsigned int); | ||||
|  | ||||
| /* field interface */ | ||||
|  | ||||
| enum id3_field_type id3_field_type(union id3_field const *); | ||||
|  | ||||
| int id3_field_setint(union id3_field *, signed long); | ||||
| int id3_field_settextencoding(union id3_field *, enum id3_field_textencoding); | ||||
| int id3_field_setstrings(union id3_field *, unsigned int, id3_ucs4_t **); | ||||
| int id3_field_addstring(union id3_field *, id3_ucs4_t const *); | ||||
| int id3_field_setlanguage(union id3_field *, char const *); | ||||
| int id3_field_setlatin1(union id3_field *, id3_latin1_t const *); | ||||
| int id3_field_setfulllatin1(union id3_field *, id3_latin1_t const *); | ||||
| int id3_field_setstring(union id3_field *, id3_ucs4_t const *); | ||||
| int id3_field_setfullstring(union id3_field *, id3_ucs4_t const *); | ||||
| int id3_field_setframeid(union id3_field *, char const *); | ||||
| int id3_field_setbinarydata(union id3_field *, | ||||
| 			    id3_byte_t const *, id3_length_t); | ||||
|  | ||||
| signed long id3_field_getint(union id3_field const *); | ||||
| id3_latin1_t const *id3_field_getlatin1(union id3_field const *); | ||||
| id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *); | ||||
| id3_ucs4_t const *id3_field_getstring(union id3_field const *); | ||||
| id3_ucs4_t const *id3_field_getfullstring(union id3_field const *); | ||||
| unsigned int id3_field_getnstrings(union id3_field const *); | ||||
| id3_ucs4_t const *id3_field_getstrings(union id3_field const *, | ||||
| 				       unsigned int); | ||||
| char const *id3_field_getframeid(union id3_field const *); | ||||
| id3_byte_t const *id3_field_getbinarydata(union id3_field const *, | ||||
| 					  id3_length_t *); | ||||
|  | ||||
| /* genre interface */ | ||||
|  | ||||
| id3_ucs4_t const *id3_genre_index(unsigned int); | ||||
| id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *); | ||||
| int id3_genre_number(id3_ucs4_t const *); | ||||
|  | ||||
| /* ucs4 interface */ | ||||
|  | ||||
| id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *); | ||||
| id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *); | ||||
| id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *); | ||||
|  | ||||
| void id3_ucs4_putnumber(id3_ucs4_t *, unsigned long); | ||||
| unsigned long id3_ucs4_getnumber(id3_ucs4_t const *); | ||||
|  | ||||
| /* latin1/utf16/utf8 interfaces */ | ||||
|  | ||||
| id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *); | ||||
| id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *); | ||||
| id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *); | ||||
|  | ||||
| /* version interface */ | ||||
|  | ||||
| # define ID3_VERSION_MAJOR	0 | ||||
| # define ID3_VERSION_MINOR	15 | ||||
| # define ID3_VERSION_PATCH	0 | ||||
| # define ID3_VERSION_EXTRA	" (beta)" | ||||
|  | ||||
| # define ID3_VERSION_STRINGIZE(str)	#str | ||||
| # define ID3_VERSION_STRING(num)	ID3_VERSION_STRINGIZE(num) | ||||
|  | ||||
| # define ID3_VERSION	ID3_VERSION_STRING(ID3_VERSION_MAJOR) "."  \ | ||||
| 			ID3_VERSION_STRING(ID3_VERSION_MINOR) "."  \ | ||||
| 			ID3_VERSION_STRING(ID3_VERSION_PATCH)  \ | ||||
| 			ID3_VERSION_EXTRA | ||||
|  | ||||
| # define ID3_PUBLISHYEAR	"2000-2003" | ||||
| # define ID3_AUTHOR		"Underbit Technologies, Inc." | ||||
| # define ID3_EMAIL		"info@underbit.com" | ||||
|  | ||||
| extern char const id3_version[]; | ||||
| extern char const id3_copyright[]; | ||||
| extern char const id3_author[]; | ||||
| extern char const id3_build[]; | ||||
|  | ||||
| # ifdef __cplusplus | ||||
| } | ||||
| # endif | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										217
									
								
								src/libid3tag/latin1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/libid3tag/latin1.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: latin1.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "latin1.h" | ||||
| # include "ucs4.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->length() | ||||
|  * DESCRIPTION:	return the number of ucs4 chars represented by a latin1 string | ||||
|  */ | ||||
| id3_length_t id3_latin1_length(id3_latin1_t const *latin1) | ||||
| { | ||||
|   id3_latin1_t const *ptr = latin1; | ||||
|  | ||||
|   while (*ptr) | ||||
|     ++ptr; | ||||
|  | ||||
|   return ptr - latin1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->size() | ||||
|  * DESCRIPTION:	return the encoding size of a latin1 string | ||||
|  */ | ||||
| id3_length_t id3_latin1_size(id3_latin1_t const *latin1) | ||||
| { | ||||
|   return id3_latin1_length(latin1) + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->copy() | ||||
|  * DESCRIPTION:	copy a latin1 string | ||||
|  */ | ||||
| void id3_latin1_copy(id3_latin1_t *dest, id3_latin1_t const *src) | ||||
| { | ||||
|   while ((*dest++ = *src++)) | ||||
|     ; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->duplicate() | ||||
|  * DESCRIPTION:	duplicate a latin1 string | ||||
|  */ | ||||
| id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *src) | ||||
| { | ||||
|   id3_latin1_t *latin1; | ||||
|  | ||||
|   latin1 = malloc(id3_latin1_size(src) * sizeof(*latin1)); | ||||
|   if (latin1) | ||||
|     id3_latin1_copy(latin1, src); | ||||
|  | ||||
|   return latin1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->ucs4duplicate() | ||||
|  * DESCRIPTION:	duplicate and decode a latin1 string into ucs4 | ||||
|  */ | ||||
| id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *latin1) | ||||
| { | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_latin1_decode(latin1, ucs4); | ||||
|  | ||||
|   return release(ucs4); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->decodechar() | ||||
|  * DESCRIPTION:	decode a (single) latin1 char into a single ucs4 char | ||||
|  */ | ||||
| id3_length_t id3_latin1_decodechar(id3_latin1_t const *latin1, | ||||
| 				   id3_ucs4_t *ucs4) | ||||
| { | ||||
|   *ucs4 = *latin1; | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->encodechar() | ||||
|  * DESCRIPTION:	encode a single ucs4 char into a (single) latin1 char | ||||
|  */ | ||||
| id3_length_t id3_latin1_encodechar(id3_latin1_t *latin1, id3_ucs4_t ucs4) | ||||
| { | ||||
|   *latin1 = ucs4; | ||||
|   if (ucs4 > 0x000000ffL) | ||||
|     *latin1 = ID3_UCS4_REPLACEMENTCHAR; | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->decode() | ||||
|  * DESCRIPTION:	decode a complete latin1 string into a ucs4 string | ||||
|  */ | ||||
| void id3_latin1_decode(id3_latin1_t const *latin1, id3_ucs4_t *ucs4) | ||||
| { | ||||
|   do | ||||
|     latin1 += id3_latin1_decodechar(latin1, ucs4); | ||||
|   while (*ucs4++); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->encode() | ||||
|  * DESCRIPTION:	encode a complete ucs4 string into a latin1 string | ||||
|  */ | ||||
| void id3_latin1_encode(id3_latin1_t *latin1, id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   do | ||||
|     latin1 += id3_latin1_encodechar(latin1, *ucs4); | ||||
|   while (*ucs4++); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->put() | ||||
|  * DESCRIPTION:	serialize a single latin1 character | ||||
|  */ | ||||
| id3_length_t id3_latin1_put(id3_byte_t **ptr, id3_latin1_t latin1) | ||||
| { | ||||
|   if (ptr) | ||||
|     *(*ptr)++ = latin1; | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->get() | ||||
|  * DESCRIPTION:	deserialize a single latin1 character | ||||
|  */ | ||||
| id3_latin1_t id3_latin1_get(id3_byte_t const **ptr) | ||||
| { | ||||
|   return *(*ptr)++; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->serialize() | ||||
|  * DESCRIPTION:	serialize a ucs4 string using latin1 encoding | ||||
|  */ | ||||
| id3_length_t id3_latin1_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, | ||||
| 				  int terminate) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|   id3_latin1_t latin1[1], *out; | ||||
|  | ||||
|   while (*ucs4) { | ||||
|     switch (id3_latin1_encodechar(out = latin1, *ucs4++)) { | ||||
|     case 1: size += id3_latin1_put(ptr, *out++); | ||||
|     case 0: break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (terminate) | ||||
|     size += id3_latin1_put(ptr, 0); | ||||
|  | ||||
|   return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	latin1->deserialize() | ||||
|  * DESCRIPTION:	deserialize a ucs4 string using latin1 encoding | ||||
|  */ | ||||
| id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **ptr, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t const *end; | ||||
|   id3_latin1_t *latin1ptr, *latin1; | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   end = *ptr + length; | ||||
|  | ||||
|   latin1 = malloc((length + 1) * sizeof(*latin1)); | ||||
|   if (latin1 == 0) | ||||
|     return 0; | ||||
|  | ||||
|   latin1ptr = latin1; | ||||
|   while (end - *ptr > 0 && (*latin1ptr = id3_latin1_get(ptr))) | ||||
|     ++latin1ptr; | ||||
|  | ||||
|   *latin1ptr = 0; | ||||
|  | ||||
|   ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_latin1_decode(latin1, ucs4); | ||||
|  | ||||
|   free(latin1); | ||||
|  | ||||
|   return ucs4; | ||||
| } | ||||
							
								
								
									
										45
									
								
								src/libid3tag/latin1.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/libid3tag/latin1.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: latin1.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_LATIN1_H | ||||
| # define LIBID3TAG_LATIN1_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| id3_length_t id3_latin1_length(id3_latin1_t const *); | ||||
| id3_length_t id3_latin1_size(id3_latin1_t const *); | ||||
|  | ||||
| void id3_latin1_copy(id3_latin1_t *, id3_latin1_t const *); | ||||
| id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *); | ||||
|  | ||||
| id3_length_t id3_latin1_decodechar(id3_latin1_t const *, id3_ucs4_t *); | ||||
| id3_length_t id3_latin1_encodechar(id3_latin1_t *, id3_ucs4_t); | ||||
|  | ||||
| void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *); | ||||
| void id3_latin1_encode(id3_latin1_t *, id3_ucs4_t const *); | ||||
|  | ||||
| id3_length_t id3_latin1_put(id3_byte_t **, id3_latin1_t); | ||||
| id3_latin1_t id3_latin1_get(id3_byte_t const **); | ||||
|  | ||||
| id3_length_t id3_latin1_serialize(id3_byte_t **, id3_ucs4_t const *, int); | ||||
| id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **, id3_length_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										21
									
								
								src/libid3tag/libid3tag.list.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/libid3tag/libid3tag.list.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # @configure_input@ | ||||
|  | ||||
| # Directories... | ||||
| $prefix=@prefix@ | ||||
| $exec_prefix=@exec_prefix@ | ||||
| $srcdir=@srcdir@ | ||||
|  | ||||
| # Product information | ||||
| %product @PACKAGE@ | ||||
| %copyright GPL | ||||
| %vendor Underbit Technologies, Inc. <info@underbit.com> | ||||
| %license @srcdir@/COPYING | ||||
| %readme @srcdir@/README | ||||
| %description libid3tag is an ID3 tag manipulation library. | ||||
| %version @VERSION@ | ||||
| %packager Giuseppe "Cowo" Corbelli <cowo@lugbs.linux.it> | ||||
|  | ||||
| %system all | ||||
| f 0755 root root @libdir@/libid3tag.la .libs/libid3tag.lai | ||||
| f 0644 root root @libdir@/libid3tag.a .libs/libid3tag.a | ||||
| f 0644 root root @includedir@/id3tag.h @srcdir@/id3tag.h | ||||
							
								
								
									
										196
									
								
								src/libid3tag/parse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/libid3tag/parse.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,196 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: parse.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include <stdlib.h> | ||||
| # include <string.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "parse.h" | ||||
| # include "latin1.h" | ||||
| # include "utf16.h" | ||||
| # include "utf8.h" | ||||
|  | ||||
| signed long id3_parse_int(id3_byte_t const **ptr, unsigned int bytes) | ||||
| { | ||||
|   signed long value = 0; | ||||
|  | ||||
|   assert(bytes >= 1 && bytes <= 4); | ||||
|  | ||||
|   if (**ptr & 0x80) | ||||
|     value = ~0; | ||||
|  | ||||
|   switch (bytes) { | ||||
|   case 4: value = (value << 8) | *(*ptr)++; | ||||
|   case 3: value = (value << 8) | *(*ptr)++; | ||||
|   case 2: value = (value << 8) | *(*ptr)++; | ||||
|   case 1: value = (value << 8) | *(*ptr)++; | ||||
|   } | ||||
|  | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| unsigned long id3_parse_uint(id3_byte_t const **ptr, unsigned int bytes) | ||||
| { | ||||
|   unsigned long value = 0; | ||||
|  | ||||
|   assert(bytes >= 1 && bytes <= 4); | ||||
|  | ||||
|   switch (bytes) { | ||||
|   case 4: value = (value << 8) | *(*ptr)++; | ||||
|   case 3: value = (value << 8) | *(*ptr)++; | ||||
|   case 2: value = (value << 8) | *(*ptr)++; | ||||
|   case 1: value = (value << 8) | *(*ptr)++; | ||||
|   } | ||||
|  | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| unsigned long id3_parse_syncsafe(id3_byte_t const **ptr, unsigned int bytes) | ||||
| { | ||||
|   unsigned long value = 0; | ||||
|  | ||||
|   assert(bytes == 4 || bytes == 5); | ||||
|  | ||||
|   switch (bytes) { | ||||
|   case 5: value = (value << 4) | (*(*ptr)++ & 0x0f); | ||||
|   case 4: value = (value << 7) | (*(*ptr)++ & 0x7f); | ||||
|           value = (value << 7) | (*(*ptr)++ & 0x7f); | ||||
| 	  value = (value << 7) | (*(*ptr)++ & 0x7f); | ||||
| 	  value = (value << 7) | (*(*ptr)++ & 0x7f); | ||||
|   } | ||||
|  | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| void id3_parse_immediate(id3_byte_t const **ptr, unsigned int bytes, | ||||
| 			 char *value) | ||||
| { | ||||
|   assert(value); | ||||
|   assert(bytes == 8 || bytes == 4 || bytes == 3); | ||||
|  | ||||
|   switch (bytes) { | ||||
|   case 8: *value++ = *(*ptr)++; | ||||
|           *value++ = *(*ptr)++; | ||||
| 	  *value++ = *(*ptr)++; | ||||
| 	  *value++ = *(*ptr)++; | ||||
|   case 4: *value++ = *(*ptr)++; | ||||
|   case 3: *value++ = *(*ptr)++; | ||||
|           *value++ = *(*ptr)++; | ||||
| 	  *value++ = *(*ptr)++; | ||||
|   } | ||||
|  | ||||
|   *value = 0; | ||||
| } | ||||
|  | ||||
| id3_latin1_t *id3_parse_latin1(id3_byte_t const **ptr, id3_length_t length, | ||||
| 			       int full) | ||||
| { | ||||
|   id3_byte_t const *end; | ||||
|   int terminated = 0; | ||||
|   id3_latin1_t *latin1; | ||||
|  | ||||
|   end = memchr(*ptr, 0, length); | ||||
|   if (end == 0) | ||||
|     end = *ptr + length; | ||||
|   else { | ||||
|     length = end - *ptr; | ||||
|     terminated = 1; | ||||
|   } | ||||
|  | ||||
|   latin1 = malloc(length + 1); | ||||
|   if (latin1) { | ||||
|     memcpy(latin1, *ptr, length); | ||||
|     latin1[length] = 0; | ||||
|  | ||||
|     if (!full) { | ||||
|       id3_latin1_t *check; | ||||
|  | ||||
|       for (check = latin1; *check; ++check) { | ||||
| 	if (*check == '\n') | ||||
| 	  *check = ' '; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   *ptr += length + terminated; | ||||
|  | ||||
|   return latin1; | ||||
| } | ||||
|  | ||||
| id3_ucs4_t *id3_parse_string(id3_byte_t const **ptr, id3_length_t length, | ||||
| 			     enum id3_field_textencoding encoding, int full) | ||||
| { | ||||
|   id3_ucs4_t *ucs4 = 0; | ||||
|   enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY; | ||||
|  | ||||
|   switch (encoding) { | ||||
|   case ID3_FIELD_TEXTENCODING_ISO_8859_1: | ||||
|     ucs4 = id3_latin1_deserialize(ptr, length); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TEXTENCODING_UTF_16BE: | ||||
|     byteorder = ID3_UTF16_BYTEORDER_BE; | ||||
|   case ID3_FIELD_TEXTENCODING_UTF_16: | ||||
|     ucs4 = id3_utf16_deserialize(ptr, length, byteorder); | ||||
|     break; | ||||
|  | ||||
|   case ID3_FIELD_TEXTENCODING_UTF_8: | ||||
|     ucs4 = id3_utf8_deserialize(ptr, length); | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   if (ucs4 && !full) { | ||||
|     id3_ucs4_t *check; | ||||
|  | ||||
|     for (check = ucs4; *check; ++check) { | ||||
|       if (*check == '\n') | ||||
| 	*check = ' '; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return ucs4; | ||||
| } | ||||
|  | ||||
| id3_byte_t *id3_parse_binary(id3_byte_t const **ptr, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t *data; | ||||
|  | ||||
|   if (length == 0) | ||||
|     return malloc(1); | ||||
|  | ||||
|   data = malloc(length); | ||||
|   if (data) | ||||
|     memcpy(data, *ptr, length); | ||||
|  | ||||
|   *ptr += length; | ||||
|  | ||||
|   return data; | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/libid3tag/parse.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/libid3tag/parse.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: parse.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_PARSE_H | ||||
| # define LIBID3TAG_PARSE_H | ||||
|  | ||||
| signed long id3_parse_int(id3_byte_t const **, unsigned int); | ||||
| unsigned long id3_parse_uint(id3_byte_t const **, unsigned int); | ||||
| unsigned long id3_parse_syncsafe(id3_byte_t const **, unsigned int); | ||||
| void id3_parse_immediate(id3_byte_t const **, unsigned int, char *); | ||||
| id3_latin1_t *id3_parse_latin1(id3_byte_t const **, id3_length_t, int); | ||||
| id3_ucs4_t *id3_parse_string(id3_byte_t const **, id3_length_t, | ||||
| 			     enum id3_field_textencoding, int); | ||||
| id3_byte_t *id3_parse_binary(id3_byte_t const **, id3_length_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										200
									
								
								src/libid3tag/render.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								src/libid3tag/render.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: render.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <string.h> | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "render.h" | ||||
| # include "ucs4.h" | ||||
| # include "latin1.h" | ||||
| # include "utf16.h" | ||||
| # include "utf8.h" | ||||
|  | ||||
| id3_length_t id3_render_immediate(id3_byte_t **ptr, | ||||
| 				  char const *value, unsigned int bytes) | ||||
| { | ||||
|   assert(value); | ||||
|   assert(bytes == 8 || bytes == 4 || bytes == 3); | ||||
|  | ||||
|   if (ptr) { | ||||
|     switch (bytes) { | ||||
|     case 8: *(*ptr)++ = *value++; | ||||
|             *(*ptr)++ = *value++; | ||||
| 	    *(*ptr)++ = *value++; | ||||
| 	    *(*ptr)++ = *value++; | ||||
|     case 4: *(*ptr)++ = *value++; | ||||
|     case 3: *(*ptr)++ = *value++; | ||||
|             *(*ptr)++ = *value++; | ||||
| 	    *(*ptr)++ = *value++; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return bytes; | ||||
| } | ||||
|  | ||||
| id3_length_t id3_render_syncsafe(id3_byte_t **ptr, | ||||
| 				 unsigned long num, unsigned int bytes) | ||||
| { | ||||
|   assert(bytes == 4 || bytes == 5); | ||||
|  | ||||
|   if (ptr) { | ||||
|     switch (bytes) { | ||||
|     case 5: *(*ptr)++ = (num >> 28) & 0x0f; | ||||
|     case 4: *(*ptr)++ = (num >> 21) & 0x7f; | ||||
|             *(*ptr)++ = (num >> 14) & 0x7f; | ||||
| 	    *(*ptr)++ = (num >>  7) & 0x7f; | ||||
| 	    *(*ptr)++ = (num >>  0) & 0x7f; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return bytes; | ||||
| } | ||||
|  | ||||
| id3_length_t id3_render_int(id3_byte_t **ptr, | ||||
| 			    signed long num, unsigned int bytes) | ||||
| { | ||||
|   assert(bytes >= 1 && bytes <= 4); | ||||
|  | ||||
|   if (ptr) { | ||||
|     switch (bytes) { | ||||
|     case 4: *(*ptr)++ = num >> 24; | ||||
|     case 3: *(*ptr)++ = num >> 16; | ||||
|     case 2: *(*ptr)++ = num >>  8; | ||||
|     case 1: *(*ptr)++ = num >>  0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return bytes; | ||||
| } | ||||
|  | ||||
| id3_length_t id3_render_binary(id3_byte_t **ptr, | ||||
| 			       id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   if (data == 0) | ||||
|     return 0; | ||||
|  | ||||
|   if (ptr) { | ||||
|     memcpy(*ptr, data, length); | ||||
|     *ptr += length; | ||||
|   } | ||||
|  | ||||
|   return length; | ||||
| } | ||||
|  | ||||
| id3_length_t id3_render_latin1(id3_byte_t **ptr, | ||||
| 			       id3_latin1_t const *latin1, int terminate) | ||||
| { | ||||
|   id3_length_t size; | ||||
|  | ||||
|   if (latin1 == 0) | ||||
|     latin1 = ""; | ||||
|  | ||||
|   size = id3_latin1_size(latin1); | ||||
|   if (!terminate) | ||||
|     --size; | ||||
|  | ||||
|   if (ptr) { | ||||
|     memcpy(*ptr, latin1, size); | ||||
|     *ptr += size; | ||||
|   } | ||||
|  | ||||
|   return size; | ||||
| } | ||||
|  | ||||
| id3_length_t id3_render_string(id3_byte_t **ptr, id3_ucs4_t const *ucs4, | ||||
| 			       enum id3_field_textencoding encoding, | ||||
| 			       int terminate) | ||||
| { | ||||
|   enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY; | ||||
|  | ||||
|   if (ucs4 == 0) | ||||
|     ucs4 = id3_ucs4_empty; | ||||
|  | ||||
|   switch (encoding) { | ||||
|   case ID3_FIELD_TEXTENCODING_ISO_8859_1: | ||||
|     return id3_latin1_serialize(ptr, ucs4, terminate); | ||||
|  | ||||
|   case ID3_FIELD_TEXTENCODING_UTF_16BE: | ||||
|     byteorder = ID3_UTF16_BYTEORDER_BE; | ||||
|   case ID3_FIELD_TEXTENCODING_UTF_16: | ||||
|     return id3_utf16_serialize(ptr, ucs4, byteorder, terminate); | ||||
|  | ||||
|   case ID3_FIELD_TEXTENCODING_UTF_8: | ||||
|     return id3_utf8_serialize(ptr, ucs4, terminate); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| id3_length_t id3_render_padding(id3_byte_t **ptr, id3_byte_t value, | ||||
| 				id3_length_t length) | ||||
| { | ||||
|   if (ptr) { | ||||
|     memset(*ptr, value, length); | ||||
|     *ptr += length; | ||||
|   } | ||||
|  | ||||
|   return length; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	render->paddedstring() | ||||
|  * DESCRIPTION:	render a space-padded string using latin1 encoding | ||||
|  */ | ||||
| id3_length_t id3_render_paddedstring(id3_byte_t **ptr, id3_ucs4_t const *ucs4, | ||||
| 				     id3_length_t length) | ||||
| { | ||||
|   id3_ucs4_t padded[31], *data, *end; | ||||
|  | ||||
|   /* latin1 encoding only (this is used for ID3v1 fields) */ | ||||
|  | ||||
|   assert(length <= 30); | ||||
|  | ||||
|   data = padded; | ||||
|   end  = data + length; | ||||
|  | ||||
|   if (ucs4) { | ||||
|     while (*ucs4 && end - data > 0) { | ||||
|       *data++ = *ucs4++; | ||||
|  | ||||
|       if (data[-1] == '\n') | ||||
| 	data[-1] = ' '; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   while (end - data > 0) | ||||
|     *data++ = ' '; | ||||
|  | ||||
|   *data = 0; | ||||
|  | ||||
|   return id3_latin1_serialize(ptr, padded, 0); | ||||
| } | ||||
							
								
								
									
										40
									
								
								src/libid3tag/render.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/libid3tag/render.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: render.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_RENDER_H | ||||
| # define LIBID3TAG_RENDER_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| id3_length_t id3_render_immediate(id3_byte_t **, char const *, unsigned int); | ||||
| id3_length_t id3_render_syncsafe(id3_byte_t **, unsigned long, unsigned int); | ||||
| id3_length_t id3_render_int(id3_byte_t **, signed long, unsigned int); | ||||
| id3_length_t id3_render_binary(id3_byte_t **, | ||||
| 			       id3_byte_t const *, id3_length_t); | ||||
| id3_length_t id3_render_latin1(id3_byte_t **, id3_latin1_t const *, int); | ||||
| id3_length_t id3_render_string(id3_byte_t **, id3_ucs4_t const *, | ||||
| 			       enum id3_field_textencoding, int); | ||||
| id3_length_t id3_render_padding(id3_byte_t **, id3_byte_t, id3_length_t); | ||||
|  | ||||
| id3_length_t id3_render_paddedstring(id3_byte_t **, id3_ucs4_t const *, | ||||
| 				     id3_length_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										909
									
								
								src/libid3tag/tag.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										909
									
								
								src/libid3tag/tag.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,909 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: tag.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <string.h> | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # ifdef HAVE_ASSERT_H | ||||
| #  include <assert.h> | ||||
| # endif | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "tag.h" | ||||
| # include "frame.h" | ||||
| # include "compat.h" | ||||
| # include "parse.h" | ||||
| # include "render.h" | ||||
| # include "latin1.h" | ||||
| # include "ucs4.h" | ||||
| # include "genre.h" | ||||
| # include "crc.h" | ||||
| # include "field.h" | ||||
| # include "util.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->new() | ||||
|  * DESCRIPTION:	allocate and return a new, empty tag | ||||
|  */ | ||||
| struct id3_tag *id3_tag_new(void) | ||||
| { | ||||
|   struct id3_tag *tag; | ||||
|  | ||||
|   tag = malloc(sizeof(*tag)); | ||||
|   if (tag) { | ||||
|     tag->refcount      = 0; | ||||
|     tag->version       = ID3_TAG_VERSION; | ||||
|     tag->flags         = 0; | ||||
|     tag->extendedflags = 0; | ||||
|     tag->restrictions  = 0; | ||||
|     tag->options       = /* ID3_TAG_OPTION_UNSYNCHRONISATION | */ | ||||
|                          ID3_TAG_OPTION_COMPRESSION | ID3_TAG_OPTION_CRC; | ||||
|     tag->nframes       = 0; | ||||
|     tag->frames        = 0; | ||||
|     tag->paddedsize    = 0; | ||||
|   } | ||||
|  | ||||
|   return tag; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->delete() | ||||
|  * DESCRIPTION:	destroy a tag and deallocate all associated memory | ||||
|  */ | ||||
| void id3_tag_delete(struct id3_tag *tag) | ||||
| { | ||||
|   assert(tag); | ||||
|  | ||||
|   if (tag->refcount == 0) { | ||||
|     id3_tag_clearframes(tag); | ||||
|  | ||||
|     if (tag->frames) | ||||
|       free(tag->frames); | ||||
|  | ||||
|     free(tag); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->addref() | ||||
|  * DESCRIPTION:	add an external reference to a tag | ||||
|  */ | ||||
| void id3_tag_addref(struct id3_tag *tag) | ||||
| { | ||||
|   assert(tag); | ||||
|  | ||||
|   ++tag->refcount; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->delref() | ||||
|  * DESCRIPTION:	remove an external reference to a tag | ||||
|  */ | ||||
| void id3_tag_delref(struct id3_tag *tag) | ||||
| { | ||||
|   assert(tag && tag->refcount > 0); | ||||
|  | ||||
|   --tag->refcount; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->version() | ||||
|  * DESCRIPTION:	return the tag's original ID3 version number | ||||
|  */ | ||||
| unsigned int id3_tag_version(struct id3_tag const *tag) | ||||
| { | ||||
|   assert(tag); | ||||
|  | ||||
|   return tag->version; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->options() | ||||
|  * DESCRIPTION:	get or set tag options | ||||
|  */ | ||||
| int id3_tag_options(struct id3_tag *tag, int mask, int values) | ||||
| { | ||||
|   assert(tag); | ||||
|  | ||||
|   if (mask) | ||||
|     tag->options = (tag->options & ~mask) | (values & mask); | ||||
|  | ||||
|   return tag->options; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->setlength() | ||||
|  * DESCRIPTION:	set the minimum rendered tag size | ||||
|  */ | ||||
| void id3_tag_setlength(struct id3_tag *tag, id3_length_t length) | ||||
| { | ||||
|   assert(tag); | ||||
|  | ||||
|   tag->paddedsize = length; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->clearframes() | ||||
|  * DESCRIPTION:	detach and delete all frames associated with a tag | ||||
|  */ | ||||
| void id3_tag_clearframes(struct id3_tag *tag) | ||||
| { | ||||
|   unsigned int i; | ||||
|  | ||||
|   assert(tag); | ||||
|  | ||||
|   for (i = 0; i < tag->nframes; ++i) { | ||||
|     id3_frame_delref(tag->frames[i]); | ||||
|     id3_frame_delete(tag->frames[i]); | ||||
|   } | ||||
|  | ||||
|   tag->nframes = 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->attachframe() | ||||
|  * DESCRIPTION:	attach a frame to a tag | ||||
|  */ | ||||
| int id3_tag_attachframe(struct id3_tag *tag, struct id3_frame *frame) | ||||
| { | ||||
|   struct id3_frame **frames; | ||||
|  | ||||
|   assert(tag && frame); | ||||
|  | ||||
|   frames = realloc(tag->frames, (tag->nframes + 1) * sizeof(*frames)); | ||||
|   if (frames == 0) | ||||
|     return -1; | ||||
|  | ||||
|   tag->frames = frames; | ||||
|   tag->frames[tag->nframes++] = frame; | ||||
|  | ||||
|   id3_frame_addref(frame); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->detachframe() | ||||
|  * DESCRIPTION:	detach (but don't delete) a frame from a tag | ||||
|  */ | ||||
| int id3_tag_detachframe(struct id3_tag *tag, struct id3_frame *frame) | ||||
| { | ||||
|   unsigned int i; | ||||
|  | ||||
|   assert(tag && frame); | ||||
|  | ||||
|   for (i = 0; i < tag->nframes; ++i) { | ||||
|     if (tag->frames[i] == frame) | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   if (i == tag->nframes) | ||||
|     return -1; | ||||
|  | ||||
|   --tag->nframes; | ||||
|   while (i++ < tag->nframes) | ||||
|     tag->frames[i - 1] = tag->frames[i]; | ||||
|  | ||||
|   id3_frame_delref(frame); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->findframe() | ||||
|  * DESCRIPTION:	find in a tag the nth (0-based) frame with the given frame ID | ||||
|  */ | ||||
| struct id3_frame *id3_tag_findframe(struct id3_tag const *tag, | ||||
| 				    char const *id, unsigned int index) | ||||
| { | ||||
|   unsigned int len, i; | ||||
|  | ||||
|   assert(tag); | ||||
|  | ||||
|   if (id == 0 || *id == 0) | ||||
|     return (index < tag->nframes) ? tag->frames[index] : 0; | ||||
|  | ||||
|   len = strlen(id); | ||||
|  | ||||
|   if (len == 4) { | ||||
|     struct id3_compat const *compat; | ||||
|  | ||||
|     compat = id3_compat_lookup(id, len); | ||||
|     if (compat && compat->equiv && !compat->translate) { | ||||
|       id  = compat->equiv; | ||||
|       len = strlen(id); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (i = 0; i < tag->nframes; ++i) { | ||||
|     if (strncmp(tag->frames[i]->id, id, len) == 0 && index-- == 0) | ||||
|       return tag->frames[i]; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| enum tagtype { | ||||
|   TAGTYPE_NONE = 0, | ||||
|   TAGTYPE_ID3V1, | ||||
|   TAGTYPE_ID3V2, | ||||
|   TAGTYPE_ID3V2_FOOTER | ||||
| }; | ||||
|  | ||||
| static | ||||
| enum tagtype tagtype(id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   if (length >= 3 && | ||||
|       data[0] == 'T' && data[1] == 'A' && data[2] == 'G') | ||||
|     return TAGTYPE_ID3V1; | ||||
|  | ||||
|   if (length >= 10 && | ||||
|       ((data[0] == 'I' && data[1] == 'D' && data[2] == '3') || | ||||
|        (data[0] == '3' && data[1] == 'D' && data[2] == 'I')) && | ||||
|       data[3] < 0xff && data[4] < 0xff && | ||||
|       data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) | ||||
|     return data[0] == 'I' ? TAGTYPE_ID3V2 : TAGTYPE_ID3V2_FOOTER; | ||||
|  | ||||
|   return TAGTYPE_NONE; | ||||
| } | ||||
|  | ||||
| static | ||||
| void parse_header(id3_byte_t const **ptr, | ||||
| 		  unsigned int *version, int *flags, id3_length_t *size) | ||||
| { | ||||
|   *ptr += 3; | ||||
|  | ||||
|   *version = id3_parse_uint(ptr, 2); | ||||
|   *flags   = id3_parse_uint(ptr, 1); | ||||
|   *size    = id3_parse_syncsafe(ptr, 4); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->query() | ||||
|  * DESCRIPTION:	if a tag begins at the given location, return its size | ||||
|  */ | ||||
| signed long id3_tag_query(id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   unsigned int version; | ||||
|   int flags; | ||||
|   id3_length_t size; | ||||
|  | ||||
|   assert(data); | ||||
|  | ||||
|   switch (tagtype(data, length)) { | ||||
|   case TAGTYPE_ID3V1: | ||||
|     return 128; | ||||
|  | ||||
|   case TAGTYPE_ID3V2: | ||||
|     parse_header(&data, &version, &flags, &size); | ||||
|  | ||||
|     if (flags & ID3_TAG_FLAG_FOOTERPRESENT) | ||||
|       size += 10; | ||||
|  | ||||
|     return 10 + size; | ||||
|  | ||||
|   case TAGTYPE_ID3V2_FOOTER: | ||||
|     parse_header(&data, &version, &flags, &size); | ||||
|     return -size - 10; | ||||
|  | ||||
|   case TAGTYPE_NONE: | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| void trim(char *str) | ||||
| { | ||||
|   char *ptr; | ||||
|  | ||||
|   ptr = str + strlen(str); | ||||
|   while (ptr > str && ptr[-1] == ' ') | ||||
|     --ptr; | ||||
|  | ||||
|   *ptr = 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| int v1_attachstr(struct id3_tag *tag, char const *id, | ||||
| 		 char *text, unsigned long number) | ||||
| { | ||||
|   struct id3_frame *frame; | ||||
|   id3_ucs4_t ucs4[31]; | ||||
|  | ||||
|   if (text) { | ||||
|     trim(text); | ||||
|     if (*text == 0) | ||||
|       return 0; | ||||
|   } | ||||
|  | ||||
|   frame = id3_frame_new(id); | ||||
|   if (frame == 0) | ||||
|     return -1; | ||||
|  | ||||
|   if (id3_field_settextencoding(&frame->fields[0], | ||||
| 				ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   if (text) | ||||
|     id3_latin1_decode(text, ucs4); | ||||
|   else | ||||
|     id3_ucs4_putnumber(ucs4, number); | ||||
|  | ||||
|   if (strcmp(id, ID3_FRAME_COMMENT) == 0) { | ||||
|     if (id3_field_setlanguage(&frame->fields[1], "XXX") == -1 || | ||||
| 	id3_field_setstring(&frame->fields[2], id3_ucs4_empty) == -1 || | ||||
| 	id3_field_setfullstring(&frame->fields[3], ucs4) == -1) | ||||
|       goto fail; | ||||
|   } | ||||
|   else { | ||||
|     id3_ucs4_t *ptr = ucs4; | ||||
|  | ||||
|     if (id3_field_setstrings(&frame->fields[1], 1, &ptr) == -1) | ||||
|       goto fail; | ||||
|   } | ||||
|  | ||||
|   if (id3_tag_attachframe(tag, frame) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   return 0; | ||||
|  | ||||
|  fail: | ||||
|   id3_frame_delete(frame); | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| static | ||||
| struct id3_tag *v1_parse(id3_byte_t const *data) | ||||
| { | ||||
|   struct id3_tag *tag; | ||||
|  | ||||
|   tag = id3_tag_new(); | ||||
|   if (tag) { | ||||
|     char title[31], artist[31], album[31], year[5], comment[31]; | ||||
|     unsigned int genre, track; | ||||
|  | ||||
|     tag->version = 0x0100; | ||||
|  | ||||
|     tag->options |=  ID3_TAG_OPTION_ID3V1; | ||||
|     tag->options &= ~ID3_TAG_OPTION_COMPRESSION; | ||||
|  | ||||
|     tag->restrictions = | ||||
|       ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 | | ||||
|       ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS; | ||||
|  | ||||
|     title[30] = artist[30] = album[30] = year[4] = comment[30] = 0; | ||||
|  | ||||
|     memcpy(title,   &data[3],  30); | ||||
|     memcpy(artist,  &data[33], 30); | ||||
|     memcpy(album,   &data[63], 30); | ||||
|     memcpy(year,    &data[93],  4); | ||||
|     memcpy(comment, &data[97], 30); | ||||
|  | ||||
|     genre = data[127]; | ||||
|  | ||||
|     track = 0; | ||||
|     if (comment[28] == 0 && comment[29] != 0) { | ||||
|       track = comment[29]; | ||||
|       tag->version = 0x0101; | ||||
|     } | ||||
|  | ||||
|     /* populate tag frames */ | ||||
|  | ||||
|     if (v1_attachstr(tag, ID3_FRAME_TITLE,  title,  0) == -1 || | ||||
| 	v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 || | ||||
| 	v1_attachstr(tag, ID3_FRAME_ALBUM,  album,  0) == -1 || | ||||
| 	v1_attachstr(tag, ID3_FRAME_YEAR,   year,   0) == -1 || | ||||
| 	(track        && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) || | ||||
| 	(genre < 0xff && v1_attachstr(tag, ID3_FRAME_GENRE, 0, genre) == -1) || | ||||
| 	v1_attachstr(tag, ID3_FRAME_COMMENT, comment, 0) == -1) { | ||||
|       id3_tag_delete(tag); | ||||
|       tag = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return tag; | ||||
| } | ||||
|  | ||||
| static | ||||
| struct id3_tag *v2_parse(id3_byte_t const *ptr) | ||||
| { | ||||
|   struct id3_tag *tag; | ||||
|   id3_byte_t *mem = 0; | ||||
|  | ||||
|   tag = id3_tag_new(); | ||||
|   if (tag) { | ||||
|     id3_byte_t const *end; | ||||
|     id3_length_t size; | ||||
|  | ||||
|     parse_header(&ptr, &tag->version, &tag->flags, &size); | ||||
|  | ||||
|     tag->paddedsize = 10 + size; | ||||
|  | ||||
|     if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) && | ||||
| 	ID3_TAG_VERSION_MAJOR(tag->version) < 4) { | ||||
|       mem = malloc(size); | ||||
|       if (mem == 0) | ||||
| 	goto fail; | ||||
|  | ||||
|       memcpy(mem, ptr, size); | ||||
|  | ||||
|       size = id3_util_deunsynchronise(mem, size); | ||||
|       ptr  = mem; | ||||
|     } | ||||
|  | ||||
|     end = ptr + size; | ||||
|  | ||||
|     if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) { | ||||
|       switch (ID3_TAG_VERSION_MAJOR(tag->version)) { | ||||
|       case 2: | ||||
| 	goto fail; | ||||
|  | ||||
|       case 3: | ||||
| 	{ | ||||
| 	  id3_byte_t const *ehptr, *ehend; | ||||
| 	  id3_length_t ehsize; | ||||
|  | ||||
| 	  enum { | ||||
| 	    EH_FLAG_CRC = 0x8000  /* CRC data present */ | ||||
| 	  }; | ||||
|  | ||||
| 	  if (end - ptr < 4) | ||||
| 	    goto fail; | ||||
|  | ||||
| 	  ehsize = id3_parse_uint(&ptr, 4); | ||||
|  | ||||
| 	  if (ehsize > end - ptr) | ||||
| 	    goto fail; | ||||
|  | ||||
| 	  ehptr = ptr; | ||||
| 	  ehend = ptr + ehsize; | ||||
|  | ||||
| 	  ptr = ehend; | ||||
|  | ||||
| 	  if (ehend - ehptr >= 6) { | ||||
| 	    int ehflags; | ||||
| 	    id3_length_t padsize; | ||||
|  | ||||
| 	    ehflags = id3_parse_uint(&ehptr, 2); | ||||
| 	    padsize = id3_parse_uint(&ehptr, 4); | ||||
|  | ||||
| 	    if (padsize > end - ptr) | ||||
| 	      goto fail; | ||||
|  | ||||
| 	    end -= padsize; | ||||
|  | ||||
| 	    if (ehflags & EH_FLAG_CRC) { | ||||
| 	      unsigned long crc; | ||||
|  | ||||
| 	      if (ehend - ehptr < 4) | ||||
| 		goto fail; | ||||
|  | ||||
| 	      crc = id3_parse_uint(&ehptr, 4); | ||||
|  | ||||
| 	      if (crc != id3_crc_calculate(ptr, end - ptr)) | ||||
| 		goto fail; | ||||
|  | ||||
| 	      tag->extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; | ||||
| 	    } | ||||
| 	  } | ||||
| 	} | ||||
| 	break; | ||||
|  | ||||
|       case 4: | ||||
| 	{ | ||||
| 	  id3_byte_t const *ehptr, *ehend; | ||||
| 	  id3_length_t ehsize; | ||||
| 	  unsigned int bytes; | ||||
|  | ||||
| 	  if (end - ptr < 4) | ||||
| 	    goto fail; | ||||
|  | ||||
| 	  ehptr  = ptr; | ||||
| 	  ehsize = id3_parse_syncsafe(&ptr, 4); | ||||
|  | ||||
| 	  if (ehsize < 6 || ehsize > end - ehptr) | ||||
| 	    goto fail; | ||||
|  | ||||
| 	  ehend = ehptr + ehsize; | ||||
|  | ||||
| 	  bytes = id3_parse_uint(&ptr, 1); | ||||
|  | ||||
| 	  if (bytes < 1 || bytes > ehend - ptr) | ||||
| 	    goto fail; | ||||
|  | ||||
| 	  ehptr = ptr + bytes; | ||||
|  | ||||
| 	  /* verify extended header size */ | ||||
| 	  { | ||||
| 	    id3_byte_t const *flagsptr = ptr, *dataptr = ehptr; | ||||
| 	    unsigned int datalen; | ||||
| 	    int ehflags; | ||||
|  | ||||
| 	    while (bytes--) { | ||||
| 	      for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags; | ||||
| 		   ehflags = (ehflags << 1) & 0xff) { | ||||
| 		if (ehflags & 0x80) { | ||||
| 		  if (dataptr == ehend) | ||||
| 		    goto fail; | ||||
| 		  datalen = id3_parse_uint(&dataptr, 1); | ||||
| 		  if (datalen > 0x7f || datalen > ehend - dataptr) | ||||
| 		    goto fail; | ||||
| 		  dataptr += datalen; | ||||
| 		} | ||||
| 	      } | ||||
| 	    } | ||||
| 	  } | ||||
|  | ||||
| 	  tag->extendedflags = id3_parse_uint(&ptr, 1); | ||||
|  | ||||
| 	  ptr = ehend; | ||||
|  | ||||
| 	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) { | ||||
| 	    bytes  = id3_parse_uint(&ehptr, 1); | ||||
| 	    ehptr += bytes; | ||||
| 	  } | ||||
|  | ||||
| 	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { | ||||
| 	    unsigned long crc; | ||||
|  | ||||
| 	    bytes = id3_parse_uint(&ehptr, 1); | ||||
| 	    if (bytes < 5) | ||||
| 	      goto fail; | ||||
|  | ||||
| 	    crc = id3_parse_syncsafe(&ehptr, 5); | ||||
| 	    ehptr += bytes - 5; | ||||
|  | ||||
| 	    if (crc != id3_crc_calculate(ptr, end - ptr)) | ||||
| 	      goto fail; | ||||
| 	  } | ||||
|  | ||||
| 	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { | ||||
| 	    bytes = id3_parse_uint(&ehptr, 1); | ||||
| 	    if (bytes < 1) | ||||
| 	      goto fail; | ||||
|  | ||||
| 	    tag->restrictions = id3_parse_uint(&ehptr, 1); | ||||
| 	    ehptr += bytes - 1; | ||||
| 	  } | ||||
| 	} | ||||
| 	break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /* frames */ | ||||
|  | ||||
|     while (ptr < end) { | ||||
|       struct id3_frame *frame; | ||||
|  | ||||
|       if (*ptr == 0) | ||||
| 	break;  /* padding */ | ||||
|  | ||||
|       frame = id3_frame_parse(&ptr, end - ptr, tag->version); | ||||
|       if (frame == 0 || id3_tag_attachframe(tag, frame) == -1) | ||||
| 	goto fail; | ||||
|     } | ||||
|  | ||||
|     if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 && | ||||
| 	id3_compat_fixup(tag) == -1) | ||||
|       goto fail; | ||||
|   } | ||||
|  | ||||
|   if (0) { | ||||
|   fail: | ||||
|     id3_tag_delete(tag); | ||||
|     tag = 0; | ||||
|   } | ||||
|  | ||||
|   if (mem) | ||||
|     free(mem); | ||||
|  | ||||
|   return tag; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->parse() | ||||
|  * DESCRIPTION:	parse a complete ID3 tag | ||||
|  */ | ||||
| struct id3_tag *id3_tag_parse(id3_byte_t const *data, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t const *ptr; | ||||
|   unsigned int version; | ||||
|   int flags; | ||||
|   id3_length_t size; | ||||
|  | ||||
|   assert(data); | ||||
|  | ||||
|   switch (tagtype(data, length)) { | ||||
|   case TAGTYPE_ID3V1: | ||||
|     return (length < 128) ? 0 : v1_parse(data); | ||||
|  | ||||
|   case TAGTYPE_ID3V2: | ||||
|     break; | ||||
|  | ||||
|   case TAGTYPE_ID3V2_FOOTER: | ||||
|   case TAGTYPE_NONE: | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   /* ID3v2.x */ | ||||
|  | ||||
|   ptr = data; | ||||
|   parse_header(&ptr, &version, &flags, &size); | ||||
|  | ||||
|   switch (ID3_TAG_VERSION_MAJOR(version)) { | ||||
|   case 4: | ||||
|     if (flags & ID3_TAG_FLAG_FOOTERPRESENT) | ||||
|       size += 10; | ||||
|   case 2: | ||||
|   case 3: | ||||
|     return (length < 10 + size) ? 0 : v2_parse(data); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| void v1_renderstr(struct id3_tag const *tag, char const *frameid, | ||||
| 		  id3_byte_t **buffer, id3_length_t length) | ||||
| { | ||||
|   struct id3_frame *frame; | ||||
|   id3_ucs4_t const *string; | ||||
|  | ||||
|   frame = id3_tag_findframe(tag, frameid, 0); | ||||
|   if (frame == 0) | ||||
|     string = id3_ucs4_empty; | ||||
|   else { | ||||
|     if (strcmp(frameid, ID3_FRAME_COMMENT) == 0) | ||||
|       string = id3_field_getfullstring(&frame->fields[3]); | ||||
|     else | ||||
|       string = id3_field_getstrings(&frame->fields[1], 0); | ||||
|   } | ||||
|  | ||||
|   id3_render_paddedstring(buffer, string, length); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	v1->render() | ||||
|  * DESCRIPTION:	render an ID3v1 (or ID3v1.1) tag | ||||
|  */ | ||||
| static | ||||
| id3_length_t v1_render(struct id3_tag const *tag, id3_byte_t *buffer) | ||||
| { | ||||
|   id3_byte_t data[128], *ptr; | ||||
|   struct id3_frame *frame; | ||||
|   unsigned int i; | ||||
|   int genre = -1; | ||||
|  | ||||
|   ptr = data; | ||||
|  | ||||
|   id3_render_immediate(&ptr, "TAG", 3); | ||||
|  | ||||
|   v1_renderstr(tag, ID3_FRAME_TITLE,   &ptr, 30); | ||||
|   v1_renderstr(tag, ID3_FRAME_ARTIST,  &ptr, 30); | ||||
|   v1_renderstr(tag, ID3_FRAME_ALBUM,   &ptr, 30); | ||||
|   v1_renderstr(tag, ID3_FRAME_YEAR,    &ptr,  4); | ||||
|   v1_renderstr(tag, ID3_FRAME_COMMENT, &ptr, 30); | ||||
|  | ||||
|   /* ID3v1.1 track number */ | ||||
|  | ||||
|   frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0); | ||||
|   if (frame) { | ||||
|     unsigned int track; | ||||
|  | ||||
|     track = id3_ucs4_getnumber(id3_field_getstrings(&frame->fields[1], 0)); | ||||
|     if (track > 0 && track <= 0xff) { | ||||
|       ptr[-2] = 0; | ||||
|       ptr[-1] = track; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* ID3v1 genre number */ | ||||
|  | ||||
|   frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0); | ||||
|   if (frame) { | ||||
|     unsigned int nstrings; | ||||
|  | ||||
|     nstrings = id3_field_getnstrings(&frame->fields[1]); | ||||
|  | ||||
|     for (i = 0; i < nstrings; ++i) { | ||||
|       genre = id3_genre_number(id3_field_getstrings(&frame->fields[1], i)); | ||||
|       if (genre != -1) | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     if (i == nstrings && nstrings > 0) | ||||
|       genre = ID3_GENRE_OTHER; | ||||
|   } | ||||
|  | ||||
|   id3_render_int(&ptr, genre, 1); | ||||
|  | ||||
|   /* make sure the tag is not empty */ | ||||
|  | ||||
|   if (genre == -1) { | ||||
|     for (i = 3; i < 127; ++i) { | ||||
|       if (data[i] != ' ') | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     if (i == 127) | ||||
|       return 0; | ||||
|   } | ||||
|  | ||||
|   if (buffer) | ||||
|     memcpy(buffer, data, 128); | ||||
|  | ||||
|   return 128; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	tag->render() | ||||
|  * DESCRIPTION:	render a complete ID3 tag | ||||
|  */ | ||||
| id3_length_t id3_tag_render(struct id3_tag const *tag, id3_byte_t *buffer) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|   id3_byte_t **ptr, | ||||
|     *header_ptr = 0, *tagsize_ptr = 0, *crc_ptr = 0, *frames_ptr = 0; | ||||
|   int flags, extendedflags; | ||||
|   unsigned int i; | ||||
|  | ||||
|   assert(tag); | ||||
|  | ||||
|   if (tag->options & ID3_TAG_OPTION_ID3V1) | ||||
|     return v1_render(tag, buffer); | ||||
|  | ||||
|   /* a tag must contain at least one (renderable) frame */ | ||||
|  | ||||
|   for (i = 0; i < tag->nframes; ++i) { | ||||
|     if (id3_frame_render(tag->frames[i], 0, 0) > 0) | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   if (i == tag->nframes) | ||||
|     return 0; | ||||
|  | ||||
|   ptr = buffer ? &buffer : 0; | ||||
|  | ||||
|   /* get flags */ | ||||
|  | ||||
|   flags         = tag->flags         & ID3_TAG_FLAG_KNOWNFLAGS; | ||||
|   extendedflags = tag->extendedflags & ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS; | ||||
|  | ||||
|   extendedflags &= ~ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; | ||||
|   if (tag->options & ID3_TAG_OPTION_CRC) | ||||
|     extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; | ||||
|  | ||||
|   extendedflags &= ~ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS; | ||||
|   if (tag->restrictions) | ||||
|     extendedflags |= ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS; | ||||
|  | ||||
|   flags &= ~ID3_TAG_FLAG_UNSYNCHRONISATION; | ||||
|   if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) | ||||
|     flags |= ID3_TAG_FLAG_UNSYNCHRONISATION; | ||||
|  | ||||
|   flags &= ~ID3_TAG_FLAG_EXTENDEDHEADER; | ||||
|   if (extendedflags) | ||||
|     flags |= ID3_TAG_FLAG_EXTENDEDHEADER; | ||||
|  | ||||
|   flags &= ~ID3_TAG_FLAG_FOOTERPRESENT; | ||||
|   if (tag->options & ID3_TAG_OPTION_APPENDEDTAG) | ||||
|     flags |= ID3_TAG_FLAG_FOOTERPRESENT; | ||||
|  | ||||
|   /* header */ | ||||
|  | ||||
|   if (ptr) | ||||
|     header_ptr = *ptr; | ||||
|  | ||||
|   size += id3_render_immediate(ptr, "ID3", 3); | ||||
|   size += id3_render_int(ptr, ID3_TAG_VERSION, 2); | ||||
|   size += id3_render_int(ptr, flags, 1); | ||||
|  | ||||
|   if (ptr) | ||||
|     tagsize_ptr = *ptr; | ||||
|  | ||||
|   size += id3_render_syncsafe(ptr, 0, 4); | ||||
|  | ||||
|   /* extended header */ | ||||
|  | ||||
|   if (flags & ID3_TAG_FLAG_EXTENDEDHEADER) { | ||||
|     id3_length_t ehsize = 0; | ||||
|     id3_byte_t *ehsize_ptr = 0; | ||||
|  | ||||
|     if (ptr) | ||||
|       ehsize_ptr = *ptr; | ||||
|  | ||||
|     ehsize += id3_render_syncsafe(ptr, 0, 4); | ||||
|     ehsize += id3_render_int(ptr, 1, 1); | ||||
|     ehsize += id3_render_int(ptr, extendedflags, 1); | ||||
|  | ||||
|     if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) | ||||
|       ehsize += id3_render_int(ptr, 0, 1); | ||||
|  | ||||
|     if (extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { | ||||
|       ehsize += id3_render_int(ptr, 5, 1); | ||||
|  | ||||
|       if (ptr) | ||||
| 	crc_ptr = *ptr; | ||||
|  | ||||
|       ehsize += id3_render_syncsafe(ptr, 0, 5); | ||||
|     } | ||||
|  | ||||
|     if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { | ||||
|       ehsize += id3_render_int(ptr, 1, 1); | ||||
|       ehsize += id3_render_int(ptr, tag->restrictions, 1); | ||||
|     } | ||||
|  | ||||
|     if (ehsize_ptr) | ||||
|       id3_render_syncsafe(&ehsize_ptr, ehsize, 4); | ||||
|  | ||||
|     size += ehsize; | ||||
|   } | ||||
|  | ||||
|   /* frames */ | ||||
|  | ||||
|   if (ptr) | ||||
|     frames_ptr = *ptr; | ||||
|  | ||||
|   for (i = 0; i < tag->nframes; ++i) | ||||
|     size += id3_frame_render(tag->frames[i], ptr, tag->options); | ||||
|  | ||||
|   /* padding */ | ||||
|  | ||||
|   if (!(flags & ID3_TAG_FLAG_FOOTERPRESENT)) { | ||||
|     if (size < tag->paddedsize) | ||||
|       size += id3_render_padding(ptr, 0, tag->paddedsize - size); | ||||
|     else if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) { | ||||
|       if (ptr == 0) | ||||
| 	size += 1; | ||||
|       else { | ||||
| 	if ((*ptr)[-1] == 0xff) | ||||
| 	  size += id3_render_padding(ptr, 0, 1); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* patch tag size and CRC */ | ||||
|  | ||||
|   if (tagsize_ptr) | ||||
|     id3_render_syncsafe(&tagsize_ptr, size - 10, 4); | ||||
|  | ||||
|   if (crc_ptr) { | ||||
|     id3_render_syncsafe(&crc_ptr, | ||||
| 			id3_crc_calculate(frames_ptr, *ptr - frames_ptr), 5); | ||||
|   } | ||||
|  | ||||
|   /* footer */ | ||||
|  | ||||
|   if (flags & ID3_TAG_FLAG_FOOTERPRESENT) { | ||||
|     size += id3_render_immediate(ptr, "3DI", 3); | ||||
|     size += id3_render_binary(ptr, header_ptr + 3, 7); | ||||
|   } | ||||
|  | ||||
|   return size; | ||||
| } | ||||
							
								
								
									
										30
									
								
								src/libid3tag/tag.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/libid3tag/tag.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: tag.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_TAG_H | ||||
| # define LIBID3TAG_TAG_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| void id3_tag_addref(struct id3_tag *); | ||||
| void id3_tag_delref(struct id3_tag *); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										224
									
								
								src/libid3tag/ucs4.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/libid3tag/ucs4.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,224 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: ucs4.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "ucs4.h" | ||||
| # include "latin1.h" | ||||
| # include "utf16.h" | ||||
| # include "utf8.h" | ||||
|  | ||||
| id3_ucs4_t const id3_ucs4_empty[] = { 0 }; | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->length() | ||||
|  * DESCRIPTION:	return the number of ucs4 chars represented by a ucs4 string | ||||
|  */ | ||||
| id3_length_t id3_ucs4_length(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   id3_ucs4_t const *ptr = ucs4; | ||||
|  | ||||
|   while (*ptr) | ||||
|     ++ptr; | ||||
|  | ||||
|   return ptr - ucs4; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->size() | ||||
|  * DESCRIPTION:	return the encoding size of a ucs4 string | ||||
|  */ | ||||
| id3_length_t id3_ucs4_size(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   return id3_ucs4_length(ucs4) + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->latin1size() | ||||
|  * DESCRIPTION:	return the encoding size of a latin1-encoded ucs4 string | ||||
|  */ | ||||
| id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   return id3_ucs4_size(ucs4); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->utf16size() | ||||
|  * DESCRIPTION:	return the encoding size of a utf16-encoded ucs4 string | ||||
|  */ | ||||
| id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|  | ||||
|   while (*ucs4) { | ||||
|     ++size; | ||||
|     if (*ucs4 >= 0x00010000L && | ||||
| 	*ucs4 <= 0x0010ffffL) | ||||
|       ++size; | ||||
|  | ||||
|     ++ucs4; | ||||
|   } | ||||
|  | ||||
|   return size + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->utf8size() | ||||
|  * DESCRIPTION:	return the encoding size of a utf8-encoded ucs4 string | ||||
|  */ | ||||
| id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|  | ||||
|   while (*ucs4) { | ||||
|     if (*ucs4 <= 0x0000007fL) | ||||
|       size += 1; | ||||
|     else if (*ucs4 <= 0x000007ffL) | ||||
|       size += 2; | ||||
|     else if (*ucs4 <= 0x0000ffffL) | ||||
|       size += 3; | ||||
|     else if (*ucs4 <= 0x001fffffL) | ||||
|       size += 4; | ||||
|     else if (*ucs4 <= 0x03ffffffL) | ||||
|       size += 5; | ||||
|     else if (*ucs4 <= 0x7fffffffL) | ||||
|       size += 6; | ||||
|     else | ||||
|       size += 2;  /* based on U+00B7 replacement char */ | ||||
|  | ||||
|     ++ucs4; | ||||
|   } | ||||
|  | ||||
|   return size + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->latin1duplicate() | ||||
|  * DESCRIPTION:	duplicate and encode a ucs4 string into latin1 | ||||
|  */ | ||||
| id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   id3_latin1_t *latin1; | ||||
|  | ||||
|   latin1 = malloc(id3_ucs4_latin1size(ucs4) * sizeof(*latin1)); | ||||
|   if (latin1) | ||||
|     id3_latin1_encode(latin1, ucs4); | ||||
|  | ||||
|   return release(latin1); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->utf16duplicate() | ||||
|  * DESCRIPTION:	duplicate and encode a ucs4 string into utf16 | ||||
|  */ | ||||
| id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   id3_utf16_t *utf16; | ||||
|  | ||||
|   utf16 = malloc(id3_ucs4_utf16size(ucs4) * sizeof(*utf16)); | ||||
|   if (utf16) | ||||
|     id3_utf16_encode(utf16, ucs4); | ||||
|  | ||||
|   return release(utf16); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->utf8duplicate() | ||||
|  * DESCRIPTION:	duplicate and encode a ucs4 string into utf8 | ||||
|  */ | ||||
| id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   id3_utf8_t *utf8; | ||||
|  | ||||
|   utf8 = malloc(id3_ucs4_utf8size(ucs4) * sizeof(*utf8)); | ||||
|   if (utf8) | ||||
|     id3_utf8_encode(utf8, ucs4); | ||||
|  | ||||
|   return release(utf8); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->copy() | ||||
|  * DESCRIPTION:	copy a ucs4 string | ||||
|  */ | ||||
| void id3_ucs4_copy(id3_ucs4_t *dest, id3_ucs4_t const *src) | ||||
| { | ||||
|   while ((*dest++ = *src++)) | ||||
|     ; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->duplicate() | ||||
|  * DESCRIPTION:	duplicate a ucs4 string | ||||
|  */ | ||||
| id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *src) | ||||
| { | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   ucs4 = malloc(id3_ucs4_size(src) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_ucs4_copy(ucs4, src); | ||||
|  | ||||
|   return ucs4; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->putnumber() | ||||
|  * DESCRIPTION:	write a ucs4 string containing a (positive) decimal number | ||||
|  */ | ||||
| void id3_ucs4_putnumber(id3_ucs4_t *ucs4, unsigned long number) | ||||
| { | ||||
|   int digits[10], *digit; | ||||
|  | ||||
|   digit = digits; | ||||
|  | ||||
|   do { | ||||
|     *digit++ = number % 10; | ||||
|     number  /= 10; | ||||
|   } | ||||
|   while (number); | ||||
|  | ||||
|   while (digit != digits) | ||||
|     *ucs4++ = '0' + *--digit; | ||||
|  | ||||
|   *ucs4 = 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	ucs4->getnumber() | ||||
|  * DESCRIPTION:	read a ucs4 string containing a (positive) decimal number | ||||
|  */ | ||||
| unsigned long id3_ucs4_getnumber(id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   unsigned long number = 0; | ||||
|  | ||||
|   while (*ucs4 >= '0' && *ucs4 <= '9') | ||||
|     number = 10 * number + (*ucs4++ - '0'); | ||||
|  | ||||
|   return number; | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/libid3tag/ucs4.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/libid3tag/ucs4.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: ucs4.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_UCS4_H | ||||
| # define LIBID3TAG_UCS4_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| # define ID3_UCS4_REPLACEMENTCHAR  0x000000b7L  /* middle dot */ | ||||
|  | ||||
| extern id3_ucs4_t const id3_ucs4_empty[]; | ||||
|  | ||||
| id3_length_t id3_ucs4_length(id3_ucs4_t const *); | ||||
| id3_length_t id3_ucs4_size(id3_ucs4_t const *); | ||||
|  | ||||
| id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *); | ||||
| id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *); | ||||
| id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *); | ||||
|  | ||||
| void id3_ucs4_copy(id3_ucs4_t *, id3_ucs4_t const *); | ||||
| id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										286
									
								
								src/libid3tag/utf16.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								src/libid3tag/utf16.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,286 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: utf16.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "utf16.h" | ||||
| # include "ucs4.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->length() | ||||
|  * DESCRIPTION:	return the number of ucs4 chars represented by a utf16 string | ||||
|  */ | ||||
| id3_length_t id3_utf16_length(id3_utf16_t const *utf16) | ||||
| { | ||||
|   id3_length_t length = 0; | ||||
|  | ||||
|   while (*utf16) { | ||||
|     if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) | ||||
|       ++length; | ||||
|     else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff && | ||||
| 	     utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) { | ||||
|       ++length; | ||||
|       ++utf16; | ||||
|     } | ||||
|  | ||||
|     ++utf16; | ||||
|   } | ||||
|  | ||||
|   return length; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->size() | ||||
|  * DESCRIPTION:	return the encoding size of a utf16 string | ||||
|  */ | ||||
| id3_length_t id3_utf16_size(id3_utf16_t const *utf16) | ||||
| { | ||||
|   id3_utf16_t const *ptr = utf16; | ||||
|  | ||||
|   while (*ptr) | ||||
|     ++ptr; | ||||
|  | ||||
|   return ptr - utf16 + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->ucs4duplicate() | ||||
|  * DESCRIPTION:	duplicate and decode a utf16 string into ucs4 | ||||
|  */ | ||||
| id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *utf16) | ||||
| { | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_utf16_decode(utf16, ucs4); | ||||
|  | ||||
|   return release(ucs4); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->decodechar() | ||||
|  * DESCRIPTION:	decode a series of utf16 chars into a single ucs4 char | ||||
|  */ | ||||
| id3_length_t id3_utf16_decodechar(id3_utf16_t const *utf16, id3_ucs4_t *ucs4) | ||||
| { | ||||
|   id3_utf16_t const *start = utf16; | ||||
|  | ||||
|   while (1) { | ||||
|     if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) { | ||||
|       *ucs4 = utf16[0]; | ||||
|       return utf16 - start + 1; | ||||
|     } | ||||
|     else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff && | ||||
| 	     utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) { | ||||
|       *ucs4 = (((utf16[0] & 0x03ffL) << 10) | | ||||
| 	       ((utf16[1] & 0x03ffL) <<  0)) + 0x00010000L; | ||||
|       return utf16 - start + 2; | ||||
|     } | ||||
|  | ||||
|     ++utf16; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->encodechar() | ||||
|  * DESCRIPTION:	encode a single ucs4 char into a series of up to 2 utf16 chars | ||||
|  */ | ||||
| id3_length_t id3_utf16_encodechar(id3_utf16_t *utf16, id3_ucs4_t ucs4) | ||||
| { | ||||
|   if (ucs4 < 0x00010000L) { | ||||
|     utf16[0] = ucs4; | ||||
|  | ||||
|     return 1; | ||||
|   } | ||||
|   else if (ucs4 < 0x00110000L) { | ||||
|     ucs4 -= 0x00010000L; | ||||
|  | ||||
|     utf16[0] = ((ucs4 >> 10) & 0x3ff) | 0xd800; | ||||
|     utf16[1] = ((ucs4 >>  0) & 0x3ff) | 0xdc00; | ||||
|  | ||||
|     return 2; | ||||
|   } | ||||
|  | ||||
|   /* default */ | ||||
|  | ||||
|   return id3_utf16_encodechar(utf16, ID3_UCS4_REPLACEMENTCHAR); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->decode() | ||||
|  * DESCRIPTION:	decode a complete utf16 string into a ucs4 string | ||||
|  */ | ||||
| void id3_utf16_decode(id3_utf16_t const *utf16, id3_ucs4_t *ucs4) | ||||
| { | ||||
|   do | ||||
|     utf16 += id3_utf16_decodechar(utf16, ucs4); | ||||
|   while (*ucs4++); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->encode() | ||||
|  * DESCRIPTION:	encode a complete ucs4 string into a utf16 string | ||||
|  */ | ||||
| void id3_utf16_encode(id3_utf16_t *utf16, id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   do | ||||
|     utf16 += id3_utf16_encodechar(utf16, *ucs4); | ||||
|   while (*ucs4++); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->put() | ||||
|  * DESCRIPTION:	serialize a single utf16 character | ||||
|  */ | ||||
| id3_length_t id3_utf16_put(id3_byte_t **ptr, id3_utf16_t utf16, | ||||
| 			   enum id3_utf16_byteorder byteorder) | ||||
| { | ||||
|   if (ptr) { | ||||
|     switch (byteorder) { | ||||
|     default: | ||||
|     case ID3_UTF16_BYTEORDER_BE: | ||||
|       (*ptr)[0] = (utf16 >> 8) & 0xff; | ||||
|       (*ptr)[1] = (utf16 >> 0) & 0xff; | ||||
|       break; | ||||
|  | ||||
|     case ID3_UTF16_BYTEORDER_LE: | ||||
|       (*ptr)[0] = (utf16 >> 0) & 0xff; | ||||
|       (*ptr)[1] = (utf16 >> 8) & 0xff; | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     *ptr += 2; | ||||
|   } | ||||
|  | ||||
|   return 2; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->get() | ||||
|  * DESCRIPTION:	deserialize a single utf16 character | ||||
|  */ | ||||
| id3_utf16_t id3_utf16_get(id3_byte_t const **ptr, | ||||
| 			  enum id3_utf16_byteorder byteorder) | ||||
| { | ||||
|   id3_utf16_t utf16; | ||||
|  | ||||
|   switch (byteorder) { | ||||
|   default: | ||||
|   case ID3_UTF16_BYTEORDER_BE: | ||||
|     utf16 = | ||||
|       ((*ptr)[0] << 8) | | ||||
|       ((*ptr)[1] << 0); | ||||
|     break; | ||||
|  | ||||
|   case ID3_UTF16_BYTEORDER_LE: | ||||
|     utf16 = | ||||
|       ((*ptr)[0] << 0) | | ||||
|       ((*ptr)[1] << 8); | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   *ptr += 2; | ||||
|  | ||||
|   return utf16; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->serialize() | ||||
|  * DESCRIPTION:	serialize a ucs4 string using utf16 encoding | ||||
|  */ | ||||
| id3_length_t id3_utf16_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, | ||||
| 				 enum id3_utf16_byteorder byteorder, | ||||
| 				 int terminate) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|   id3_utf16_t utf16[2], *out; | ||||
|  | ||||
|   if (byteorder == ID3_UTF16_BYTEORDER_ANY) | ||||
|     size += id3_utf16_put(ptr, 0xfeff, byteorder); | ||||
|  | ||||
|   while (*ucs4) { | ||||
|     switch (id3_utf16_encodechar(out = utf16, *ucs4++)) { | ||||
|     case 2: size += id3_utf16_put(ptr, *out++, byteorder); | ||||
|     case 1: size += id3_utf16_put(ptr, *out++, byteorder); | ||||
|     case 0: break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (terminate) | ||||
|     size += id3_utf16_put(ptr, 0, byteorder); | ||||
|  | ||||
|   return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf16->deserialize() | ||||
|  * DESCRIPTION:	deserialize a ucs4 string using utf16 encoding | ||||
|  */ | ||||
| id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **ptr, id3_length_t length, | ||||
| 				  enum id3_utf16_byteorder byteorder) | ||||
| { | ||||
|   id3_byte_t const *end; | ||||
|   id3_utf16_t *utf16ptr, *utf16; | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   end = *ptr + (length & ~1); | ||||
|  | ||||
|   utf16 = malloc((length / 2 + 1) * sizeof(*utf16)); | ||||
|   if (utf16 == 0) | ||||
|     return 0; | ||||
|  | ||||
|   if (byteorder == ID3_UTF16_BYTEORDER_ANY && end - *ptr > 0) { | ||||
|     switch (((*ptr)[0] << 8) | | ||||
| 	    ((*ptr)[1] << 0)) { | ||||
|     case 0xfeff: | ||||
|       byteorder = ID3_UTF16_BYTEORDER_BE; | ||||
|       *ptr += 2; | ||||
|       break; | ||||
|  | ||||
|     case 0xfffe: | ||||
|       byteorder = ID3_UTF16_BYTEORDER_LE; | ||||
|       *ptr += 2; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   utf16ptr = utf16; | ||||
|   while (end - *ptr > 0 && (*utf16ptr = id3_utf16_get(ptr, byteorder))) | ||||
|     ++utf16ptr; | ||||
|  | ||||
|   *utf16ptr = 0; | ||||
|  | ||||
|   ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_utf16_decode(utf16, ucs4); | ||||
|  | ||||
|   free(utf16); | ||||
|  | ||||
|   return ucs4; | ||||
| } | ||||
							
								
								
									
										51
									
								
								src/libid3tag/utf16.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/libid3tag/utf16.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: utf16.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_UTF16_H | ||||
| # define LIBID3TAG_UTF16_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| enum id3_utf16_byteorder { | ||||
|   ID3_UTF16_BYTEORDER_ANY, | ||||
|   ID3_UTF16_BYTEORDER_BE, | ||||
|   ID3_UTF16_BYTEORDER_LE | ||||
| }; | ||||
|  | ||||
| id3_length_t id3_utf16_length(id3_utf16_t const *); | ||||
| id3_length_t id3_utf16_size(id3_utf16_t const *); | ||||
|  | ||||
| id3_length_t id3_utf16_decodechar(id3_utf16_t const *, id3_ucs4_t *); | ||||
| id3_length_t id3_utf16_encodechar(id3_utf16_t *, id3_ucs4_t); | ||||
|  | ||||
| void id3_utf16_decode(id3_utf16_t const *, id3_ucs4_t *); | ||||
| void id3_utf16_encode(id3_utf16_t *, id3_ucs4_t const *); | ||||
|  | ||||
| id3_length_t id3_utf16_put(id3_byte_t **, id3_utf16_t, | ||||
| 			   enum id3_utf16_byteorder); | ||||
| id3_utf16_t id3_utf16_get(id3_byte_t const **, enum id3_utf16_byteorder); | ||||
|  | ||||
| id3_length_t id3_utf16_serialize(id3_byte_t **, id3_ucs4_t const *, | ||||
| 				 enum id3_utf16_byteorder, int); | ||||
| id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **, id3_length_t, | ||||
| 				  enum id3_utf16_byteorder); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										365
									
								
								src/libid3tag/utf8.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								src/libid3tag/utf8.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,365 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: utf8.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "utf8.h" | ||||
| # include "ucs4.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->length() | ||||
|  * DESCRIPTION:	return the number of ucs4 chars represented by a utf8 string | ||||
|  */ | ||||
| id3_length_t id3_utf8_length(id3_utf8_t const *utf8) | ||||
| { | ||||
|   id3_length_t length = 0; | ||||
|  | ||||
|   while (*utf8) { | ||||
|     if ((utf8[0] & 0x80) == 0x00) | ||||
|       ++length; | ||||
|     else if ((utf8[0] & 0xe0) == 0xc0 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80) { | ||||
|       if (((utf8[0] & 0x1fL) << 6) >= 0x00000080L) { | ||||
| 	++length; | ||||
| 	utf8 += 1; | ||||
|       } | ||||
|     } | ||||
|     else if ((utf8[0] & 0xf0) == 0xe0 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80) { | ||||
|       if ((((utf8[0] & 0x0fL) << 12) | | ||||
| 	   ((utf8[1] & 0x3fL) <<  6)) >= 0x00000800L) { | ||||
| 	++length; | ||||
| 	utf8 += 2; | ||||
|       } | ||||
|     } | ||||
|     else if ((utf8[0] & 0xf8) == 0xf0 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80 && | ||||
| 	     (utf8[3] & 0xc0) == 0x80) { | ||||
|       if ((((utf8[0] & 0x07L) << 18) | | ||||
| 	   ((utf8[1] & 0x3fL) << 12)) >= 0x00010000L) { | ||||
| 	++length; | ||||
| 	utf8 += 3; | ||||
|       } | ||||
|     } | ||||
|     else if ((utf8[0] & 0xfc) == 0xf8 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80 && | ||||
| 	     (utf8[3] & 0xc0) == 0x80 && | ||||
| 	     (utf8[4] & 0xc0) == 0x80) { | ||||
|       if ((((utf8[0] & 0x03L) << 24) | | ||||
| 	   ((utf8[0] & 0x3fL) << 18)) >= 0x00200000L) { | ||||
| 	++length; | ||||
| 	utf8 += 4; | ||||
|       } | ||||
|     } | ||||
|     else if ((utf8[0] & 0xfe) == 0xfc && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80 && | ||||
| 	     (utf8[3] & 0xc0) == 0x80 && | ||||
| 	     (utf8[4] & 0xc0) == 0x80 && | ||||
| 	     (utf8[5] & 0xc0) == 0x80) { | ||||
|       if ((((utf8[0] & 0x01L) << 30) | | ||||
| 	   ((utf8[0] & 0x3fL) << 24)) >= 0x04000000L) { | ||||
| 	++length; | ||||
| 	utf8 += 5; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ++utf8; | ||||
|   } | ||||
|  | ||||
|   return length; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->size() | ||||
|  * DESCRIPTION:	return the encoding size of a utf8 string | ||||
|  */ | ||||
| id3_length_t id3_utf8_size(id3_utf8_t const *utf8) | ||||
| { | ||||
|   id3_utf8_t const *ptr = utf8; | ||||
|  | ||||
|   while (*ptr) | ||||
|     ++ptr; | ||||
|  | ||||
|   return ptr - utf8 + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->ucs4duplicate() | ||||
|  * DESCRIPTION:	duplicate and decode a utf8 string into ucs4 | ||||
|  */ | ||||
| id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *utf8) | ||||
| { | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_utf8_decode(utf8, ucs4); | ||||
|  | ||||
|   return release(ucs4); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->decodechar() | ||||
|  * DESCRIPTION:	decode a series of utf8 chars into a single ucs4 char | ||||
|  */ | ||||
| id3_length_t id3_utf8_decodechar(id3_utf8_t const *utf8, id3_ucs4_t *ucs4) | ||||
| { | ||||
|   id3_utf8_t const *start = utf8; | ||||
|  | ||||
|   while (1) { | ||||
|     if ((utf8[0] & 0x80) == 0x00) { | ||||
|       *ucs4 = utf8[0]; | ||||
|       return utf8 - start + 1; | ||||
|     } | ||||
|     else if ((utf8[0] & 0xe0) == 0xc0 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80) { | ||||
|       *ucs4 = | ||||
| 	((utf8[0] & 0x1fL) << 6) | | ||||
| 	((utf8[1] & 0x3fL) << 0); | ||||
|       if (*ucs4 >= 0x00000080L) | ||||
| 	return utf8 - start + 2; | ||||
|     } | ||||
|     else if ((utf8[0] & 0xf0) == 0xe0 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80) { | ||||
|       *ucs4 = | ||||
| 	((utf8[0] & 0x0fL) << 12) | | ||||
| 	((utf8[1] & 0x3fL) <<  6) | | ||||
| 	((utf8[2] & 0x3fL) <<  0); | ||||
|       if (*ucs4 >= 0x00000800L) | ||||
| 	return utf8 - start + 3; | ||||
|     } | ||||
|     else if ((utf8[0] & 0xf8) == 0xf0 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80 && | ||||
| 	     (utf8[3] & 0xc0) == 0x80) { | ||||
|       *ucs4 = | ||||
| 	((utf8[0] & 0x07L) << 18) | | ||||
| 	((utf8[1] & 0x3fL) << 12) | | ||||
| 	((utf8[2] & 0x3fL) <<  6) | | ||||
| 	((utf8[3] & 0x3fL) <<  0); | ||||
|       if (*ucs4 >= 0x00010000L) | ||||
| 	return utf8 - start + 4; | ||||
|     } | ||||
|     else if ((utf8[0] & 0xfc) == 0xf8 && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80 && | ||||
| 	     (utf8[3] & 0xc0) == 0x80 && | ||||
| 	     (utf8[4] & 0xc0) == 0x80) { | ||||
|       *ucs4 = | ||||
| 	((utf8[0] & 0x03L) << 24) | | ||||
| 	((utf8[1] & 0x3fL) << 18) | | ||||
| 	((utf8[2] & 0x3fL) << 12) | | ||||
| 	((utf8[3] & 0x3fL) <<  6) | | ||||
| 	((utf8[4] & 0x3fL) <<  0); | ||||
|       if (*ucs4 >= 0x00200000L) | ||||
| 	return utf8 - start + 5; | ||||
|     } | ||||
|     else if ((utf8[0] & 0xfe) == 0xfc && | ||||
| 	     (utf8[1] & 0xc0) == 0x80 && | ||||
| 	     (utf8[2] & 0xc0) == 0x80 && | ||||
| 	     (utf8[3] & 0xc0) == 0x80 && | ||||
| 	     (utf8[4] & 0xc0) == 0x80 && | ||||
| 	     (utf8[5] & 0xc0) == 0x80) { | ||||
|       *ucs4 = | ||||
| 	((utf8[0] & 0x01L) << 30) | | ||||
| 	((utf8[1] & 0x3fL) << 24) | | ||||
| 	((utf8[2] & 0x3fL) << 18) | | ||||
| 	((utf8[3] & 0x3fL) << 12) | | ||||
| 	((utf8[4] & 0x3fL) <<  6) | | ||||
| 	((utf8[5] & 0x3fL) <<  0); | ||||
|       if (*ucs4 >= 0x04000000L) | ||||
| 	return utf8 - start + 6; | ||||
|     } | ||||
|  | ||||
|     ++utf8; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->encodechar() | ||||
|  * DESCRIPTION:	encode a single ucs4 char into a series of up to 6 utf8 chars | ||||
|  */ | ||||
| id3_length_t id3_utf8_encodechar(id3_utf8_t *utf8, id3_ucs4_t ucs4) | ||||
| { | ||||
|   if (ucs4 <= 0x0000007fL) { | ||||
|     utf8[0] = ucs4; | ||||
|  | ||||
|     return 1; | ||||
|   } | ||||
|   else if (ucs4 <= 0x000007ffL) { | ||||
|     utf8[0] = 0xc0 | ((ucs4 >>  6) & 0x1f); | ||||
|     utf8[1] = 0x80 | ((ucs4 >>  0) & 0x3f); | ||||
|  | ||||
|     return 2; | ||||
|   } | ||||
|   else if (ucs4 <= 0x0000ffffL) { | ||||
|     utf8[0] = 0xe0 | ((ucs4 >> 12) & 0x0f); | ||||
|     utf8[1] = 0x80 | ((ucs4 >>  6) & 0x3f); | ||||
|     utf8[2] = 0x80 | ((ucs4 >>  0) & 0x3f); | ||||
|  | ||||
|     return 3; | ||||
|   } | ||||
|   else if (ucs4 <= 0x001fffffL) { | ||||
|     utf8[0] = 0xf0 | ((ucs4 >> 18) & 0x07); | ||||
|     utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f); | ||||
|     utf8[2] = 0x80 | ((ucs4 >>  6) & 0x3f); | ||||
|     utf8[3] = 0x80 | ((ucs4 >>  0) & 0x3f); | ||||
|  | ||||
|     return 4; | ||||
|   } | ||||
|   else if (ucs4 <= 0x03ffffffL) { | ||||
|     utf8[0] = 0xf8 | ((ucs4 >> 24) & 0x03); | ||||
|     utf8[1] = 0x80 | ((ucs4 >> 18) & 0x3f); | ||||
|     utf8[2] = 0x80 | ((ucs4 >> 12) & 0x3f); | ||||
|     utf8[3] = 0x80 | ((ucs4 >>  6) & 0x3f); | ||||
|     utf8[4] = 0x80 | ((ucs4 >>  0) & 0x3f); | ||||
|  | ||||
|     return 5; | ||||
|   } | ||||
|   else if (ucs4 <= 0x7fffffffL) { | ||||
|     utf8[0] = 0xfc | ((ucs4 >> 30) & 0x01); | ||||
|     utf8[1] = 0x80 | ((ucs4 >> 24) & 0x3f); | ||||
|     utf8[2] = 0x80 | ((ucs4 >> 18) & 0x3f); | ||||
|     utf8[3] = 0x80 | ((ucs4 >> 12) & 0x3f); | ||||
|     utf8[4] = 0x80 | ((ucs4 >>  6) & 0x3f); | ||||
|     utf8[5] = 0x80 | ((ucs4 >>  0) & 0x3f); | ||||
|  | ||||
|     return 6; | ||||
|   } | ||||
|  | ||||
|   /* default */ | ||||
|  | ||||
|   return id3_utf8_encodechar(utf8, ID3_UCS4_REPLACEMENTCHAR); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->decode() | ||||
|  * DESCRIPTION:	decode a complete utf8 string into a ucs4 string | ||||
|  */ | ||||
| void id3_utf8_decode(id3_utf8_t const *utf8, id3_ucs4_t *ucs4) | ||||
| { | ||||
|   do | ||||
|     utf8 += id3_utf8_decodechar(utf8, ucs4); | ||||
|   while (*ucs4++); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->encode() | ||||
|  * DESCRIPTION:	encode a complete ucs4 string into a utf8 string | ||||
|  */ | ||||
| void id3_utf8_encode(id3_utf8_t *utf8, id3_ucs4_t const *ucs4) | ||||
| { | ||||
|   do | ||||
|     utf8 += id3_utf8_encodechar(utf8, *ucs4); | ||||
|   while (*ucs4++); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->put() | ||||
|  * DESCRIPTION:	serialize a single utf8 character | ||||
|  */ | ||||
| id3_length_t id3_utf8_put(id3_byte_t **ptr, id3_utf8_t utf8) | ||||
| { | ||||
|   if (ptr) | ||||
|     *(*ptr)++ = utf8; | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->get() | ||||
|  * DESCRIPTION:	deserialize a single utf8 character | ||||
|  */ | ||||
| id3_utf8_t id3_utf8_get(id3_byte_t const **ptr) | ||||
| { | ||||
|   return *(*ptr)++; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->serialize() | ||||
|  * DESCRIPTION:	serialize a ucs4 string using utf8 encoding | ||||
|  */ | ||||
| id3_length_t id3_utf8_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, | ||||
| 				int terminate) | ||||
| { | ||||
|   id3_length_t size = 0; | ||||
|   id3_utf8_t utf8[6], *out; | ||||
|  | ||||
|   while (*ucs4) { | ||||
|     switch (id3_utf8_encodechar(out = utf8, *ucs4++)) { | ||||
|     case 6: size += id3_utf8_put(ptr, *out++); | ||||
|     case 5: size += id3_utf8_put(ptr, *out++); | ||||
|     case 4: size += id3_utf8_put(ptr, *out++); | ||||
|     case 3: size += id3_utf8_put(ptr, *out++); | ||||
|     case 2: size += id3_utf8_put(ptr, *out++); | ||||
|     case 1: size += id3_utf8_put(ptr, *out++); | ||||
|     case 0: break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (terminate) | ||||
|     size += id3_utf8_put(ptr, 0); | ||||
|  | ||||
|   return size; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	utf8->deserialize() | ||||
|  * DESCRIPTION:	deserialize a ucs4 string using utf8 encoding | ||||
|  */ | ||||
| id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **ptr, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t const *end; | ||||
|   id3_utf8_t *utf8ptr, *utf8; | ||||
|   id3_ucs4_t *ucs4; | ||||
|  | ||||
|   end = *ptr + length; | ||||
|  | ||||
|   utf8 = malloc((length + 1) * sizeof(*utf8)); | ||||
|   if (utf8 == 0) | ||||
|     return 0; | ||||
|  | ||||
|   utf8ptr = utf8; | ||||
|   while (end - *ptr > 0 && (*utf8ptr = id3_utf8_get(ptr))) | ||||
|     ++utf8ptr; | ||||
|  | ||||
|   *utf8ptr = 0; | ||||
|  | ||||
|   ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4)); | ||||
|   if (ucs4) | ||||
|     id3_utf8_decode(utf8, ucs4); | ||||
|  | ||||
|   free(utf8); | ||||
|  | ||||
|   return ucs4; | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/libid3tag/utf8.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/libid3tag/utf8.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: utf8.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_UTF8_H | ||||
| # define LIBID3TAG_UTF8_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| id3_length_t id3_utf8_length(id3_utf8_t const *); | ||||
| id3_length_t id3_utf8_size(id3_utf8_t const *); | ||||
|  | ||||
| id3_length_t id3_utf8_decodechar(id3_utf8_t const *, id3_ucs4_t *); | ||||
| id3_length_t id3_utf8_encodechar(id3_utf8_t *, id3_ucs4_t); | ||||
|  | ||||
| void id3_utf8_decode(id3_utf8_t const *, id3_ucs4_t *); | ||||
| void id3_utf8_encode(id3_utf8_t *, id3_ucs4_t const *); | ||||
|  | ||||
| id3_length_t id3_utf8_put(id3_byte_t **, id3_utf8_t); | ||||
| id3_utf8_t id3_utf8_get(id3_byte_t const **); | ||||
|  | ||||
| id3_length_t id3_utf8_serialize(id3_byte_t **, id3_ucs4_t const *, int); | ||||
| id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **, id3_length_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										147
									
								
								src/libid3tag/util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								src/libid3tag/util.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: util.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
| # include <zlib.h> | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "util.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	util->unsynchronise() | ||||
|  * DESCRIPTION:	perform (in-place) unsynchronisation | ||||
|  */ | ||||
| id3_length_t id3_util_unsynchronise(id3_byte_t *data, id3_length_t length) | ||||
| { | ||||
|   id3_length_t bytes = 0, count; | ||||
|   id3_byte_t *end = data + length; | ||||
|   id3_byte_t const *ptr; | ||||
|  | ||||
|   if (length == 0) | ||||
|     return 0; | ||||
|  | ||||
|   for (ptr = data; ptr < end - 1; ++ptr) { | ||||
|     if (ptr[0] == 0xff && (ptr[1] == 0x00 || (ptr[1] & 0xe0) == 0xe0)) | ||||
|       ++bytes; | ||||
|   } | ||||
|  | ||||
|   if (bytes) { | ||||
|     ptr  = end; | ||||
|     end += bytes; | ||||
|  | ||||
|     *--end = *--ptr; | ||||
|  | ||||
|     for (count = bytes; count; *--end = *--ptr) { | ||||
|       if (ptr[-1] == 0xff && (ptr[0] == 0x00 || (ptr[0] & 0xe0) == 0xe0)) { | ||||
| 	*--end = 0x00; | ||||
| 	--count; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return length + bytes; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	util->deunsynchronise() | ||||
|  * DESCRIPTION:	undo unsynchronisation (in-place) | ||||
|  */ | ||||
| id3_length_t id3_util_deunsynchronise(id3_byte_t *data, id3_length_t length) | ||||
| { | ||||
|   id3_byte_t const *old, *end = data + length; | ||||
|   id3_byte_t *new; | ||||
|  | ||||
|   if (length == 0) | ||||
|     return 0; | ||||
|  | ||||
|   for (old = new = data; old < end - 1; ++old) { | ||||
|     *new++ = *old; | ||||
|     if (old[0] == 0xff && old[1] == 0x00) | ||||
|       ++old; | ||||
|   } | ||||
|  | ||||
|   *new++ = *old; | ||||
|  | ||||
|   return new - data; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	util->compress() | ||||
|  * DESCRIPTION:	perform zlib deflate method compression | ||||
|  */ | ||||
| id3_byte_t *id3_util_compress(id3_byte_t const *data, id3_length_t length, | ||||
| 			      id3_length_t *newlength) | ||||
| { | ||||
|   id3_byte_t *compressed; | ||||
|  | ||||
|   *newlength  = length + 12; | ||||
|   *newlength += *newlength / 1000; | ||||
|  | ||||
|   compressed = malloc(*newlength); | ||||
|   if (compressed) { | ||||
|     if (compress2(compressed, newlength, data, length, | ||||
| 		  Z_BEST_COMPRESSION) != Z_OK || | ||||
| 	*newlength >= length) { | ||||
|       free(compressed); | ||||
|       compressed = 0; | ||||
|     } | ||||
|     else { | ||||
|       id3_byte_t *resized; | ||||
|  | ||||
|       resized = realloc(compressed, *newlength ? *newlength : 1); | ||||
|       if (resized) | ||||
| 	compressed = resized; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return compressed; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	util->decompress() | ||||
|  * DESCRIPTION:	undo zlib deflate method compression | ||||
|  */ | ||||
| id3_byte_t *id3_util_decompress(id3_byte_t const *data, id3_length_t length, | ||||
| 				id3_length_t newlength) | ||||
| { | ||||
|   id3_byte_t *decompressed; | ||||
|  | ||||
|   decompressed = malloc(newlength ? newlength : 1); | ||||
|   if (decompressed) { | ||||
|     id3_length_t size; | ||||
|  | ||||
|     size = newlength; | ||||
|  | ||||
|     if (uncompress(decompressed, &size, data, length) != Z_OK || | ||||
| 	size != newlength) { | ||||
|       free(decompressed); | ||||
|       decompressed = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return decompressed; | ||||
| } | ||||
							
								
								
									
										35
									
								
								src/libid3tag/util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/libid3tag/util.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: util.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_UTIL_H | ||||
| # define LIBID3TAG_UTIL_H | ||||
|  | ||||
| # include "id3tag.h" | ||||
|  | ||||
| id3_length_t id3_util_unsynchronise(id3_byte_t *, id3_length_t); | ||||
| id3_length_t id3_util_deunsynchronise(id3_byte_t *, id3_length_t); | ||||
|  | ||||
| id3_byte_t *id3_util_compress(id3_byte_t const *, id3_length_t, | ||||
| 			      id3_length_t *); | ||||
| id3_byte_t *id3_util_decompress(id3_byte_t const *, id3_length_t, | ||||
| 				id3_length_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										45
									
								
								src/libid3tag/version.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/libid3tag/version.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: version.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include "id3tag.h" | ||||
| # include "version.h" | ||||
|  | ||||
| char const id3_version[]   = "ID3 Tag Library " ID3_VERSION; | ||||
| char const id3_copyright[] = "Copyright (C) " ID3_PUBLISHYEAR " " ID3_AUTHOR; | ||||
| char const id3_author[]    = ID3_AUTHOR " <" ID3_EMAIL ">"; | ||||
|  | ||||
| char const id3_build[] = "" | ||||
| # if defined(DEBUG) | ||||
|   "DEBUG " | ||||
| # elif defined(NDEBUG) | ||||
|   "NDEBUG " | ||||
| # endif | ||||
|  | ||||
| # if defined(EXPERIMENTAL) | ||||
|   "EXPERIMENTAL " | ||||
| # endif | ||||
| ; | ||||
							
								
								
									
										25
									
								
								src/libid3tag/version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/libid3tag/version.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * libid3tag - ID3 tag manipulation library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: version.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBID3TAG_VERSION_H | ||||
| # define LIBID3TAG_VERSION_H | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										321
									
								
								src/libmad/CHANGES
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								src/libmad/CHANGES
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,321 @@ | ||||
|  | ||||
|  libmad - MPEG audio decoder library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: CHANGES,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| Version 0.15.0 (beta) | ||||
|  | ||||
|   * Updated to autoconf 2.57, automake 1.7.5, libtool 1.4.3. | ||||
|  | ||||
|   * Added new mad_f_div() API routine. | ||||
|  | ||||
|   * Added a 64th entry to the Layer I/Layer II scalefactor table, for better | ||||
|     compatibility with existing streams. The --enable-strict-iso option to | ||||
|     `configure' can be used to disable use of this entry. | ||||
|  | ||||
|   * Modified the header decoding routine to allow the reserved emphasis | ||||
|     value, for better compatibility with existing streams. The | ||||
|     --enable-strict-iso option to `configure' can be used to restore the | ||||
|     previous behavior of reporting this value as an error. | ||||
|  | ||||
|   * Added new MAD_EMPHASIS_RESERVED enumeration constant. | ||||
|  | ||||
|   * Fixed a bug in the ARM version of mad_f_scale64() discovered by Andre | ||||
|     McCurdy. | ||||
|  | ||||
|   * Rewrote PowerPC assembly for minor gains. | ||||
|  | ||||
|   * Modified mad_timer_fraction() to avoid the possibility of division by | ||||
|     zero when 0 is passed as the second argument. | ||||
|  | ||||
|   * Fixed a non-fatal problem caused by attempting to designate ancillary | ||||
|     bits in Layer III after a decoding error. | ||||
|  | ||||
|   * Changed to build a shared library by default. | ||||
|  | ||||
|   * Changed to use native Cygwin build by default; give --host=mingw32 to | ||||
|     `configure' to use MinGW (and avoid a dependency on the Cygwin DLL). | ||||
|  | ||||
| Version 0.14.2 (beta) | ||||
|  | ||||
|   * Changed Cygwin builds to use MinGW; resulting Win32 executables no | ||||
|     longer have a dependency on Cygwin DLLs. | ||||
|  | ||||
|   * Added a new mad_stream_errorstr() API function to libmad for retrieving | ||||
|     a string description of the current error condition. | ||||
|  | ||||
| Version 0.14.1 (beta) | ||||
|  | ||||
|   * Updated config.guess and config.sub to latest upstream versions. | ||||
|  | ||||
|   * Enabled libtool versioning rather than release numbering. | ||||
|  | ||||
|   * Improved the documentation in minimad.c. | ||||
|  | ||||
|   * Several other small fixes. | ||||
|  | ||||
| Version 0.14.0 (beta) | ||||
|  | ||||
|   * Added a 64-bit FPM negation operation to improve performance of subband | ||||
|     synthesis on some platforms. | ||||
|  | ||||
|   * Improved MSVC++ portability and added MSVC++ project files. | ||||
|  | ||||
|   * Added rounding to Layer III requantization for slightly better accuracy. | ||||
|  | ||||
| Version 0.13.0 (beta) | ||||
|  | ||||
|   * Ancillary data is now properly extracted from Layer III streams. | ||||
|  | ||||
|   * Rewrote the Layer III joint stereo decoding routine to correct a major | ||||
|     MPEG-2 problem and a minor MPEG-1 problem decoding intensity stereo. | ||||
|  | ||||
|   * Eliminated the dependency on sign-extending right shifts for Layer I and | ||||
|     Layer II. | ||||
|  | ||||
|   * Renamed `private' field to `private_bits' for better C++ compatibility. | ||||
|  | ||||
|   * Gratuitously renamed `sfreq' field to `samplerate' and | ||||
|     MAD_ERROR_BADSAMPLEFREQ constant to MAD_ERROR_BADSAMPLERATE. | ||||
|  | ||||
|   * Added `samplerate' and `channels' fields to synth.pcm struct to allow | ||||
|     these to be different from the decoded frame, and for simpler access. | ||||
|  | ||||
|   * Added new mad_stream_options() and mad_decoder_options() API entries for | ||||
|     special runtime decoding options. | ||||
|  | ||||
|   * Added new MAD_OPTION_IGNORECRC and MAD_OPTION_HALFSAMPLERATE options. | ||||
|  | ||||
|   * Added new MAD_FLAG_FREEFORMAT indicator flag. | ||||
|  | ||||
|   * Fixed some bugs in the async decoder. | ||||
|  | ||||
|   * Added a new mad_timer_multiply() API routine. | ||||
|  | ||||
|   * Eliminated `+' from asm constraints under Intel for better compatibility | ||||
|     with some compilers. | ||||
|  | ||||
|   * Fixed a PIC-related problem in libmad/imdct_l_arm.S. | ||||
|  | ||||
|   * Eliminated a static variable to make libmad thread-safe. | ||||
|  | ||||
| Version 0.12.5 (beta) | ||||
|  | ||||
|   * Modified Layer III requantization to occur during Huffman decoding for | ||||
|     significant performance gains. | ||||
|  | ||||
|   * Optimized short block IMDCT by eliminating redundant calculations. | ||||
|  | ||||
|   * Made several other Layer III performance improvements; added | ||||
|     ASO_INTERLEAVE1, ASO_INTERLEAVE2, and ASO_ZEROCHECK | ||||
|     architecture-specific options for best performance on various | ||||
|     architectures. | ||||
|  | ||||
|   * Optimized synthesis DCT to store result values as soon as they are | ||||
|     calculated. | ||||
|  | ||||
| Version 0.12.4 (beta) | ||||
|  | ||||
|   * New PowerPC fixed-point assembly courtesy of David Blythe. | ||||
|  | ||||
|   * Reorganized fixed-point assembly routines for easier maintenance and | ||||
|     better performance. | ||||
|  | ||||
|   * Improved performance of subband synthesis through better indexing and | ||||
|     fewer local variables. | ||||
|  | ||||
|   * Added alias reduction for the lower two subbands of mixed short blocks, | ||||
|     per a report of ambiguity with ISO/IEC 11172-3 and for uniformity with | ||||
|     most other implementations. Also improved alias reduction performance | ||||
|     using multiply/accumulate. | ||||
|  | ||||
|   * Added --enable-strict-iso option to `configure' to override best | ||||
|     accepted practices such as the alias reduction for mixed short blocks. | ||||
|  | ||||
|   * Improved performance of Layer III IMDCT by using longer | ||||
|     multiply/accumulate runs where possible. | ||||
|  | ||||
| Version 0.12.3 (beta) | ||||
|  | ||||
|   * Added MPEG 2.5 support. | ||||
|  | ||||
|   * Added preliminary support for parameterizing the binary point position | ||||
|     in the fixed-point representation. | ||||
|  | ||||
|   * Added multiply/accumulate optimization to the Layer III IMDCT for long | ||||
|     blocks. | ||||
|  | ||||
|   * Fixed a bug in the handling of Layer III mixed_block_flag. | ||||
|  | ||||
|   * Fixed a configure problem when multiple -O CFLAGS are present. | ||||
|  | ||||
| Version 0.12.2 (beta) | ||||
|  | ||||
|   * Rearranged the synthesis polyphase filterbank memory vector for better | ||||
|     locality of reference, and rewrote mad_synth_frame() to accommodate, | ||||
|     resulting in improved performance. | ||||
|  | ||||
|   * Discovered a combination of compiler optimization flags that further | ||||
|     improve performance. | ||||
|  | ||||
|   * Changed some array references in layer3.c to pointer derefs. | ||||
|  | ||||
| Version 0.12.1 (beta) | ||||
|  | ||||
|   * Resolved the intensity + MS joint stereo issue (a simple bug). | ||||
|     OPT_ISKLUGE is no longer considered to be a kluge. | ||||
|  | ||||
|   * Fixed another, hopefully last main_data memory bug. | ||||
|  | ||||
|   * Split part of struct mad_frame into struct mad_header for convenience | ||||
|     and size. | ||||
|  | ||||
| Version 0.12.0 (alpha) | ||||
|  | ||||
|   * Changed the build environment to use automake and libtool. A libmad | ||||
|     shared library can now be built using the --enable-shared option to | ||||
|     `configure'. | ||||
|  | ||||
|   * Added another callback to MAD's high-level decoder API after the frame | ||||
|     header has been read but before the frame's audio data is decoded. | ||||
|  | ||||
|   * Streamlined header processing so that mad_frame_decode() can be called | ||||
|     with or without having already called mad_frame_header(). | ||||
|  | ||||
|   * Fixed some other header reading miscellany, including CRC handling and | ||||
|     free bitrate detection, and frame length verification with free | ||||
|     bitrates. | ||||
|  | ||||
|   * Fixed a problem with Layer III free bitrates > 320 kbps. The main_data | ||||
|     buffer size should now be large enough to handle any size frame, by | ||||
|     virtue of the maximum possible part2_3_length. | ||||
|  | ||||
|   * Further developed the async API; arbitrary messages can now be passed to | ||||
|     the subsidiary decoding process. | ||||
|  | ||||
|   * Streamlined libmad/timer.c and extended its interface. It now has | ||||
|     support for video frame/field lengths, including output support for | ||||
|     drop-frame encoding. | ||||
|  | ||||
|   * Replaced many constant integer preprocessor defines with enums. | ||||
|  | ||||
| Version 0.11.4 (beta) | ||||
|  | ||||
|   * Fixed free format bitrate discovery. | ||||
|  | ||||
|   * Changed the timer implementation and extended its interface. | ||||
|  | ||||
|   * Integrated Nicolas Pitre's patch for pre-shifting at compile-time and | ||||
|     for better multiply/accumulate code output. | ||||
|  | ||||
|   * Applied Simon Burge's patch to imdct_l_arm.S for a.out compatibility. | ||||
|  | ||||
|   * Added -mtune=strongarm for all ARM targets. | ||||
|  | ||||
| Version 0.11.3 (beta) | ||||
|  | ||||
|   * Added new --enable-speed and --enable-accuracy options for `configure' | ||||
|     to automatically select appropriate SSO/ASO options, et al. | ||||
|  | ||||
|   * Modified subband synthesis to use multiply/accumulate optimization (if | ||||
|     available) for better speed and/or accuracy. | ||||
|  | ||||
|   * Incorporated Andre McCurdy's changes for further rounding optimizations | ||||
|     in the rest of his code. | ||||
|  | ||||
| Version 0.11.2 (beta) | ||||
|  | ||||
|   * Incorporated Nicolas Pitre's ARM assembly and parameterized scaling | ||||
|     changes. | ||||
|  | ||||
|   * Incorporated Andre McCurdy's ARM assembly optimization (used only if | ||||
|     --enable-aso is given to `configure' to enable architecture-specific | ||||
|     optimizations.) | ||||
|  | ||||
|   * Reduced FPM_INTEL assembly to two instructions. | ||||
|  | ||||
|   * Fixed accuracy problems with certain FPM modes in synth.c. | ||||
|  | ||||
|   * Improved the accuracy of FPM_APPROX. | ||||
|  | ||||
|   * Improved the accuracy of SSO. | ||||
|  | ||||
|   * Improved sync discovery by checking for a sync word in the following | ||||
|     frame. | ||||
|  | ||||
|   * Minor code clean-up. | ||||
|  | ||||
|   * Added experimental rules for generating a libmad.so shared library. | ||||
|  | ||||
| Version 0.11.1 (beta) | ||||
|  | ||||
|   * Moved libmad code into a separate directory. | ||||
|  | ||||
|   * Changed SSO to be disabled by default, as output accuracy is deemed to | ||||
|     be more important than speed in the general case. | ||||
|  | ||||
|   * Fixed a bug in Layer III sanity checking that could cause a crash on | ||||
|     certain random data input. | ||||
|  | ||||
|   * Extended the Layer III requantization table from 8191 to 8206 as some | ||||
|     encoders are known to use these values, even though ISO/IEC 11172-3 | ||||
|     suggests the maximum should be 8191. | ||||
|  | ||||
| Version 0.11.0 (beta) | ||||
|  | ||||
|   * Implemented MPEG-2 extension to Lower Sampling Frequencies. | ||||
|  | ||||
|   * Improved Layer III performance by avoiding IMDCT calculation when all | ||||
|     input samples are zero. | ||||
|  | ||||
|   * Significantly reduced size of Layer II tables. | ||||
|  | ||||
| Version 0.10.3 (beta) | ||||
|  | ||||
|   * Improved SSO output quality. | ||||
|  | ||||
|   * Made portable to cygwin. | ||||
|  | ||||
|   * Localized memory references in III_huffdecode() for better performance. | ||||
|  | ||||
| Version 0.10.2 (beta) | ||||
|  | ||||
|   * Rewrote Layer III long block 36-point IMDCT routine for better | ||||
|     performance. | ||||
|  | ||||
|   * Improved subband synthesis fixed-point games somewhat. | ||||
|  | ||||
| Version 0.10.1 (beta) | ||||
|  | ||||
|   * Added a subband synthesis optimization (SSO) which involves modifying | ||||
|     the fixed-point multiplication method during windowing. This produces | ||||
|     subtle differences in the output but improves performance greatly. | ||||
|  | ||||
|   * Added I_STEREO and MS_STEREO flags to frame struct. | ||||
|  | ||||
|   * Eliminated privately-used CRCFAILED flag. | ||||
|  | ||||
|   * Fixed a bug where Layer III decoding could crash on some badly-formatted | ||||
|     (e.g. non-MPEG) bitstreams. | ||||
|  | ||||
|   * Miscellaneous code clean-up. | ||||
|  | ||||
| Version 0.10.0 (beta) | ||||
|  | ||||
|   * Added SPARC fixed-point math support. | ||||
|  | ||||
|   * Revamped libmad API for better high- and low-level support. | ||||
|  | ||||
|   * Documented more of the code. | ||||
|  | ||||
|   * Changed sync semantics such that new stream buffers are assumed to be | ||||
|     sync-aligned. | ||||
|  | ||||
|   * Changed Layer III to dynamically allocate static memory so as not to | ||||
|     waste it (about 6.4K) when only decoding Layer I or Layer II. | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
							
								
								
									
										340
									
								
								src/libmad/COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								src/libmad/COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||
|      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Library General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
|  | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if you | ||||
| distribute copies of the software, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
|  | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
|  | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| patent must be licensed for everyone's free use or not licensed at all. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
|  | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
|  | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
|  | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
|  | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
|  | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
|  | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
|  | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
|  | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
|  | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  However, as a | ||||
| special exception, the source code distributed need not include | ||||
| anything that is normally distributed (in either source or binary | ||||
| form) with the major components (compiler, kernel, and so on) of the | ||||
| operating system on which the executable runs, unless that component | ||||
| itself accompanies the executable. | ||||
|  | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
|  | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
|  | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program subject to | ||||
| these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
|  | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
|  | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the General Public License from time to time.  Such new versions will | ||||
| be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
|  | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| make exceptions for this.  Our decision will be guided by the two goals | ||||
| of preserving the free status of all derivatives of our free software and | ||||
| of promoting the sharing and reuse of software generally. | ||||
|  | ||||
| 			    NO WARRANTY | ||||
|  | ||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
|  | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
| 	    How to Apply These Terms to Your New Programs | ||||
|  | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     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 | ||||
|  | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
|  | ||||
|     Gnomovision version 69, Copyright (C) year  name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
|  | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Library General | ||||
| Public License instead of this License. | ||||
							
								
								
									
										21
									
								
								src/libmad/COPYRIGHT
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/libmad/COPYRIGHT
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
|  | ||||
|  libmad - MPEG audio decoder library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  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 | ||||
|  | ||||
|  If you would like to negotiate alternate licensing terms, you may do | ||||
|  so by contacting: Underbit Technologies, Inc. <info@underbit.com> | ||||
|  | ||||
							
								
								
									
										100
									
								
								src/libmad/CREDITS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/libmad/CREDITS
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
|  | ||||
|  libmad - MPEG audio decoder library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: CREDITS,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| AUTHOR | ||||
|  | ||||
|   Except where otherwise noted, all code was authored by: | ||||
|  | ||||
|       Robert Leslie <rob@underbit.com> | ||||
|  | ||||
| CONTRIBUTORS | ||||
|  | ||||
|   Significant contributions have been incorporated with thanks to: | ||||
|  | ||||
|       Anonymous | ||||
|         2002/03/15: frame.c | ||||
|           - Reported problem with use of reserved emphasis value. | ||||
|  | ||||
|       Niek Albers <info@daansystems.com> | ||||
|         2003/04/21: layer3.c | ||||
|           - Reported runtime uninitialized use of `ptr' in designating | ||||
|             ancillary bits after a decoding error. | ||||
|  | ||||
|       David Blythe <blythe@routefree.com> | ||||
|         2001/01/30: fixed.h | ||||
|           - Provided initial PowerPC fixed-point assembly. | ||||
|  | ||||
|       Simon Burge <simonb@wasabisystems.com> | ||||
|         2000/09/20: imdct_l_arm.S | ||||
|           - Suggested patch for a.out compatibility. | ||||
|  | ||||
|       Joshua Haberman <joshua@haberman.com> | ||||
|         2001/08/10: decoder.c, huffman.c | ||||
|           - Suggested portability fixes. | ||||
|  | ||||
|       Timothy King <lordzork@lordzork.com> | ||||
|         2002/05/04: sf_table.dat, layer12.c | ||||
|           - Reported problem with use of (missing) scalefactor index 63. | ||||
|  | ||||
|       Andre McCurdy <armccurdy@yahoo.co.uk> | ||||
|         2000/08/10: imdct_l_arm.S | ||||
|           - ARM optimized assembly replacement for III_imdct_l(). | ||||
|         2000/09/15: imdct_l_arm.S | ||||
|           - Applied Nicolas Pitre's rounding optimisation in all remaining | ||||
|             places. | ||||
|         2001/02/10: layer3.c | ||||
|           - Inspiration for Huffman decoding and requantization rewrite, and | ||||
|             other miscellany. | ||||
|         2001/03/24: imdct_l_arm.S | ||||
|           - Corrected PIC unsafe code. | ||||
|         2002/02/16: fixed.h | ||||
|           - Discovered bug in ARM version of mad_f_scale64(). | ||||
|  | ||||
|       Haruhiko OGASAWARA <theta@m1.interq.or.jp> | ||||
|         2001/01/28: layer3.c | ||||
|           - Reported discrepancy in alias reduction for mixed short blocks. | ||||
|  | ||||
|       Brett Paterson <brett@fmod.org> | ||||
|         2001/10/28: global.h | ||||
|           - Reported missing <assert.h> et al. under MS Embedded Visual C. | ||||
|  | ||||
|       Sean 'Shaleh' Perry <shaleh@via.net> | ||||
|         2000/04/04: fixed.h | ||||
|           - Suggested use of size-dependent typedefs. | ||||
|         2001/10/22: config.guess, config.sub | ||||
|           - Keep up to date for proper Debian packaging. | ||||
|  | ||||
|       Bertrand Petit <eemad@phoe.frmug.org> | ||||
|         2001/11/05: synth.h | ||||
|           - Suggested PCM channel enumeration constants. | ||||
|         2001/11/05: stream.h | ||||
|           - Suggested MAD_ERROR_NONE enumeration constant. | ||||
|         2001/11/05: stream.c | ||||
|           - Suggested mad_stream_errorstr() function. | ||||
|  | ||||
|       Nicolas Pitre <nico@cam.org> | ||||
|         2000/09/09: fixed.h | ||||
|           - Parameterized all scaling for correct use of all multiplication | ||||
|             methods within mad_synth_frame(). | ||||
|           - Rewrote the FPM_ARM version of mad_f_mul() so we have 64-bit | ||||
|             multiplication result, rounding and scaling with 3 instructions. | ||||
|         2000/09/09: imdct_l_arm.S | ||||
|           - Optimized rounding + scaling operations. | ||||
|         2000/09/17: synth.c | ||||
|           - Changed D[] run-time shifts to compile-time. | ||||
|           - Modified synthesis for better multiply/accumulate code output. | ||||
|         2001/08/11: fixed.h, synth.c | ||||
|           - Suggested 64-bit FPM negation and negative term factorization | ||||
|             during synthesis. | ||||
|         2001/08/11: fixed.h | ||||
|           - Suggested unrounded behavior for FPM_DEFAULT when OPT_SPEED. | ||||
|         2001/11/19: fixed.c | ||||
|           - Suggested computation of any resampling ratio. | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
							
								
								
									
										607
									
								
								src/libmad/D.dat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								src/libmad/D.dat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,607 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: D.dat,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * These are the coefficients for the subband synthesis window. This is a | ||||
|  * reordered version of Table B.3 from ISO/IEC 11172-3. | ||||
|  * | ||||
|  * Every value is parameterized so that shift optimizations can be made at | ||||
|  * compile-time. For example, every value can be right-shifted 12 bits to | ||||
|  * minimize multiply instruction times without any loss of accuracy. | ||||
|  */ | ||||
|  | ||||
|   {  PRESHIFT(0x00000000) /*  0.000000000 */,	/*  0 */ | ||||
|     -PRESHIFT(0x0001d000) /* -0.000442505 */, | ||||
|      PRESHIFT(0x000d5000) /*  0.003250122 */, | ||||
|     -PRESHIFT(0x001cb000) /* -0.007003784 */, | ||||
|      PRESHIFT(0x007f5000) /*  0.031082153 */, | ||||
|     -PRESHIFT(0x01421000) /* -0.078628540 */, | ||||
|      PRESHIFT(0x019ae000) /*  0.100311279 */, | ||||
|     -PRESHIFT(0x09271000) /* -0.572036743 */, | ||||
|      PRESHIFT(0x1251e000) /*  1.144989014 */, | ||||
|      PRESHIFT(0x09271000) /*  0.572036743 */, | ||||
|      PRESHIFT(0x019ae000) /*  0.100311279 */, | ||||
|      PRESHIFT(0x01421000) /*  0.078628540 */, | ||||
|      PRESHIFT(0x007f5000) /*  0.031082153 */, | ||||
|      PRESHIFT(0x001cb000) /*  0.007003784 */, | ||||
|      PRESHIFT(0x000d5000) /*  0.003250122 */, | ||||
|      PRESHIFT(0x0001d000) /*  0.000442505 */, | ||||
|  | ||||
|      PRESHIFT(0x00000000) /*  0.000000000 */, | ||||
|     -PRESHIFT(0x0001d000) /* -0.000442505 */, | ||||
|      PRESHIFT(0x000d5000) /*  0.003250122 */, | ||||
|     -PRESHIFT(0x001cb000) /* -0.007003784 */, | ||||
|      PRESHIFT(0x007f5000) /*  0.031082153 */, | ||||
|     -PRESHIFT(0x01421000) /* -0.078628540 */, | ||||
|      PRESHIFT(0x019ae000) /*  0.100311279 */, | ||||
|     -PRESHIFT(0x09271000) /* -0.572036743 */, | ||||
|      PRESHIFT(0x1251e000) /*  1.144989014 */, | ||||
|      PRESHIFT(0x09271000) /*  0.572036743 */, | ||||
|      PRESHIFT(0x019ae000) /*  0.100311279 */, | ||||
|      PRESHIFT(0x01421000) /*  0.078628540 */, | ||||
|      PRESHIFT(0x007f5000) /*  0.031082153 */, | ||||
|      PRESHIFT(0x001cb000) /*  0.007003784 */, | ||||
|      PRESHIFT(0x000d5000) /*  0.003250122 */, | ||||
|      PRESHIFT(0x0001d000) /*  0.000442505 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  1 */ | ||||
|     -PRESHIFT(0x0001f000) /* -0.000473022 */, | ||||
|      PRESHIFT(0x000da000) /*  0.003326416 */, | ||||
|     -PRESHIFT(0x00207000) /* -0.007919312 */, | ||||
|      PRESHIFT(0x007d0000) /*  0.030517578 */, | ||||
|     -PRESHIFT(0x0158d000) /* -0.084182739 */, | ||||
|      PRESHIFT(0x01747000) /*  0.090927124 */, | ||||
|     -PRESHIFT(0x099a8000) /* -0.600219727 */, | ||||
|      PRESHIFT(0x124f0000) /*  1.144287109 */, | ||||
|      PRESHIFT(0x08b38000) /*  0.543823242 */, | ||||
|      PRESHIFT(0x01bde000) /*  0.108856201 */, | ||||
|      PRESHIFT(0x012b4000) /*  0.073059082 */, | ||||
|      PRESHIFT(0x0080f000) /*  0.031478882 */, | ||||
|      PRESHIFT(0x00191000) /*  0.006118774 */, | ||||
|      PRESHIFT(0x000d0000) /*  0.003173828 */, | ||||
|      PRESHIFT(0x0001a000) /*  0.000396729 */, | ||||
|  | ||||
|     -PRESHIFT(0x00001000) /* -0.000015259 */, | ||||
|     -PRESHIFT(0x0001f000) /* -0.000473022 */, | ||||
|      PRESHIFT(0x000da000) /*  0.003326416 */, | ||||
|     -PRESHIFT(0x00207000) /* -0.007919312 */, | ||||
|      PRESHIFT(0x007d0000) /*  0.030517578 */, | ||||
|     -PRESHIFT(0x0158d000) /* -0.084182739 */, | ||||
|      PRESHIFT(0x01747000) /*  0.090927124 */, | ||||
|     -PRESHIFT(0x099a8000) /* -0.600219727 */, | ||||
|      PRESHIFT(0x124f0000) /*  1.144287109 */, | ||||
|      PRESHIFT(0x08b38000) /*  0.543823242 */, | ||||
|      PRESHIFT(0x01bde000) /*  0.108856201 */, | ||||
|      PRESHIFT(0x012b4000) /*  0.073059082 */, | ||||
|      PRESHIFT(0x0080f000) /*  0.031478882 */, | ||||
|      PRESHIFT(0x00191000) /*  0.006118774 */, | ||||
|      PRESHIFT(0x000d0000) /*  0.003173828 */, | ||||
|      PRESHIFT(0x0001a000) /*  0.000396729 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  2 */ | ||||
|     -PRESHIFT(0x00023000) /* -0.000534058 */, | ||||
|      PRESHIFT(0x000de000) /*  0.003387451 */, | ||||
|     -PRESHIFT(0x00245000) /* -0.008865356 */, | ||||
|      PRESHIFT(0x007a0000) /*  0.029785156 */, | ||||
|     -PRESHIFT(0x016f7000) /* -0.089706421 */, | ||||
|      PRESHIFT(0x014a8000) /*  0.080688477 */, | ||||
|     -PRESHIFT(0x0a0d8000) /* -0.628295898 */, | ||||
|      PRESHIFT(0x12468000) /*  1.142211914 */, | ||||
|      PRESHIFT(0x083ff000) /*  0.515609741 */, | ||||
|      PRESHIFT(0x01dd8000) /*  0.116577148 */, | ||||
|      PRESHIFT(0x01149000) /*  0.067520142 */, | ||||
|      PRESHIFT(0x00820000) /*  0.031738281 */, | ||||
|      PRESHIFT(0x0015b000) /*  0.005294800 */, | ||||
|      PRESHIFT(0x000ca000) /*  0.003082275 */, | ||||
|      PRESHIFT(0x00018000) /*  0.000366211 */, | ||||
|  | ||||
|     -PRESHIFT(0x00001000) /* -0.000015259 */, | ||||
|     -PRESHIFT(0x00023000) /* -0.000534058 */, | ||||
|      PRESHIFT(0x000de000) /*  0.003387451 */, | ||||
|     -PRESHIFT(0x00245000) /* -0.008865356 */, | ||||
|      PRESHIFT(0x007a0000) /*  0.029785156 */, | ||||
|     -PRESHIFT(0x016f7000) /* -0.089706421 */, | ||||
|      PRESHIFT(0x014a8000) /*  0.080688477 */, | ||||
|     -PRESHIFT(0x0a0d8000) /* -0.628295898 */, | ||||
|      PRESHIFT(0x12468000) /*  1.142211914 */, | ||||
|      PRESHIFT(0x083ff000) /*  0.515609741 */, | ||||
|      PRESHIFT(0x01dd8000) /*  0.116577148 */, | ||||
|      PRESHIFT(0x01149000) /*  0.067520142 */, | ||||
|      PRESHIFT(0x00820000) /*  0.031738281 */, | ||||
|      PRESHIFT(0x0015b000) /*  0.005294800 */, | ||||
|      PRESHIFT(0x000ca000) /*  0.003082275 */, | ||||
|      PRESHIFT(0x00018000) /*  0.000366211 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  3 */ | ||||
|     -PRESHIFT(0x00026000) /* -0.000579834 */, | ||||
|      PRESHIFT(0x000e1000) /*  0.003433228 */, | ||||
|     -PRESHIFT(0x00285000) /* -0.009841919 */, | ||||
|      PRESHIFT(0x00765000) /*  0.028884888 */, | ||||
|     -PRESHIFT(0x0185d000) /* -0.095169067 */, | ||||
|      PRESHIFT(0x011d1000) /*  0.069595337 */, | ||||
|     -PRESHIFT(0x0a7fe000) /* -0.656219482 */, | ||||
|      PRESHIFT(0x12386000) /*  1.138763428 */, | ||||
|      PRESHIFT(0x07ccb000) /*  0.487472534 */, | ||||
|      PRESHIFT(0x01f9c000) /*  0.123474121 */, | ||||
|      PRESHIFT(0x00fdf000) /*  0.061996460 */, | ||||
|      PRESHIFT(0x00827000) /*  0.031845093 */, | ||||
|      PRESHIFT(0x00126000) /*  0.004486084 */, | ||||
|      PRESHIFT(0x000c4000) /*  0.002990723 */, | ||||
|      PRESHIFT(0x00015000) /*  0.000320435 */, | ||||
|  | ||||
|     -PRESHIFT(0x00001000) /* -0.000015259 */, | ||||
|     -PRESHIFT(0x00026000) /* -0.000579834 */, | ||||
|      PRESHIFT(0x000e1000) /*  0.003433228 */, | ||||
|     -PRESHIFT(0x00285000) /* -0.009841919 */, | ||||
|      PRESHIFT(0x00765000) /*  0.028884888 */, | ||||
|     -PRESHIFT(0x0185d000) /* -0.095169067 */, | ||||
|      PRESHIFT(0x011d1000) /*  0.069595337 */, | ||||
|     -PRESHIFT(0x0a7fe000) /* -0.656219482 */, | ||||
|      PRESHIFT(0x12386000) /*  1.138763428 */, | ||||
|      PRESHIFT(0x07ccb000) /*  0.487472534 */, | ||||
|      PRESHIFT(0x01f9c000) /*  0.123474121 */, | ||||
|      PRESHIFT(0x00fdf000) /*  0.061996460 */, | ||||
|      PRESHIFT(0x00827000) /*  0.031845093 */, | ||||
|      PRESHIFT(0x00126000) /*  0.004486084 */, | ||||
|      PRESHIFT(0x000c4000) /*  0.002990723 */, | ||||
|      PRESHIFT(0x00015000) /*  0.000320435 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  4 */ | ||||
|     -PRESHIFT(0x00029000) /* -0.000625610 */, | ||||
|      PRESHIFT(0x000e3000) /*  0.003463745 */, | ||||
|     -PRESHIFT(0x002c7000) /* -0.010848999 */, | ||||
|      PRESHIFT(0x0071e000) /*  0.027801514 */, | ||||
|     -PRESHIFT(0x019bd000) /* -0.100540161 */, | ||||
|      PRESHIFT(0x00ec0000) /*  0.057617187 */, | ||||
|     -PRESHIFT(0x0af15000) /* -0.683914185 */, | ||||
|      PRESHIFT(0x12249000) /*  1.133926392 */, | ||||
|      PRESHIFT(0x075a0000) /*  0.459472656 */, | ||||
|      PRESHIFT(0x0212c000) /*  0.129577637 */, | ||||
|      PRESHIFT(0x00e79000) /*  0.056533813 */, | ||||
|      PRESHIFT(0x00825000) /*  0.031814575 */, | ||||
|      PRESHIFT(0x000f4000) /*  0.003723145 */, | ||||
|      PRESHIFT(0x000be000) /*  0.002899170 */, | ||||
|      PRESHIFT(0x00013000) /*  0.000289917 */, | ||||
|  | ||||
|     -PRESHIFT(0x00001000) /* -0.000015259 */, | ||||
|     -PRESHIFT(0x00029000) /* -0.000625610 */, | ||||
|      PRESHIFT(0x000e3000) /*  0.003463745 */, | ||||
|     -PRESHIFT(0x002c7000) /* -0.010848999 */, | ||||
|      PRESHIFT(0x0071e000) /*  0.027801514 */, | ||||
|     -PRESHIFT(0x019bd000) /* -0.100540161 */, | ||||
|      PRESHIFT(0x00ec0000) /*  0.057617187 */, | ||||
|     -PRESHIFT(0x0af15000) /* -0.683914185 */, | ||||
|      PRESHIFT(0x12249000) /*  1.133926392 */, | ||||
|      PRESHIFT(0x075a0000) /*  0.459472656 */, | ||||
|      PRESHIFT(0x0212c000) /*  0.129577637 */, | ||||
|      PRESHIFT(0x00e79000) /*  0.056533813 */, | ||||
|      PRESHIFT(0x00825000) /*  0.031814575 */, | ||||
|      PRESHIFT(0x000f4000) /*  0.003723145 */, | ||||
|      PRESHIFT(0x000be000) /*  0.002899170 */, | ||||
|      PRESHIFT(0x00013000) /*  0.000289917 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  5 */ | ||||
|     -PRESHIFT(0x0002d000) /* -0.000686646 */, | ||||
|      PRESHIFT(0x000e4000) /*  0.003479004 */, | ||||
|     -PRESHIFT(0x0030b000) /* -0.011886597 */, | ||||
|      PRESHIFT(0x006cb000) /*  0.026535034 */, | ||||
|     -PRESHIFT(0x01b17000) /* -0.105819702 */, | ||||
|      PRESHIFT(0x00b77000) /*  0.044784546 */, | ||||
|     -PRESHIFT(0x0b619000) /* -0.711318970 */, | ||||
|      PRESHIFT(0x120b4000) /*  1.127746582 */, | ||||
|      PRESHIFT(0x06e81000) /*  0.431655884 */, | ||||
|      PRESHIFT(0x02288000) /*  0.134887695 */, | ||||
|      PRESHIFT(0x00d17000) /*  0.051132202 */, | ||||
|      PRESHIFT(0x0081b000) /*  0.031661987 */, | ||||
|      PRESHIFT(0x000c5000) /*  0.003005981 */, | ||||
|      PRESHIFT(0x000b7000) /*  0.002792358 */, | ||||
|      PRESHIFT(0x00011000) /*  0.000259399 */, | ||||
|  | ||||
|     -PRESHIFT(0x00001000) /* -0.000015259 */, | ||||
|     -PRESHIFT(0x0002d000) /* -0.000686646 */, | ||||
|      PRESHIFT(0x000e4000) /*  0.003479004 */, | ||||
|     -PRESHIFT(0x0030b000) /* -0.011886597 */, | ||||
|      PRESHIFT(0x006cb000) /*  0.026535034 */, | ||||
|     -PRESHIFT(0x01b17000) /* -0.105819702 */, | ||||
|      PRESHIFT(0x00b77000) /*  0.044784546 */, | ||||
|     -PRESHIFT(0x0b619000) /* -0.711318970 */, | ||||
|      PRESHIFT(0x120b4000) /*  1.127746582 */, | ||||
|      PRESHIFT(0x06e81000) /*  0.431655884 */, | ||||
|      PRESHIFT(0x02288000) /*  0.134887695 */, | ||||
|      PRESHIFT(0x00d17000) /*  0.051132202 */, | ||||
|      PRESHIFT(0x0081b000) /*  0.031661987 */, | ||||
|      PRESHIFT(0x000c5000) /*  0.003005981 */, | ||||
|      PRESHIFT(0x000b7000) /*  0.002792358 */, | ||||
|      PRESHIFT(0x00011000) /*  0.000259399 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  6 */ | ||||
|     -PRESHIFT(0x00031000) /* -0.000747681 */, | ||||
|      PRESHIFT(0x000e4000) /*  0.003479004 */, | ||||
|     -PRESHIFT(0x00350000) /* -0.012939453 */, | ||||
|      PRESHIFT(0x0066c000) /*  0.025085449 */, | ||||
|     -PRESHIFT(0x01c67000) /* -0.110946655 */, | ||||
|      PRESHIFT(0x007f5000) /*  0.031082153 */, | ||||
|     -PRESHIFT(0x0bd06000) /* -0.738372803 */, | ||||
|      PRESHIFT(0x11ec7000) /*  1.120223999 */, | ||||
|      PRESHIFT(0x06772000) /*  0.404083252 */, | ||||
|      PRESHIFT(0x023b3000) /*  0.139450073 */, | ||||
|      PRESHIFT(0x00bbc000) /*  0.045837402 */, | ||||
|      PRESHIFT(0x00809000) /*  0.031387329 */, | ||||
|      PRESHIFT(0x00099000) /*  0.002334595 */, | ||||
|      PRESHIFT(0x000b0000) /*  0.002685547 */, | ||||
|      PRESHIFT(0x00010000) /*  0.000244141 */, | ||||
|  | ||||
|     -PRESHIFT(0x00001000) /* -0.000015259 */, | ||||
|     -PRESHIFT(0x00031000) /* -0.000747681 */, | ||||
|      PRESHIFT(0x000e4000) /*  0.003479004 */, | ||||
|     -PRESHIFT(0x00350000) /* -0.012939453 */, | ||||
|      PRESHIFT(0x0066c000) /*  0.025085449 */, | ||||
|     -PRESHIFT(0x01c67000) /* -0.110946655 */, | ||||
|      PRESHIFT(0x007f5000) /*  0.031082153 */, | ||||
|     -PRESHIFT(0x0bd06000) /* -0.738372803 */, | ||||
|      PRESHIFT(0x11ec7000) /*  1.120223999 */, | ||||
|      PRESHIFT(0x06772000) /*  0.404083252 */, | ||||
|      PRESHIFT(0x023b3000) /*  0.139450073 */, | ||||
|      PRESHIFT(0x00bbc000) /*  0.045837402 */, | ||||
|      PRESHIFT(0x00809000) /*  0.031387329 */, | ||||
|      PRESHIFT(0x00099000) /*  0.002334595 */, | ||||
|      PRESHIFT(0x000b0000) /*  0.002685547 */, | ||||
|      PRESHIFT(0x00010000) /*  0.000244141 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00002000) /* -0.000030518 */,	/*  7 */ | ||||
|     -PRESHIFT(0x00035000) /* -0.000808716 */, | ||||
|      PRESHIFT(0x000e3000) /*  0.003463745 */, | ||||
|     -PRESHIFT(0x00397000) /* -0.014022827 */, | ||||
|      PRESHIFT(0x005ff000) /*  0.023422241 */, | ||||
|     -PRESHIFT(0x01dad000) /* -0.115921021 */, | ||||
|      PRESHIFT(0x0043a000) /*  0.016510010 */, | ||||
|     -PRESHIFT(0x0c3d9000) /* -0.765029907 */, | ||||
|      PRESHIFT(0x11c83000) /*  1.111373901 */, | ||||
|      PRESHIFT(0x06076000) /*  0.376800537 */, | ||||
|      PRESHIFT(0x024ad000) /*  0.143264771 */, | ||||
|      PRESHIFT(0x00a67000) /*  0.040634155 */, | ||||
|      PRESHIFT(0x007f0000) /*  0.031005859 */, | ||||
|      PRESHIFT(0x0006f000) /*  0.001693726 */, | ||||
|      PRESHIFT(0x000a9000) /*  0.002578735 */, | ||||
|      PRESHIFT(0x0000e000) /*  0.000213623 */, | ||||
|  | ||||
|     -PRESHIFT(0x00002000) /* -0.000030518 */, | ||||
|     -PRESHIFT(0x00035000) /* -0.000808716 */, | ||||
|      PRESHIFT(0x000e3000) /*  0.003463745 */, | ||||
|     -PRESHIFT(0x00397000) /* -0.014022827 */, | ||||
|      PRESHIFT(0x005ff000) /*  0.023422241 */, | ||||
|     -PRESHIFT(0x01dad000) /* -0.115921021 */, | ||||
|      PRESHIFT(0x0043a000) /*  0.016510010 */, | ||||
|     -PRESHIFT(0x0c3d9000) /* -0.765029907 */, | ||||
|      PRESHIFT(0x11c83000) /*  1.111373901 */, | ||||
|      PRESHIFT(0x06076000) /*  0.376800537 */, | ||||
|      PRESHIFT(0x024ad000) /*  0.143264771 */, | ||||
|      PRESHIFT(0x00a67000) /*  0.040634155 */, | ||||
|      PRESHIFT(0x007f0000) /*  0.031005859 */, | ||||
|      PRESHIFT(0x0006f000) /*  0.001693726 */, | ||||
|      PRESHIFT(0x000a9000) /*  0.002578735 */, | ||||
|      PRESHIFT(0x0000e000) /*  0.000213623 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00002000) /* -0.000030518 */,	/*  8 */ | ||||
|     -PRESHIFT(0x0003a000) /* -0.000885010 */, | ||||
|      PRESHIFT(0x000e0000) /*  0.003417969 */, | ||||
|     -PRESHIFT(0x003df000) /* -0.015121460 */, | ||||
|      PRESHIFT(0x00586000) /*  0.021575928 */, | ||||
|     -PRESHIFT(0x01ee6000) /* -0.120697021 */, | ||||
|      PRESHIFT(0x00046000) /*  0.001068115 */, | ||||
|     -PRESHIFT(0x0ca8d000) /* -0.791213989 */, | ||||
|      PRESHIFT(0x119e9000) /*  1.101211548 */, | ||||
|      PRESHIFT(0x05991000) /*  0.349868774 */, | ||||
|      PRESHIFT(0x02578000) /*  0.146362305 */, | ||||
|      PRESHIFT(0x0091a000) /*  0.035552979 */, | ||||
|      PRESHIFT(0x007d1000) /*  0.030532837 */, | ||||
|      PRESHIFT(0x00048000) /*  0.001098633 */, | ||||
|      PRESHIFT(0x000a1000) /*  0.002456665 */, | ||||
|      PRESHIFT(0x0000d000) /*  0.000198364 */, | ||||
|  | ||||
|     -PRESHIFT(0x00002000) /* -0.000030518 */, | ||||
|     -PRESHIFT(0x0003a000) /* -0.000885010 */, | ||||
|      PRESHIFT(0x000e0000) /*  0.003417969 */, | ||||
|     -PRESHIFT(0x003df000) /* -0.015121460 */, | ||||
|      PRESHIFT(0x00586000) /*  0.021575928 */, | ||||
|     -PRESHIFT(0x01ee6000) /* -0.120697021 */, | ||||
|      PRESHIFT(0x00046000) /*  0.001068115 */, | ||||
|     -PRESHIFT(0x0ca8d000) /* -0.791213989 */, | ||||
|      PRESHIFT(0x119e9000) /*  1.101211548 */, | ||||
|      PRESHIFT(0x05991000) /*  0.349868774 */, | ||||
|      PRESHIFT(0x02578000) /*  0.146362305 */, | ||||
|      PRESHIFT(0x0091a000) /*  0.035552979 */, | ||||
|      PRESHIFT(0x007d1000) /*  0.030532837 */, | ||||
|      PRESHIFT(0x00048000) /*  0.001098633 */, | ||||
|      PRESHIFT(0x000a1000) /*  0.002456665 */, | ||||
|      PRESHIFT(0x0000d000) /*  0.000198364 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00002000) /* -0.000030518 */,	/*  9 */ | ||||
|     -PRESHIFT(0x0003f000) /* -0.000961304 */, | ||||
|      PRESHIFT(0x000dd000) /*  0.003372192 */, | ||||
|     -PRESHIFT(0x00428000) /* -0.016235352 */, | ||||
|      PRESHIFT(0x00500000) /*  0.019531250 */, | ||||
|     -PRESHIFT(0x02011000) /* -0.125259399 */, | ||||
|     -PRESHIFT(0x003e6000) /* -0.015228271 */, | ||||
|     -PRESHIFT(0x0d11e000) /* -0.816864014 */, | ||||
|      PRESHIFT(0x116fc000) /*  1.089782715 */, | ||||
|      PRESHIFT(0x052c5000) /*  0.323318481 */, | ||||
|      PRESHIFT(0x02616000) /*  0.148773193 */, | ||||
|      PRESHIFT(0x007d6000) /*  0.030609131 */, | ||||
|      PRESHIFT(0x007aa000) /*  0.029937744 */, | ||||
|      PRESHIFT(0x00024000) /*  0.000549316 */, | ||||
|      PRESHIFT(0x0009a000) /*  0.002349854 */, | ||||
|      PRESHIFT(0x0000b000) /*  0.000167847 */, | ||||
|  | ||||
|     -PRESHIFT(0x00002000) /* -0.000030518 */, | ||||
|     -PRESHIFT(0x0003f000) /* -0.000961304 */, | ||||
|      PRESHIFT(0x000dd000) /*  0.003372192 */, | ||||
|     -PRESHIFT(0x00428000) /* -0.016235352 */, | ||||
|      PRESHIFT(0x00500000) /*  0.019531250 */, | ||||
|     -PRESHIFT(0x02011000) /* -0.125259399 */, | ||||
|     -PRESHIFT(0x003e6000) /* -0.015228271 */, | ||||
|     -PRESHIFT(0x0d11e000) /* -0.816864014 */, | ||||
|      PRESHIFT(0x116fc000) /*  1.089782715 */, | ||||
|      PRESHIFT(0x052c5000) /*  0.323318481 */, | ||||
|      PRESHIFT(0x02616000) /*  0.148773193 */, | ||||
|      PRESHIFT(0x007d6000) /*  0.030609131 */, | ||||
|      PRESHIFT(0x007aa000) /*  0.029937744 */, | ||||
|      PRESHIFT(0x00024000) /*  0.000549316 */, | ||||
|      PRESHIFT(0x0009a000) /*  0.002349854 */, | ||||
|      PRESHIFT(0x0000b000) /*  0.000167847 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00002000) /* -0.000030518 */,	/* 10 */ | ||||
|     -PRESHIFT(0x00044000) /* -0.001037598 */, | ||||
|      PRESHIFT(0x000d7000) /*  0.003280640 */, | ||||
|     -PRESHIFT(0x00471000) /* -0.017349243 */, | ||||
|      PRESHIFT(0x0046b000) /*  0.017257690 */, | ||||
|     -PRESHIFT(0x0212b000) /* -0.129562378 */, | ||||
|     -PRESHIFT(0x0084a000) /* -0.032379150 */, | ||||
|     -PRESHIFT(0x0d78a000) /* -0.841949463 */, | ||||
|      PRESHIFT(0x113be000) /*  1.077117920 */, | ||||
|      PRESHIFT(0x04c16000) /*  0.297210693 */, | ||||
|      PRESHIFT(0x02687000) /*  0.150497437 */, | ||||
|      PRESHIFT(0x0069c000) /*  0.025817871 */, | ||||
|      PRESHIFT(0x0077f000) /*  0.029281616 */, | ||||
|      PRESHIFT(0x00002000) /*  0.000030518 */, | ||||
|      PRESHIFT(0x00093000) /*  0.002243042 */, | ||||
|      PRESHIFT(0x0000a000) /*  0.000152588 */, | ||||
|  | ||||
|     -PRESHIFT(0x00002000) /* -0.000030518 */, | ||||
|     -PRESHIFT(0x00044000) /* -0.001037598 */, | ||||
|      PRESHIFT(0x000d7000) /*  0.003280640 */, | ||||
|     -PRESHIFT(0x00471000) /* -0.017349243 */, | ||||
|      PRESHIFT(0x0046b000) /*  0.017257690 */, | ||||
|     -PRESHIFT(0x0212b000) /* -0.129562378 */, | ||||
|     -PRESHIFT(0x0084a000) /* -0.032379150 */, | ||||
|     -PRESHIFT(0x0d78a000) /* -0.841949463 */, | ||||
|      PRESHIFT(0x113be000) /*  1.077117920 */, | ||||
|      PRESHIFT(0x04c16000) /*  0.297210693 */, | ||||
|      PRESHIFT(0x02687000) /*  0.150497437 */, | ||||
|      PRESHIFT(0x0069c000) /*  0.025817871 */, | ||||
|      PRESHIFT(0x0077f000) /*  0.029281616 */, | ||||
|      PRESHIFT(0x00002000) /*  0.000030518 */, | ||||
|      PRESHIFT(0x00093000) /*  0.002243042 */, | ||||
|      PRESHIFT(0x0000a000) /*  0.000152588 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00003000) /* -0.000045776 */,	/* 11 */ | ||||
|     -PRESHIFT(0x00049000) /* -0.001113892 */, | ||||
|      PRESHIFT(0x000d0000) /*  0.003173828 */, | ||||
|     -PRESHIFT(0x004ba000) /* -0.018463135 */, | ||||
|      PRESHIFT(0x003ca000) /*  0.014801025 */, | ||||
|     -PRESHIFT(0x02233000) /* -0.133590698 */, | ||||
|     -PRESHIFT(0x00ce4000) /* -0.050354004 */, | ||||
|     -PRESHIFT(0x0ddca000) /* -0.866363525 */, | ||||
|      PRESHIFT(0x1102f000) /*  1.063217163 */, | ||||
|      PRESHIFT(0x04587000) /*  0.271591187 */, | ||||
|      PRESHIFT(0x026cf000) /*  0.151596069 */, | ||||
|      PRESHIFT(0x0056c000) /*  0.021179199 */, | ||||
|      PRESHIFT(0x0074e000) /*  0.028533936 */, | ||||
|     -PRESHIFT(0x0001d000) /* -0.000442505 */, | ||||
|      PRESHIFT(0x0008b000) /*  0.002120972 */, | ||||
|      PRESHIFT(0x00009000) /*  0.000137329 */, | ||||
|  | ||||
|     -PRESHIFT(0x00003000) /* -0.000045776 */, | ||||
|     -PRESHIFT(0x00049000) /* -0.001113892 */, | ||||
|      PRESHIFT(0x000d0000) /*  0.003173828 */, | ||||
|     -PRESHIFT(0x004ba000) /* -0.018463135 */, | ||||
|      PRESHIFT(0x003ca000) /*  0.014801025 */, | ||||
|     -PRESHIFT(0x02233000) /* -0.133590698 */, | ||||
|     -PRESHIFT(0x00ce4000) /* -0.050354004 */, | ||||
|     -PRESHIFT(0x0ddca000) /* -0.866363525 */, | ||||
|      PRESHIFT(0x1102f000) /*  1.063217163 */, | ||||
|      PRESHIFT(0x04587000) /*  0.271591187 */, | ||||
|      PRESHIFT(0x026cf000) /*  0.151596069 */, | ||||
|      PRESHIFT(0x0056c000) /*  0.021179199 */, | ||||
|      PRESHIFT(0x0074e000) /*  0.028533936 */, | ||||
|     -PRESHIFT(0x0001d000) /* -0.000442505 */, | ||||
|      PRESHIFT(0x0008b000) /*  0.002120972 */, | ||||
|      PRESHIFT(0x00009000) /*  0.000137329 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00003000) /* -0.000045776 */,	/* 12 */ | ||||
|     -PRESHIFT(0x0004f000) /* -0.001205444 */, | ||||
|      PRESHIFT(0x000c8000) /*  0.003051758 */, | ||||
|     -PRESHIFT(0x00503000) /* -0.019577026 */, | ||||
|      PRESHIFT(0x0031a000) /*  0.012115479 */, | ||||
|     -PRESHIFT(0x02326000) /* -0.137298584 */, | ||||
|     -PRESHIFT(0x011b5000) /* -0.069168091 */, | ||||
|     -PRESHIFT(0x0e3dd000) /* -0.890090942 */, | ||||
|      PRESHIFT(0x10c54000) /*  1.048156738 */, | ||||
|      PRESHIFT(0x03f1b000) /*  0.246505737 */, | ||||
|      PRESHIFT(0x026ee000) /*  0.152069092 */, | ||||
|      PRESHIFT(0x00447000) /*  0.016708374 */, | ||||
|      PRESHIFT(0x00719000) /*  0.027725220 */, | ||||
|     -PRESHIFT(0x00039000) /* -0.000869751 */, | ||||
|      PRESHIFT(0x00084000) /*  0.002014160 */, | ||||
|      PRESHIFT(0x00008000) /*  0.000122070 */, | ||||
|  | ||||
|     -PRESHIFT(0x00003000) /* -0.000045776 */, | ||||
|     -PRESHIFT(0x0004f000) /* -0.001205444 */, | ||||
|      PRESHIFT(0x000c8000) /*  0.003051758 */, | ||||
|     -PRESHIFT(0x00503000) /* -0.019577026 */, | ||||
|      PRESHIFT(0x0031a000) /*  0.012115479 */, | ||||
|     -PRESHIFT(0x02326000) /* -0.137298584 */, | ||||
|     -PRESHIFT(0x011b5000) /* -0.069168091 */, | ||||
|     -PRESHIFT(0x0e3dd000) /* -0.890090942 */, | ||||
|      PRESHIFT(0x10c54000) /*  1.048156738 */, | ||||
|      PRESHIFT(0x03f1b000) /*  0.246505737 */, | ||||
|      PRESHIFT(0x026ee000) /*  0.152069092 */, | ||||
|      PRESHIFT(0x00447000) /*  0.016708374 */, | ||||
|      PRESHIFT(0x00719000) /*  0.027725220 */, | ||||
|     -PRESHIFT(0x00039000) /* -0.000869751 */, | ||||
|      PRESHIFT(0x00084000) /*  0.002014160 */, | ||||
|      PRESHIFT(0x00008000) /*  0.000122070 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00004000) /* -0.000061035 */,	/* 13 */ | ||||
|     -PRESHIFT(0x00055000) /* -0.001296997 */, | ||||
|      PRESHIFT(0x000bd000) /*  0.002883911 */, | ||||
|     -PRESHIFT(0x0054c000) /* -0.020690918 */, | ||||
|      PRESHIFT(0x0025d000) /*  0.009231567 */, | ||||
|     -PRESHIFT(0x02403000) /* -0.140670776 */, | ||||
|     -PRESHIFT(0x016ba000) /* -0.088775635 */, | ||||
|     -PRESHIFT(0x0e9be000) /* -0.913055420 */, | ||||
|      PRESHIFT(0x1082d000) /*  1.031936646 */, | ||||
|      PRESHIFT(0x038d4000) /*  0.221984863 */, | ||||
|      PRESHIFT(0x026e7000) /*  0.151962280 */, | ||||
|      PRESHIFT(0x0032e000) /*  0.012420654 */, | ||||
|      PRESHIFT(0x006df000) /*  0.026840210 */, | ||||
|     -PRESHIFT(0x00053000) /* -0.001266479 */, | ||||
|      PRESHIFT(0x0007d000) /*  0.001907349 */, | ||||
|      PRESHIFT(0x00007000) /*  0.000106812 */, | ||||
|  | ||||
|     -PRESHIFT(0x00004000) /* -0.000061035 */, | ||||
|     -PRESHIFT(0x00055000) /* -0.001296997 */, | ||||
|      PRESHIFT(0x000bd000) /*  0.002883911 */, | ||||
|     -PRESHIFT(0x0054c000) /* -0.020690918 */, | ||||
|      PRESHIFT(0x0025d000) /*  0.009231567 */, | ||||
|     -PRESHIFT(0x02403000) /* -0.140670776 */, | ||||
|     -PRESHIFT(0x016ba000) /* -0.088775635 */, | ||||
|     -PRESHIFT(0x0e9be000) /* -0.913055420 */, | ||||
|      PRESHIFT(0x1082d000) /*  1.031936646 */, | ||||
|      PRESHIFT(0x038d4000) /*  0.221984863 */, | ||||
|      PRESHIFT(0x026e7000) /*  0.151962280 */, | ||||
|      PRESHIFT(0x0032e000) /*  0.012420654 */, | ||||
|      PRESHIFT(0x006df000) /*  0.026840210 */, | ||||
|     -PRESHIFT(0x00053000) /* -0.001266479 */, | ||||
|      PRESHIFT(0x0007d000) /*  0.001907349 */, | ||||
|      PRESHIFT(0x00007000) /*  0.000106812 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00004000) /* -0.000061035 */,	/* 14 */ | ||||
|     -PRESHIFT(0x0005b000) /* -0.001388550 */, | ||||
|      PRESHIFT(0x000b1000) /*  0.002700806 */, | ||||
|     -PRESHIFT(0x00594000) /* -0.021789551 */, | ||||
|      PRESHIFT(0x00192000) /*  0.006134033 */, | ||||
|     -PRESHIFT(0x024c8000) /* -0.143676758 */, | ||||
|     -PRESHIFT(0x01bf2000) /* -0.109161377 */, | ||||
|     -PRESHIFT(0x0ef69000) /* -0.935195923 */, | ||||
|      PRESHIFT(0x103be000) /*  1.014617920 */, | ||||
|      PRESHIFT(0x032b4000) /*  0.198059082 */, | ||||
|      PRESHIFT(0x026bc000) /*  0.151306152 */, | ||||
|      PRESHIFT(0x00221000) /*  0.008316040 */, | ||||
|      PRESHIFT(0x006a2000) /*  0.025909424 */, | ||||
|     -PRESHIFT(0x0006a000) /* -0.001617432 */, | ||||
|      PRESHIFT(0x00075000) /*  0.001785278 */, | ||||
|      PRESHIFT(0x00007000) /*  0.000106812 */, | ||||
|  | ||||
|     -PRESHIFT(0x00004000) /* -0.000061035 */, | ||||
|     -PRESHIFT(0x0005b000) /* -0.001388550 */, | ||||
|      PRESHIFT(0x000b1000) /*  0.002700806 */, | ||||
|     -PRESHIFT(0x00594000) /* -0.021789551 */, | ||||
|      PRESHIFT(0x00192000) /*  0.006134033 */, | ||||
|     -PRESHIFT(0x024c8000) /* -0.143676758 */, | ||||
|     -PRESHIFT(0x01bf2000) /* -0.109161377 */, | ||||
|     -PRESHIFT(0x0ef69000) /* -0.935195923 */, | ||||
|      PRESHIFT(0x103be000) /*  1.014617920 */, | ||||
|      PRESHIFT(0x032b4000) /*  0.198059082 */, | ||||
|      PRESHIFT(0x026bc000) /*  0.151306152 */, | ||||
|      PRESHIFT(0x00221000) /*  0.008316040 */, | ||||
|      PRESHIFT(0x006a2000) /*  0.025909424 */, | ||||
|     -PRESHIFT(0x0006a000) /* -0.001617432 */, | ||||
|      PRESHIFT(0x00075000) /*  0.001785278 */, | ||||
|      PRESHIFT(0x00007000) /*  0.000106812 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00005000) /* -0.000076294 */,	/* 15 */ | ||||
|     -PRESHIFT(0x00061000) /* -0.001480103 */, | ||||
|      PRESHIFT(0x000a3000) /*  0.002487183 */, | ||||
|     -PRESHIFT(0x005da000) /* -0.022857666 */, | ||||
|      PRESHIFT(0x000b9000) /*  0.002822876 */, | ||||
|     -PRESHIFT(0x02571000) /* -0.146255493 */, | ||||
|     -PRESHIFT(0x0215c000) /* -0.130310059 */, | ||||
|     -PRESHIFT(0x0f4dc000) /* -0.956481934 */, | ||||
|      PRESHIFT(0x0ff0a000) /*  0.996246338 */, | ||||
|      PRESHIFT(0x02cbf000) /*  0.174789429 */, | ||||
|      PRESHIFT(0x0266e000) /*  0.150115967 */, | ||||
|      PRESHIFT(0x00120000) /*  0.004394531 */, | ||||
|      PRESHIFT(0x00662000) /*  0.024932861 */, | ||||
|     -PRESHIFT(0x0007f000) /* -0.001937866 */, | ||||
|      PRESHIFT(0x0006f000) /*  0.001693726 */, | ||||
|      PRESHIFT(0x00006000) /*  0.000091553 */, | ||||
|  | ||||
|     -PRESHIFT(0x00005000) /* -0.000076294 */, | ||||
|     -PRESHIFT(0x00061000) /* -0.001480103 */, | ||||
|      PRESHIFT(0x000a3000) /*  0.002487183 */, | ||||
|     -PRESHIFT(0x005da000) /* -0.022857666 */, | ||||
|      PRESHIFT(0x000b9000) /*  0.002822876 */, | ||||
|     -PRESHIFT(0x02571000) /* -0.146255493 */, | ||||
|     -PRESHIFT(0x0215c000) /* -0.130310059 */, | ||||
|     -PRESHIFT(0x0f4dc000) /* -0.956481934 */, | ||||
|      PRESHIFT(0x0ff0a000) /*  0.996246338 */, | ||||
|      PRESHIFT(0x02cbf000) /*  0.174789429 */, | ||||
|      PRESHIFT(0x0266e000) /*  0.150115967 */, | ||||
|      PRESHIFT(0x00120000) /*  0.004394531 */, | ||||
|      PRESHIFT(0x00662000) /*  0.024932861 */, | ||||
|     -PRESHIFT(0x0007f000) /* -0.001937866 */, | ||||
|      PRESHIFT(0x0006f000) /*  0.001693726 */, | ||||
|      PRESHIFT(0x00006000) /*  0.000091553 */ }, | ||||
|  | ||||
|   { -PRESHIFT(0x00005000) /* -0.000076294 */,	/* 16 */ | ||||
|     -PRESHIFT(0x00068000) /* -0.001586914 */, | ||||
|      PRESHIFT(0x00092000) /*  0.002227783 */, | ||||
|     -PRESHIFT(0x0061f000) /* -0.023910522 */, | ||||
|     -PRESHIFT(0x0002d000) /* -0.000686646 */, | ||||
|     -PRESHIFT(0x025ff000) /* -0.148422241 */, | ||||
|     -PRESHIFT(0x026f7000) /* -0.152206421 */, | ||||
|     -PRESHIFT(0x0fa13000) /* -0.976852417 */, | ||||
|      PRESHIFT(0x0fa13000) /*  0.976852417 */, | ||||
|      PRESHIFT(0x026f7000) /*  0.152206421 */, | ||||
|      PRESHIFT(0x025ff000) /*  0.148422241 */, | ||||
|      PRESHIFT(0x0002d000) /*  0.000686646 */, | ||||
|      PRESHIFT(0x0061f000) /*  0.023910522 */, | ||||
|     -PRESHIFT(0x00092000) /* -0.002227783 */, | ||||
|      PRESHIFT(0x00068000) /*  0.001586914 */, | ||||
|      PRESHIFT(0x00005000) /*  0.000076294 */, | ||||
|  | ||||
|     -PRESHIFT(0x00005000) /* -0.000076294 */, | ||||
|     -PRESHIFT(0x00068000) /* -0.001586914 */, | ||||
|      PRESHIFT(0x00092000) /*  0.002227783 */, | ||||
|     -PRESHIFT(0x0061f000) /* -0.023910522 */, | ||||
|     -PRESHIFT(0x0002d000) /* -0.000686646 */, | ||||
|     -PRESHIFT(0x025ff000) /* -0.148422241 */, | ||||
|     -PRESHIFT(0x026f7000) /* -0.152206421 */, | ||||
|     -PRESHIFT(0x0fa13000) /* -0.976852417 */, | ||||
|      PRESHIFT(0x0fa13000) /*  0.976852417 */, | ||||
|      PRESHIFT(0x026f7000) /*  0.152206421 */, | ||||
|      PRESHIFT(0x025ff000) /*  0.148422241 */, | ||||
|      PRESHIFT(0x0002d000) /*  0.000686646 */, | ||||
|      PRESHIFT(0x0061f000) /*  0.023910522 */, | ||||
|     -PRESHIFT(0x00092000) /* -0.002227783 */, | ||||
|      PRESHIFT(0x00068000) /*  0.001586914 */, | ||||
|      PRESHIFT(0x00005000) /*  0.000076294 */ } | ||||
							
								
								
									
										183
									
								
								src/libmad/INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/libmad/INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| Basic Installation | ||||
| ================== | ||||
|  | ||||
|    These are generic installation instructions. | ||||
|  | ||||
|    The `configure' shell script attempts to guess correct values for | ||||
| various system-dependent variables used during compilation.  It uses | ||||
| those values to create a `Makefile' in each directory of the package. | ||||
| It may also create one or more `.h' files containing system-dependent | ||||
| definitions.  Finally, it creates a shell script `config.status' that | ||||
| you can run in the future to recreate the current configuration, a file | ||||
| `config.cache' that saves the results of its tests to speed up | ||||
| reconfiguring, and a file `config.log' containing compiler output | ||||
| (useful mainly for debugging `configure'). | ||||
|  | ||||
|    If you need to do unusual things to compile the package, please try | ||||
| to figure out how `configure' could check whether to do them, and mail | ||||
| diffs or instructions to the address given in the `README' so they can | ||||
| be considered for the next release.  If at some point `config.cache' | ||||
| contains results you don't want to keep, you may remove or edit it. | ||||
|  | ||||
|    The file `configure.in' is used to create `configure' by a program | ||||
| called `autoconf'.  You only need `configure.in' if you want to change | ||||
| it or regenerate `configure' using a newer version of `autoconf'. | ||||
|  | ||||
| The simplest way to compile this package is: | ||||
|  | ||||
|   1. `cd' to the directory containing the package's source code and type | ||||
|      `./configure' to configure the package for your system.  If you're | ||||
|      using `csh' on an old version of System V, you might need to type | ||||
|      `sh ./configure' instead to prevent `csh' from trying to execute | ||||
|      `configure' itself. | ||||
|  | ||||
|      Running `configure' takes awhile.  While running, it prints some | ||||
|      messages telling which features it is checking for. | ||||
|  | ||||
|   2. Type `make' to compile the package. | ||||
|  | ||||
|   3. Optionally, type `make check' to run any self-tests that come with | ||||
|      the package. | ||||
|  | ||||
|   4. Type `make install' to install the programs and any data files and | ||||
|      documentation. | ||||
|  | ||||
|   5. You can remove the program binaries and object files from the | ||||
|      source code directory by typing `make clean'.  To also remove the | ||||
|      files that `configure' created (so you can compile the package for | ||||
|      a different kind of computer), type `make distclean'.  There is | ||||
|      also a `make maintainer-clean' target, but that is intended mainly | ||||
|      for the package's developers.  If you use it, you may have to get | ||||
|      all sorts of other programs in order to regenerate files that came | ||||
|      with the distribution. | ||||
|  | ||||
| Compilers and Options | ||||
| ===================== | ||||
|  | ||||
|    Some systems require unusual options for compilation or linking that | ||||
| the `configure' script does not know about.  You can give `configure' | ||||
| initial values for variables by setting them in the environment.  Using | ||||
| a Bourne-compatible shell, you can do that on the command line like | ||||
| this: | ||||
|      CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure | ||||
|  | ||||
| Or on systems that have the `env' program, you can do it like this: | ||||
|      env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure | ||||
|  | ||||
| Compiling For Multiple Architectures | ||||
| ==================================== | ||||
|  | ||||
|    You can compile the package for more than one kind of computer at the | ||||
| same time, by placing the object files for each architecture in their | ||||
| own directory.  To do this, you must use a version of `make' that | ||||
| supports the `VPATH' variable, such as GNU `make'.  `cd' to the | ||||
| directory where you want the object files and executables to go and run | ||||
| the `configure' script.  `configure' automatically checks for the | ||||
| source code in the directory that `configure' is in and in `..'. | ||||
|  | ||||
|    If you have to use a `make' that does not supports the `VPATH' | ||||
| variable, you have to compile the package for one architecture at a time | ||||
| in the source code directory.  After you have installed the package for | ||||
| one architecture, use `make distclean' before reconfiguring for another | ||||
| architecture. | ||||
|  | ||||
| Installation Names | ||||
| ================== | ||||
|  | ||||
|    By default, `make install' will install the package's files in | ||||
| `/usr/local/bin', `/usr/local/man', etc.  You can specify an | ||||
| installation prefix other than `/usr/local' by giving `configure' the | ||||
| option `--prefix=PATH'. | ||||
|  | ||||
|    You can specify separate installation prefixes for | ||||
| architecture-specific files and architecture-independent files.  If you | ||||
| give `configure' the option `--exec-prefix=PATH', the package will use | ||||
| PATH as the prefix for installing programs and libraries. | ||||
| Documentation and other data files will still use the regular prefix. | ||||
|  | ||||
|    In addition, if you use an unusual directory layout you can give | ||||
| options like `--bindir=PATH' to specify different values for particular | ||||
| kinds of files.  Run `configure --help' for a list of the directories | ||||
| you can set and what kinds of files go in them. | ||||
|  | ||||
|    If the package supports it, you can cause programs to be installed | ||||
| with an extra prefix or suffix on their names by giving `configure' the | ||||
| option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | ||||
|  | ||||
| Optional Features | ||||
| ================= | ||||
|  | ||||
|    Some packages pay attention to `--enable-FEATURE' options to | ||||
| `configure', where FEATURE indicates an optional part of the package. | ||||
| They may also pay attention to `--with-PACKAGE' options, where PACKAGE | ||||
| is something like `gnu-as' or `x' (for the X Window System).  The | ||||
| `README' should mention any `--enable-' and `--with-' options that the | ||||
| package recognizes. | ||||
|  | ||||
|    For packages that use the X Window System, `configure' can usually | ||||
| find the X include and library files automatically, but if it doesn't, | ||||
| you can use the `configure' options `--x-includes=DIR' and | ||||
| `--x-libraries=DIR' to specify their locations. | ||||
|  | ||||
| Specifying the System Type | ||||
| ========================== | ||||
|  | ||||
|    There may be some features `configure' can not figure out | ||||
| automatically, but needs to determine by the type of host the package | ||||
| will run on.  Usually `configure' can figure that out, but if it prints | ||||
| a message saying it can not guess the host type, give it the | ||||
| `--host=TYPE' option.  TYPE can either be a short name for the system | ||||
| type, such as `sun4', or a canonical name with three fields: | ||||
|      CPU-COMPANY-SYSTEM | ||||
|  | ||||
| See the file `config.sub' for the possible values of each field.  If | ||||
| `config.sub' isn't included in this package, then this package doesn't | ||||
| need to know the host type. | ||||
|  | ||||
|    If you are building compiler tools for cross-compiling, you can also | ||||
| use the `--target=TYPE' option to select the type of system they will | ||||
| produce code for and the `--build=TYPE' option to select the type of | ||||
| system on which you are compiling the package. | ||||
|  | ||||
| Sharing Defaults | ||||
| ================ | ||||
|  | ||||
|    If you want to set default values for `configure' scripts to share, | ||||
| you can create a site shell script called `config.site' that gives | ||||
| default values for variables like `CC', `cache_file', and `prefix'. | ||||
| `configure' looks for `PREFIX/share/config.site' if it exists, then | ||||
| `PREFIX/etc/config.site' if it exists.  Or, you can set the | ||||
| `CONFIG_SITE' environment variable to the location of the site script. | ||||
| A warning: not all `configure' scripts look for a site script. | ||||
|  | ||||
| Operation Controls | ||||
| ================== | ||||
|  | ||||
|    `configure' recognizes the following options to control how it | ||||
| operates. | ||||
|  | ||||
| `--cache-file=FILE' | ||||
|      Use and save the results of the tests in FILE instead of | ||||
|      `./config.cache'.  Set FILE to `/dev/null' to disable caching, for | ||||
|      debugging `configure'. | ||||
|  | ||||
| `--help' | ||||
|      Print a summary of the options to `configure', and exit. | ||||
|  | ||||
| `--quiet' | ||||
| `--silent' | ||||
| `-q' | ||||
|      Do not print messages saying which checks are being made.  To | ||||
|      suppress all normal output, redirect it to `/dev/null' (any error | ||||
|      messages will still be shown). | ||||
|  | ||||
| `--srcdir=DIR' | ||||
|      Look for the package's source code in directory DIR.  Usually | ||||
|      `configure' can determine that directory automatically. | ||||
|  | ||||
| `--version' | ||||
|      Print the version of Autoconf used to generate the `configure' | ||||
|      script, and exit. | ||||
|  | ||||
| `configure' also accepts some other, not widely useful, options. | ||||
|  | ||||
							
								
								
									
										140
									
								
								src/libmad/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/libmad/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| ## | ||||
| ## libmad - MPEG audio decoder library | ||||
| ## Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
| ## | ||||
| ## 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 | ||||
| ## | ||||
| ## $Id: Makefile.am,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
| ## | ||||
|  | ||||
| ## Process this file with automake to produce Makefile.in | ||||
|  | ||||
| SUBDIRS =		 | ||||
| #DIST_SUBDIRS =		msvc++ | ||||
|  | ||||
| noinst_LTLIBRARIES =	libmad.la | ||||
| noinst_HEADERS =	mad.h | ||||
|  | ||||
| EXTRA_PROGRAMS =	minimad | ||||
|  | ||||
| minimad_SOURCES =	minimad.c | ||||
| minimad_INCLUDES =	 | ||||
| minimad_LDADD =		libmad.la | ||||
|  | ||||
| EXTRA_DIST =		mad.h.sed  \ | ||||
| 			CHANGES COPYRIGHT CREDITS README TODO VERSION | ||||
|  | ||||
| exported_headers =	version.h fixed.h bit.h timer.h stream.h frame.h  \ | ||||
| 			synth.h decoder.h | ||||
|  | ||||
| headers =		$(exported_headers)  \ | ||||
| 			global.h layer12.h layer3.h huffman.h | ||||
|  | ||||
| data_includes =		D.dat imdct_s.dat qc_table.dat rq_table.dat  \ | ||||
| 			sf_table.dat | ||||
|  | ||||
| libmad_la_SOURCES =	version.c fixed.c bit.c timer.c stream.c frame.c  \ | ||||
| 			synth.c decoder.c layer12.c layer3.c huffman.c  \ | ||||
| 			$(headers) $(data_includes) | ||||
|  | ||||
| EXTRA_libmad_la_SOURCES =	imdct_l_arm.S #synth_mmx.S | ||||
|  | ||||
| libmad_la_DEPENDENCIES =	@ASO_OBJS@ | ||||
| libmad_la_LIBADD =		@ASO_OBJS@ | ||||
|  | ||||
| INCLUDES =		$(FPM) $(ASO) | ||||
|  | ||||
| BUILT_SOURCES =		mad.h | ||||
| CLEANFILES =		mad.h | ||||
|  | ||||
| ## From the libtool documentation on library versioning: | ||||
| ## | ||||
| ## CURRENT | ||||
| ##      The most recent interface number that this library implements. | ||||
| ## | ||||
| ## REVISION | ||||
| ##      The implementation number of the CURRENT interface. | ||||
| ## | ||||
| ## AGE | ||||
| ##      The difference between the newest and oldest interfaces that this | ||||
| ##      library implements.  In other words, the library implements all the | ||||
| ##      interface numbers in the range from number `CURRENT - AGE' to | ||||
| ##      `CURRENT'. | ||||
| ## | ||||
| ##    If two libraries have identical CURRENT and AGE numbers, then the | ||||
| ## dynamic linker chooses the library with the greater REVISION number. | ||||
| ## | ||||
| ##   1. Start with version information of `0:0:0' for each libtool library. | ||||
| ## | ||||
| ##   2. Update the version information only immediately before a public | ||||
| ##      release of your software.  More frequent updates are unnecessary, | ||||
| ##      and only guarantee that the current interface number gets larger | ||||
| ##      faster. | ||||
| ## | ||||
| ##   3. If the library source code has changed at all since the last | ||||
| ##      update, then increment REVISION (`C:R:A' becomes `C:r+1:A'). | ||||
| ## | ||||
| ##   4. If any interfaces have been added, removed, or changed since the | ||||
| ##      last update, increment CURRENT, and set REVISION to 0. | ||||
| ## | ||||
| ##   5. If any interfaces have been added since the last public release, | ||||
| ##      then increment AGE. | ||||
| ## | ||||
| ##   6. If any interfaces have been removed since the last public release, | ||||
| ##      then set AGE to 0. | ||||
|  | ||||
| version_current =	2 | ||||
| version_revision =	0 | ||||
| version_age =		2 | ||||
|  | ||||
| version_info =		$(version_current):$(version_revision):$(version_age) | ||||
|  | ||||
| libmad_la_LDFLAGS =	-version-info $(version_info) | ||||
|  | ||||
| mad.h: config.status config.h Makefile.am  \ | ||||
| 		$(srcdir)/COPYRIGHT $(srcdir)/mad.h.sed $(exported_headers) | ||||
| 	(sed -e '1s|.*|/*|' -e '1b' -e '$$s|.*| */|' -e '$$b'  \ | ||||
| 		-e 's/^.*/ *&/' $(srcdir)/COPYRIGHT; echo;  \ | ||||
| 	echo "# ifdef __cplusplus";  \ | ||||
| 	echo 'extern "C" {';  \ | ||||
| 	echo "# endif"; echo;  \ | ||||
| 	if [ ".$(FPM)" != "." ]; then  \ | ||||
| 		echo ".$(FPM)" | sed -e 's|^\.-D|# define |'; echo;  \ | ||||
| 	fi;  \ | ||||
| 	sed -ne 's/^# *define  *\(HAVE_.*_ASM\).*/# define \1/p'  \ | ||||
| 		config.h; echo;  \ | ||||
| 	sed -ne 's/^# *define  *OPT_\(SPEED\|ACCURACY\).*/# define OPT_\1/p'  \ | ||||
| 		config.h; echo;  \ | ||||
| 	sed -ne 's/^# *define  *\(SIZEOF_.*\)/# define \1/p'  \ | ||||
| 		config.h; echo;  \ | ||||
| 	for header in $(exported_headers); do  \ | ||||
| 		echo;  \ | ||||
| 		sed -n -f $(srcdir)/mad.h.sed $(srcdir)/$$header;  \ | ||||
| 	done; echo;  \ | ||||
| 	echo "# ifdef __cplusplus";  \ | ||||
| 	echo '}';  \ | ||||
| 	echo "# endif") >$@ | ||||
|  | ||||
| libtool: $(LIBTOOL_DEPS) | ||||
| 	$(SHELL) ./config.status --recheck | ||||
|  | ||||
| .c.s: | ||||
| 	$(COMPILE) -S $< | ||||
|  | ||||
| again: | ||||
| 	$(MAKE) clean | ||||
| 	$(MAKE) | ||||
|  | ||||
| .PHONY: again | ||||
							
								
								
									
										241
									
								
								src/libmad/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								src/libmad/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
|  | ||||
|  libmad - MPEG audio decoder library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: README,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| INTRODUCTION | ||||
|  | ||||
|   MAD (libmad) is a high-quality MPEG audio decoder. It currently supports | ||||
|   MPEG-1 and the MPEG-2 extension to Lower Sampling Frequencies, as well as | ||||
|   the so-called MPEG 2.5 format. All three audio layers (Layer I, Layer II, | ||||
|   and Layer III a.k.a. MP3) are fully implemented. | ||||
|  | ||||
|   MAD does not yet support MPEG-2 multichannel audio (although it should be | ||||
|   backward compatible with such streams) nor does it currently support AAC. | ||||
|  | ||||
|   MAD has the following special features: | ||||
|  | ||||
|     - 24-bit PCM output | ||||
|     - 100% fixed-point (integer) computation | ||||
|     - completely new implementation based on the ISO/IEC standards | ||||
|     - distributed under the terms of the GNU General Public License (GPL) | ||||
|  | ||||
|   Because MAD provides full 24-bit PCM output, applications using MAD are | ||||
|   able to produce high quality audio. Even when the output device supports | ||||
|   only 16-bit PCM, applications can use the extra resolution to increase the | ||||
|   audible dynamic range through the use of dithering or noise shaping. | ||||
|  | ||||
|   Because MAD uses integer computation rather than floating point, it is | ||||
|   well suited for architectures without a floating point unit. All | ||||
|   calculations are performed with a 32-bit fixed-point integer | ||||
|   representation. | ||||
|  | ||||
|   Because MAD is a new implementation of the ISO/IEC standards, it is | ||||
|   unencumbered by the errors of other implementations. MAD is NOT a | ||||
|   derivation of the ISO reference source or any other code. Considerable | ||||
|   effort has been expended to ensure a correct implementation, even in cases | ||||
|   where the standards are ambiguous or misleading. | ||||
|  | ||||
|   Because MAD is distributed under the terms of the GPL, its redistribution | ||||
|   is not generally restricted, so long as the terms of the GPL are followed. | ||||
|   This means MAD can be incorporated into other software as long as that | ||||
|   software is also distributed under the GPL. (Should this be undesirable, | ||||
|   alternate arrangements may be possible by contacting Underbit.) | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| ABOUT THE CODE | ||||
|  | ||||
|   The code is optimized and performs very well, although specific | ||||
|   improvements can still be made. The output from the decoder library | ||||
|   consists of 32-bit signed linear fixed-point values that can be easily | ||||
|   scaled for any size PCM output, up to 24 bits per sample. | ||||
|  | ||||
|   The API for libmad can be found in the `mad.h' header file. Note that this | ||||
|   file is automatically generated, and will not exist until after you have | ||||
|   built the library. | ||||
|  | ||||
|   There are two APIs available, one high-level, and the other low-level. | ||||
|   With the low-level API, each step of the decoding process must be handled | ||||
|   explicitly, offering the greatest amount of control. With the high-level | ||||
|   API, after callbacks are configured, a single routine will decode an | ||||
|   entire bitstream. | ||||
|  | ||||
|   The high-level API may either be used synchronously or asynchronously. If | ||||
|   used asynchronously, decoding will occur in a separate process. | ||||
|   Communication is possible with the decoding process by passing control | ||||
|   messages. | ||||
|  | ||||
|   The file `minimad.c' contains an example usage of the libmad API that | ||||
|   shows only the bare minimum required to implement a useful decoder. It | ||||
|   expects a regular file to be redirected to standard input, and it sends | ||||
|   decoded 16-bit signed little-endian PCM samples to standard output. If a | ||||
|   decoding error occurs, it is reported to standard error and decoding | ||||
|   continues. Note that the scale() routine in this code is only provided as | ||||
|   an example; it rounds MAD's high-resolution samples down to 16 bits, but | ||||
|   does not perform any dithering or noise shaping. It is therefore not | ||||
|   recommended to use this routine as-is in your own code if sound quality is | ||||
|   important. | ||||
|  | ||||
| Integer Performance | ||||
|  | ||||
|   To get the best possible performance, it is recommended that an assembly | ||||
|   version of the fixed-point multiply and related routines be selected. | ||||
|   Several such assembly routines have been written for various CPUs. | ||||
|  | ||||
|   If an assembly version is not available, a fast approximation version will | ||||
|   be used. This will result in reduced accuracy of the decoder. | ||||
|  | ||||
|   Alternatively, if 64-bit integers are supported as a datatype by the | ||||
|   compiler, another version can be used that is much more accurate. | ||||
|   However, using an assembly version is generally much faster and just as | ||||
|   accurate. | ||||
|  | ||||
|   More information can be gathered from the `fixed.h' header file. | ||||
|  | ||||
|   MAD's CPU-intensive subband synthesis routine can be further optimized at | ||||
|   the expense of a slight loss in output accuracy due to a modified method | ||||
|   for fixed-point multiplication with a small windowing constant. While this | ||||
|   is helpful for performance and the output accuracy loss is generally | ||||
|   undetectable, it is disabled by default and must be explicitly enabled. | ||||
|  | ||||
|   Under some architectures, other special optimizations may also be | ||||
|   available. | ||||
|  | ||||
| Audio Quality | ||||
|  | ||||
|   The output from MAD has been found to satisfy the ISO/IEC 11172-4 | ||||
|   computational accuracy requirements for compliance. In most | ||||
|   configurations, MAD is a Full Layer III ISO/IEC 11172-3 audio decoder as | ||||
|   defined by the standard. | ||||
|  | ||||
|   When the approximation version of the fixed-point multiply is used, MAD is | ||||
|   a limited accuracy ISO/IEC 11172-3 audio decoder as defined by the | ||||
|   standard. | ||||
|  | ||||
|   MAD can alternatively be configured to produce output with less or more | ||||
|   accuracy than the default, as a tradeoff with performance. | ||||
|  | ||||
|   MAD produces output samples with a precision greater than 24 bits. Because | ||||
|   most output formats use fewer bits, typically 16, it is recommended that a | ||||
|   dithering algorithm be used (rather than rounding or truncating) to obtain | ||||
|   the highest quality audio. However, dithering may unfavorably affect an | ||||
|   analytic examination of the output (such as compliance testing); you may | ||||
|   therefore wish to use rounding in this case instead. | ||||
|  | ||||
| Portability Issues | ||||
|  | ||||
|   GCC is preferred to compile the code, but other compilers may also work. | ||||
|   The assembly code in `fixed.h' depends on the inline assembly features of | ||||
|   your compiler. If you're not using GCC or MSVC++, you can either write | ||||
|   your own assembly macros or use the default (low quality output) version. | ||||
|  | ||||
|   The union initialization of `huffman.c' may not be portable to all | ||||
|   platforms when GCC is not used. | ||||
|  | ||||
|   The code should not be sensitive to word sizes or byte ordering, however | ||||
|   it does assume A % B has the same sign as A. | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| BUILDING AND INSTALLING | ||||
|  | ||||
| Windows Platforms | ||||
|  | ||||
|   MAD can be built under Windows using either MSVC++ or Cygwin. A MSVC++ | ||||
|   project file can be found under the `msvc++' subdirectory. | ||||
|  | ||||
|   To build libmad using Cygwin, you will first need to install the Cygwin | ||||
|   tools: | ||||
|  | ||||
|       http://www.cygwin.com/ | ||||
|  | ||||
|   You may then proceed with the following POSIX instructions within the | ||||
|   Cygwin shell. | ||||
|  | ||||
|   Note that by default Cygwin will build a library that depends on the | ||||
|   Cygwin DLL. You can use MinGW to build a library that does not depend on | ||||
|   the Cygwin DLL. To do so, give the option --host=mingw32 to `configure'. | ||||
|  | ||||
| POSIX Platforms (including Cygwin) | ||||
|  | ||||
|   The code is distributed with a `configure' script that will generate for | ||||
|   you a `Makefile' and a `config.h' for your platform. See the file | ||||
|   `INSTALL' for generic instructions. | ||||
|  | ||||
|   The specific options you may want to give `configure' are: | ||||
|  | ||||
|       --enable-speed            optimize for speed over accuracy | ||||
|  | ||||
|       --enable-accuracy         optimize for accuracy over speed | ||||
|  | ||||
|       --disable-debugging       do not compile with debugging support, and | ||||
|                                 use more optimizations | ||||
|  | ||||
|       --disable-shared          do not build a shared library | ||||
|  | ||||
|   Note that you need not specify one of --enable-speed or --enable-accuracy; | ||||
|   in its default configuration, MAD is optimized for both. You should only | ||||
|   use one of these options if you wish to compromise speed or accuracy for | ||||
|   the other. | ||||
|  | ||||
|   By default the package will build a shared library if possible for your | ||||
|   platform. If you want only a static library, use --disable-shared. | ||||
|  | ||||
|   It is not normally necessary to use the following options, but you may | ||||
|   fine-tune the configuration with them if desired: | ||||
|  | ||||
|       --enable-fpm=ARCH         use the ARCH-specific version of the | ||||
|                                 fixed-point math assembly routines | ||||
|                                 (current options are: intel, arm, mips, | ||||
|                                 sparc, ppc; also allowed are: 64bit, approx) | ||||
|  | ||||
|       --enable-sso              use the subband synthesis optimization, | ||||
|                                 with reduced accuracy | ||||
|  | ||||
|       --disable-aso             do not use certain architecture-specific | ||||
|                                 optimizations | ||||
|  | ||||
|   By default an appropriate fixed-point assembly routine will be selected | ||||
|   for the configured host type, if it can be determined. Thus if you are | ||||
|   cross-compiling for another architecture, you should be sure either to | ||||
|   give `configure' a host type argument (--host) or to use an explicit | ||||
|   --enable-fpm option. | ||||
|  | ||||
|   If an appropriate assembly routine cannot be determined, the default | ||||
|   approximation version will be used. In this case, use of an alternate | ||||
|   --enable-fpm is highly recommended. | ||||
|  | ||||
| Experimenting and Developing | ||||
|  | ||||
|   Further options for `configure' that may be useful to developers and | ||||
|   experimenters are: | ||||
|  | ||||
|       --enable-debugging        enable diagnostic debugging support and | ||||
|                                 debugging symbols | ||||
|  | ||||
|       --enable-profiling        generate `gprof' profiling code | ||||
|  | ||||
|       --enable-experimental     enable code using the EXPERIMENTAL | ||||
|                                 preprocessor define | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| COPYRIGHT | ||||
|  | ||||
|   Please read the `COPYRIGHT' file for copyright and warranty information. | ||||
|   Also, the file `COPYING' contains the full text of the GNU GPL. | ||||
|  | ||||
|   Send inquiries, comments, bug reports, suggestions, patches, etc. to: | ||||
|  | ||||
|       Underbit Technologies, Inc. <support@underbit.com> | ||||
|  | ||||
|   See also the MAD home page on the Web: | ||||
|  | ||||
|       http://www.underbit.com/products/mad/ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
							
								
								
									
										70
									
								
								src/libmad/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/libmad/TODO
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
|  | ||||
|  libmad - MPEG audio decoder library | ||||
|  Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  | ||||
|  $Id: TODO,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  | ||||
| =============================================================================== | ||||
|  | ||||
| libmad: | ||||
|   - more API layers (buffering, PCM samples, dithering, etc.) | ||||
|   - x86 performance optimization compiler flags | ||||
|   - function documentation, general docs | ||||
|   - finish async API | ||||
|   - parse system streams? | ||||
|   - MPEG-2 MC, AAC? | ||||
|   - logarithmic multiplication? | ||||
|   - multiple frame decoding for better locality of reference? | ||||
|   - frame serial numbers, Layer III frame continuity checks | ||||
|  | ||||
| fixed.h: | ||||
|   - experiment with FPM_INTEL: | ||||
|  | ||||
| # if 1 | ||||
| #    define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed_t __result;  \ | ||||
|        asm ("shrl %3,%1\n\t"  \ | ||||
| 	    "shll %4,%2\n\t"  \ | ||||
| 	    "orl %2,%1"  \ | ||||
| 	    : "=rm" (__result)  \ | ||||
| 	    : "0" (lo), "r" (hi),  \ | ||||
| 	      "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| # else | ||||
| #    define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed64hi_t __hi_;  \ | ||||
|        mad_fixed64lo_t __lo_;  \ | ||||
|        mad_fixed_t __result;  \ | ||||
|        asm ("sall %2,%1"  \ | ||||
| 	    : "=r" (__hi_)  \ | ||||
| 	    : "0" (hi), "I" (32 - MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        asm ("shrl %2,%1"  \ | ||||
| 	    : "=r" (__lo_)  \ | ||||
| 	    : "0" (lo), "I" (MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        asm ("orl %1,%2"  \ | ||||
| 	    : "=rm" (__result)  \ | ||||
| 	    : "r" (__hi_), "0" (__lo_)  \ | ||||
| 	    : "cc");  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| # endif | ||||
|  | ||||
| libmad Layer I: | ||||
|   - check frame length sanity | ||||
|  | ||||
| libmad Layer II: | ||||
|   - check legal bitrate/mode combinations | ||||
|   - check frame length sanity | ||||
|  | ||||
| libmad Layer III: | ||||
|   - circular buffer | ||||
|   - optimize zero_part from Huffman decoding throughout | ||||
|   - MPEG 2.5 8000 Hz sf bands? mixed blocks? | ||||
|   - stereo->mono conversion optimization? | ||||
|   - enable frame-at-a-time decoding | ||||
|   - improve portability of huffman.c | ||||
|  | ||||
							
								
								
									
										7
									
								
								src/libmad/VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/libmad/VERSION
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| 0.15.0b | ||||
| configure.ac:24 | ||||
| version.h:25-28 | ||||
| msvc++/config.h:115 | ||||
| msvc++/mad.h:38-41 | ||||
|  | ||||
| Makefile.am:89-91 | ||||
							
								
								
									
										237
									
								
								src/libmad/bit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								src/libmad/bit.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: bit.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # ifdef HAVE_LIMITS_H | ||||
| #  include <limits.h> | ||||
| # else | ||||
| #  define CHAR_BIT  8 | ||||
| # endif | ||||
|  | ||||
| # include "bit.h" | ||||
|  | ||||
| /* | ||||
|  * This is the lookup table for computing the CRC-check word. | ||||
|  * As described in section 2.4.3.1 and depicted in Figure A.9 | ||||
|  * of ISO/IEC 11172-3, the generator polynomial is: | ||||
|  * | ||||
|  * G(X) = X^16 + X^15 + X^2 + 1 | ||||
|  */ | ||||
| static | ||||
| unsigned short const crc_table[256] = { | ||||
|   0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, | ||||
|   0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, | ||||
|   0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, | ||||
|   0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, | ||||
|   0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, | ||||
|   0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, | ||||
|   0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, | ||||
|   0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, | ||||
|  | ||||
|   0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, | ||||
|   0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, | ||||
|   0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, | ||||
|   0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, | ||||
|   0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, | ||||
|   0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, | ||||
|   0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, | ||||
|   0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, | ||||
|  | ||||
|   0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, | ||||
|   0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, | ||||
|   0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, | ||||
|   0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, | ||||
|   0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, | ||||
|   0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, | ||||
|   0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, | ||||
|   0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, | ||||
|  | ||||
|   0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, | ||||
|   0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, | ||||
|   0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, | ||||
|   0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, | ||||
|   0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, | ||||
|   0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, | ||||
|   0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, | ||||
|   0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 | ||||
| }; | ||||
|  | ||||
| # define CRC_POLY  0x8005 | ||||
|  | ||||
| /* | ||||
|  * NAME:	bit->init() | ||||
|  * DESCRIPTION:	initialize bit pointer struct | ||||
|  */ | ||||
| void mad_bit_init(struct mad_bitptr *bitptr, unsigned char const *byte) | ||||
| { | ||||
|   bitptr->byte  = byte; | ||||
|   bitptr->cache = 0; | ||||
|   bitptr->left  = CHAR_BIT; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	bit->length() | ||||
|  * DESCRIPTION:	return number of bits between start and end points | ||||
|  */ | ||||
| unsigned int mad_bit_length(struct mad_bitptr const *begin, | ||||
| 			    struct mad_bitptr const *end) | ||||
| { | ||||
|   return begin->left + | ||||
|     CHAR_BIT * (end->byte - (begin->byte + 1)) + (CHAR_BIT - end->left); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	bit->nextbyte() | ||||
|  * DESCRIPTION:	return pointer to next unprocessed byte | ||||
|  */ | ||||
| unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *bitptr) | ||||
| { | ||||
|   return bitptr->left == CHAR_BIT ? bitptr->byte : bitptr->byte + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	bit->skip() | ||||
|  * DESCRIPTION:	advance bit pointer | ||||
|  */ | ||||
| void mad_bit_skip(struct mad_bitptr *bitptr, unsigned int len) | ||||
| { | ||||
|   bitptr->byte += len / CHAR_BIT; | ||||
|   bitptr->left -= len % CHAR_BIT; | ||||
|  | ||||
|   if (bitptr->left > CHAR_BIT) { | ||||
|     bitptr->byte++; | ||||
|     bitptr->left += CHAR_BIT; | ||||
|   } | ||||
|  | ||||
|   if (bitptr->left < CHAR_BIT) | ||||
|     bitptr->cache = *bitptr->byte; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	bit->read() | ||||
|  * DESCRIPTION:	read an arbitrary number of bits and return their UIMSBF value | ||||
|  */ | ||||
| unsigned long mad_bit_read(struct mad_bitptr *bitptr, unsigned int len) | ||||
| { | ||||
|   register unsigned long value; | ||||
|  | ||||
|   if (bitptr->left == CHAR_BIT) | ||||
|     bitptr->cache = *bitptr->byte; | ||||
|  | ||||
|   if (len < bitptr->left) { | ||||
|     value = (bitptr->cache & ((1 << bitptr->left) - 1)) >> | ||||
|       (bitptr->left - len); | ||||
|     bitptr->left -= len; | ||||
|  | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   /* remaining bits in current byte */ | ||||
|  | ||||
|   value = bitptr->cache & ((1 << bitptr->left) - 1); | ||||
|   len  -= bitptr->left; | ||||
|  | ||||
|   bitptr->byte++; | ||||
|   bitptr->left = CHAR_BIT; | ||||
|  | ||||
|   /* more bytes */ | ||||
|  | ||||
|   while (len >= CHAR_BIT) { | ||||
|     value = (value << CHAR_BIT) | *bitptr->byte++; | ||||
|     len  -= CHAR_BIT; | ||||
|   } | ||||
|  | ||||
|   if (len > 0) { | ||||
|     bitptr->cache = *bitptr->byte; | ||||
|  | ||||
|     value = (value << len) | (bitptr->cache >> (CHAR_BIT - len)); | ||||
|     bitptr->left -= len; | ||||
|   } | ||||
|  | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| # if 0 | ||||
| /* | ||||
|  * NAME:	bit->write() | ||||
|  * DESCRIPTION:	write an arbitrary number of bits | ||||
|  */ | ||||
| void mad_bit_write(struct mad_bitptr *bitptr, unsigned int len, | ||||
| 		   unsigned long value) | ||||
| { | ||||
|   unsigned char *ptr; | ||||
|  | ||||
|   ptr = (unsigned char *) bitptr->byte; | ||||
|  | ||||
|   /* ... */ | ||||
| } | ||||
| # endif | ||||
|  | ||||
| /* | ||||
|  * NAME:	bit->crc() | ||||
|  * DESCRIPTION:	compute CRC-check word | ||||
|  */ | ||||
| unsigned short mad_bit_crc(struct mad_bitptr bitptr, unsigned int len, | ||||
| 			   unsigned short init) | ||||
| { | ||||
|   register unsigned int crc; | ||||
|  | ||||
|   for (crc = init; len >= 32; len -= 32) { | ||||
|     register unsigned long data; | ||||
|  | ||||
|     data = mad_bit_read(&bitptr, 32); | ||||
|  | ||||
|     crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 24)) & 0xff]; | ||||
|     crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 16)) & 0xff]; | ||||
|     crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >>  8)) & 0xff]; | ||||
|     crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >>  0)) & 0xff]; | ||||
|   } | ||||
|  | ||||
|   switch (len / 8) { | ||||
|   case 3: crc = (crc << 8) ^ | ||||
| 	    crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff]; | ||||
|   case 2: crc = (crc << 8) ^ | ||||
| 	    crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff]; | ||||
|   case 1: crc = (crc << 8) ^ | ||||
| 	    crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff]; | ||||
|  | ||||
|   len %= 8; | ||||
|  | ||||
|   case 0: break; | ||||
|   } | ||||
|  | ||||
|   while (len--) { | ||||
|     register unsigned int msb; | ||||
|  | ||||
|     msb = mad_bit_read(&bitptr, 1) ^ (crc >> 15); | ||||
|  | ||||
|     crc <<= 1; | ||||
|     if (msb & 1) | ||||
|       crc ^= CRC_POLY; | ||||
|   } | ||||
|  | ||||
|   return crc & 0xffff; | ||||
| } | ||||
							
								
								
									
										47
									
								
								src/libmad/bit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/libmad/bit.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: bit.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_BIT_H | ||||
| # define LIBMAD_BIT_H | ||||
|  | ||||
| struct mad_bitptr { | ||||
|   unsigned char const *byte; | ||||
|   unsigned short cache; | ||||
|   unsigned short left; | ||||
| }; | ||||
|  | ||||
| void mad_bit_init(struct mad_bitptr *, unsigned char const *); | ||||
|  | ||||
| # define mad_bit_finish(bitptr)		/* nothing */ | ||||
|  | ||||
| unsigned int mad_bit_length(struct mad_bitptr const *, | ||||
| 			    struct mad_bitptr const *); | ||||
|  | ||||
| # define mad_bit_bitsleft(bitptr)  ((bitptr)->left) | ||||
| unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *); | ||||
|  | ||||
| void mad_bit_skip(struct mad_bitptr *, unsigned int); | ||||
| unsigned long mad_bit_read(struct mad_bitptr *, unsigned int); | ||||
| void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long); | ||||
|  | ||||
| unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										129
									
								
								src/libmad/config.h.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/libmad/config.h.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| /* config.h.in.  Generated from configure.ac by autoheader.  */ | ||||
|  | ||||
| /* Define to enable diagnostic debugging support. */ | ||||
| #undef DEBUG | ||||
|  | ||||
| /* Define to enable experimental code. */ | ||||
| #undef EXPERIMENTAL | ||||
|  | ||||
| /* Define to 1 if you have the <assert.h> header file. */ | ||||
| #undef HAVE_ASSERT_H | ||||
|  | ||||
| /* Define to 1 if you have the <dlfcn.h> header file. */ | ||||
| #undef HAVE_DLFCN_H | ||||
|  | ||||
| /* Define to 1 if you have the <errno.h> header file. */ | ||||
| #undef HAVE_ERRNO_H | ||||
|  | ||||
| /* Define to 1 if you have the `fcntl' function. */ | ||||
| #undef HAVE_FCNTL | ||||
|  | ||||
| /* Define to 1 if you have the <fcntl.h> header file. */ | ||||
| #undef HAVE_FCNTL_H | ||||
|  | ||||
| /* Define to 1 if you have the `fork' function. */ | ||||
| #undef HAVE_FORK | ||||
|  | ||||
| /* Define to 1 if you have the <inttypes.h> header file. */ | ||||
| #undef HAVE_INTTYPES_H | ||||
|  | ||||
| /* Define to 1 if you have the <limits.h> header file. */ | ||||
| #undef HAVE_LIMITS_H | ||||
|  | ||||
| /* Define if your MIPS CPU supports a 2-operand MADD16 instruction. */ | ||||
| #undef HAVE_MADD16_ASM | ||||
|  | ||||
| /* Define if your MIPS CPU supports a 2-operand MADD instruction. */ | ||||
| #undef HAVE_MADD_ASM | ||||
|  | ||||
| /* Define to 1 if you have the <memory.h> header file. */ | ||||
| #undef HAVE_MEMORY_H | ||||
|  | ||||
| /* Define to 1 if you have the `pipe' function. */ | ||||
| #undef HAVE_PIPE | ||||
|  | ||||
| /* Define to 1 if you have the <stdint.h> header file. */ | ||||
| #undef HAVE_STDINT_H | ||||
|  | ||||
| /* Define to 1 if you have the <stdlib.h> header file. */ | ||||
| #undef HAVE_STDLIB_H | ||||
|  | ||||
| /* Define to 1 if you have the <strings.h> header file. */ | ||||
| #undef HAVE_STRINGS_H | ||||
|  | ||||
| /* Define to 1 if you have the <string.h> header file. */ | ||||
| #undef HAVE_STRING_H | ||||
|  | ||||
| /* Define to 1 if you have the <sys/stat.h> header file. */ | ||||
| #undef HAVE_SYS_STAT_H | ||||
|  | ||||
| /* Define to 1 if you have the <sys/types.h> header file. */ | ||||
| #undef HAVE_SYS_TYPES_H | ||||
|  | ||||
| /* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ | ||||
| #undef HAVE_SYS_WAIT_H | ||||
|  | ||||
| /* Define to 1 if you have the <unistd.h> header file. */ | ||||
| #undef HAVE_UNISTD_H | ||||
|  | ||||
| /* Define to 1 if you have the `waitpid' function. */ | ||||
| #undef HAVE_WAITPID | ||||
|  | ||||
| /* Define to disable debugging assertions. */ | ||||
| #undef NDEBUG | ||||
|  | ||||
| /* Define to optimize for accuracy over speed. */ | ||||
| #undef OPT_ACCURACY | ||||
|  | ||||
| /* Define to optimize for speed over accuracy. */ | ||||
| #undef OPT_SPEED | ||||
|  | ||||
| /* Define to enable a fast subband synthesis approximation optimization. */ | ||||
| #undef OPT_SSO | ||||
|  | ||||
| /* Define to influence a strict interpretation of the ISO/IEC standards, even | ||||
|    if this is in opposition with best accepted practices. */ | ||||
| #undef OPT_STRICT | ||||
|  | ||||
| /* Name of package */ | ||||
| #undef PACKAGE | ||||
|  | ||||
| /* Define to the address where bug reports for this package should be sent. */ | ||||
| #undef PACKAGE_BUGREPORT | ||||
|  | ||||
| /* Define to the full name of this package. */ | ||||
| #undef PACKAGE_NAME | ||||
|  | ||||
| /* Define to the full name and version of this package. */ | ||||
| #undef PACKAGE_STRING | ||||
|  | ||||
| /* Define to the one symbol short name of this package. */ | ||||
| #undef PACKAGE_TARNAME | ||||
|  | ||||
| /* Define to the version of this package. */ | ||||
| #undef PACKAGE_VERSION | ||||
|  | ||||
| /* The size of a `int', as computed by sizeof. */ | ||||
| #undef SIZEOF_INT | ||||
|  | ||||
| /* The size of a `long', as computed by sizeof. */ | ||||
| #undef SIZEOF_LONG | ||||
|  | ||||
| /* The size of a `long long', as computed by sizeof. */ | ||||
| #undef SIZEOF_LONG_LONG | ||||
|  | ||||
| /* Define to 1 if you have the ANSI C header files. */ | ||||
| #undef STDC_HEADERS | ||||
|  | ||||
| /* Version number of package */ | ||||
| #undef VERSION | ||||
|  | ||||
| /* Define to empty if `const' does not conform to ANSI C. */ | ||||
| #undef const | ||||
|  | ||||
| /* Define as `__inline' if that's what the C compiler calls it, or to nothing | ||||
|    if it is not supported. */ | ||||
| #undef inline | ||||
|  | ||||
| /* Define to `int' if <sys/types.h> does not define. */ | ||||
| #undef pid_t | ||||
							
								
								
									
										432
									
								
								src/libmad/configure.ac
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								src/libmad/configure.ac
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,432 @@ | ||||
| dnl -*- m4 -*- | ||||
| dnl | ||||
| dnl libmad - MPEG audio decoder library | ||||
| dnl Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
| dnl | ||||
| dnl This program is free software; you can redistribute it and/or modify | ||||
| dnl it under the terms of the GNU General Public License as published by | ||||
| dnl the Free Software Foundation; either version 2 of the License, or | ||||
| dnl (at your option) any later version. | ||||
| dnl | ||||
| dnl This program is distributed in the hope that it will be useful, | ||||
| dnl but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| dnl GNU General Public License for more details. | ||||
| dnl | ||||
| dnl You should have received a copy of the GNU General Public License | ||||
| dnl along with this program; if not, write to the Free Software | ||||
| dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
| dnl | ||||
| AC_REVISION([$Id: configure.ac,v 1.1 2003/08/14 03:57:13 shank Exp $])dnl | ||||
|  | ||||
| dnl Process this file with autoconf to produce a configure script. | ||||
|  | ||||
| AC_INIT([MPEG Audio Decoder], [0.15.0b], [support@underbit.com], [libmad]) | ||||
| AC_PREREQ(2.53) | ||||
|  | ||||
| AC_CONFIG_SRCDIR([decoder.h]) | ||||
|  | ||||
| AM_INIT_AUTOMAKE | ||||
|  | ||||
| AM_CONFIG_HEADER([config.h]) | ||||
|  | ||||
| dnl System type. | ||||
|  | ||||
| AC_CANONICAL_HOST | ||||
|  | ||||
| dnl Checks for programs. | ||||
|  | ||||
| AC_PROG_CC | ||||
| AM_PROG_AS | ||||
|  | ||||
| if test "$GCC" = yes | ||||
| then | ||||
|     case "$host" in | ||||
| 	*-*-mingw*) | ||||
| 	    case "$build" in | ||||
| 		*-*-cygwin*) | ||||
| 		    CPPFLAGS="$CPPFLAGS -mno-cygwin" | ||||
| 		    LDFLAGS="$LDFLAGS -mno-cygwin" | ||||
| 		    ;; | ||||
| 	    esac | ||||
|     esac | ||||
|  | ||||
| dnl    case "$host" in | ||||
| dnl	*-*-cygwin* | *-*-mingw*) | ||||
| dnl	    LDFLAGS="$LDFLAGS -no-undefined -mdll" | ||||
| dnl	    ;; | ||||
| dnl    esac | ||||
| fi | ||||
|  | ||||
| dnl Support for libtool. | ||||
|  | ||||
| AC_DISABLE_SHARED | ||||
| dnl AC_LIBTOOL_WIN32_DLL | ||||
| AC_PROG_LIBTOOL | ||||
|  | ||||
| AC_SUBST(LIBTOOL_DEPS) | ||||
|  | ||||
| dnl Compiler options. | ||||
|  | ||||
| arch="" | ||||
| debug="" | ||||
| optimize="" | ||||
| profile="" | ||||
|  | ||||
| set -- $CFLAGS | ||||
| CFLAGS="" | ||||
|  | ||||
| if test "$GCC" = yes | ||||
| then | ||||
|     CFLAGS="-Wall" | ||||
| fi | ||||
|  | ||||
| while test $# -gt 0 | ||||
| do | ||||
|     case "$1" in | ||||
| 	-Wall) | ||||
| 	    if test "$GCC" = yes | ||||
| 	    then | ||||
| 		: | ||||
| 	    else | ||||
| 		CFLAGS="$CFLAGS $1" | ||||
| 	    fi | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-g) | ||||
| 	    debug="-g" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-mno-cygwin) | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-m*) | ||||
| 	    arch="$arch $1" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-O2) | ||||
| 	    optimize="-O" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-fomit-frame-pointer) | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	-O*|-f*) | ||||
| 	    optimize="$optimize $1" | ||||
| 	    shift | ||||
| 	    ;; | ||||
| 	*) | ||||
| 	    CFLAGS="$CFLAGS $1" | ||||
| 	    shift | ||||
| 	    ;; | ||||
|     esac | ||||
| done | ||||
|  | ||||
| if test "$GCC" = yes | ||||
| then | ||||
|     if test -z "$arch" | ||||
|     then | ||||
| 	case "$host" in | ||||
| 	    i386-*)           ;; | ||||
| 	    i?86-*)           arch="-march=i486" ;; | ||||
| 	    arm*-empeg-*)     arch="-march=armv4 -mtune=strongarm1100" ;; | ||||
| 	    armv4*-*)         arch="-march=armv4 -mtune=strongarm" ;; | ||||
| 	    powerpc-*)        ;; | ||||
| 	    mips*-agenda-*)   arch="-mcpu=vr4100" ;; | ||||
| 	    mips*-luxsonor-*) arch="-mips1 -mcpu=r3000 -Wa,-m4010" ;; | ||||
| 	esac | ||||
|     fi | ||||
|  | ||||
|     case "$optimize" in | ||||
| 	-O|"-O "*) | ||||
| 	    optimize="-O" | ||||
| 	    optimize="$optimize -fforce-mem" | ||||
| 	    optimize="$optimize -fforce-addr" | ||||
| 	    : #x optimize="$optimize -finline-functions" | ||||
| 	    : #- optimize="$optimize -fstrength-reduce" | ||||
| 	    optimize="$optimize -fthread-jumps" | ||||
| 	    optimize="$optimize -fcse-follow-jumps" | ||||
| 	    optimize="$optimize -fcse-skip-blocks" | ||||
| 	    : #x optimize="$optimize -frerun-cse-after-loop" | ||||
| 	    : #x optimize="$optimize -frerun-loop-opt" | ||||
| 	    : #x optimize="$optimize -fgcse" | ||||
| 	    optimize="$optimize -fexpensive-optimizations" | ||||
| 	    optimize="$optimize -fregmove" | ||||
| 	    : #* optimize="$optimize -fdelayed-branch" | ||||
| 	    : #x optimize="$optimize -fschedule-insns" | ||||
| 	    optimize="$optimize -fschedule-insns2" | ||||
| 	    : #? optimize="$optimize -ffunction-sections" | ||||
| 	    : #? optimize="$optimize -fcaller-saves" | ||||
| 	    : #> optimize="$optimize -funroll-loops" | ||||
| 	    : #> optimize="$optimize -funroll-all-loops" | ||||
| 	    : #x optimize="$optimize -fmove-all-movables" | ||||
| 	    : #x optimize="$optimize -freduce-all-givs" | ||||
| 	    : #? optimize="$optimize -fstrict-aliasing" | ||||
| 	    : #* optimize="$optimize -fstructure-noalias" | ||||
|  | ||||
| 	    case "$host" in | ||||
| 		arm*-*) | ||||
| 		    optimize="$optimize -fstrength-reduce" | ||||
| 		    ;; | ||||
| 		mips*-*) | ||||
| 		    optimize="$optimize -fstrength-reduce" | ||||
| 		    optimize="$optimize -finline-functions" | ||||
| 		    ;; | ||||
| 		i?86-*) | ||||
| 		    optimize="$optimize -fstrength-reduce" | ||||
| 		    ;; | ||||
| 		powerpc-apple-*) | ||||
| 		    # this triggers an internal compiler error with gcc2 | ||||
| 		    : #optimize="$optimize -fstrength-reduce" | ||||
|  | ||||
| 		    # this is really only beneficial with gcc3 | ||||
| 		    : #optimize="$optimize -finline-functions" | ||||
| 		    ;; | ||||
| 		*) | ||||
| 		    # this sometimes provokes bugs in gcc 2.95.2 | ||||
| 		    : #optimize="$optimize -fstrength-reduce" | ||||
| 		    ;; | ||||
| 	    esac | ||||
| 	    ;; | ||||
|     esac | ||||
| fi | ||||
|  | ||||
| case "$host" in | ||||
|     mips*-agenda-*) | ||||
| 	AC_DEFINE(HAVE_MADD16_ASM, 1, | ||||
| 	    [Define if your MIPS CPU supports a 2-operand MADD16 instruction.]) | ||||
| 	;; | ||||
|     mips*-luxsonor-*) | ||||
| 	AC_DEFINE(HAVE_MADD_ASM, 1, | ||||
| 	    [Define if your MIPS CPU supports a 2-operand MADD instruction.]) | ||||
| 	;; | ||||
| esac | ||||
|  | ||||
| dnl Checks for header files. | ||||
|  | ||||
| AC_HEADER_STDC | ||||
| AC_HEADER_SYS_WAIT | ||||
| AC_CHECK_HEADERS(assert.h limits.h unistd.h sys/types.h fcntl.h errno.h) | ||||
|  | ||||
| dnl Checks for typedefs, structures, and compiler characteristics. | ||||
|  | ||||
| AC_C_CONST | ||||
| AC_C_INLINE | ||||
| AC_TYPE_PID_T | ||||
|  | ||||
| AC_CHECK_SIZEOF(int, 2) | ||||
| AC_CHECK_SIZEOF(long, 4) | ||||
| AC_CHECK_SIZEOF(long long, 8) | ||||
|  | ||||
| dnl Checks for library functions. | ||||
|  | ||||
| AC_CHECK_FUNCS(waitpid fcntl pipe fork) | ||||
|  | ||||
| dnl Other options. | ||||
|  | ||||
| AC_SUBST(FPM) | ||||
| AC_SUBST(ASO) | ||||
| AC_SUBST(ASO_OBJS) | ||||
|  | ||||
| dnl handle --enable and --disable options | ||||
|  | ||||
| AC_CACHE_SAVE | ||||
|  | ||||
| AC_MSG_CHECKING(whether to optimize for speed or for accuracy) | ||||
|  | ||||
| AC_ARG_ENABLE(speed, AC_HELP_STRING([--enable-speed], | ||||
| 		     [optimize for speed over accuracy]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    optimize_for="speed" | ||||
| 	    AC_DEFINE(OPT_SPEED, 1, | ||||
| 		[Define to optimize for speed over accuracy.]) | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
|  | ||||
| AC_ARG_ENABLE(accuracy, AC_HELP_STRING([--enable-accuracy], | ||||
| 			[optimize for accuracy over speed]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    if test "$optimize_for" = "speed" | ||||
| 	    then | ||||
| 		optimize_for="both" | ||||
| 	    else | ||||
| 		optimize_for="accuracy" | ||||
| 	    fi | ||||
| 	    AC_DEFINE(OPT_ACCURACY, 1, | ||||
| 		[Define to optimize for accuracy over speed.]) | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
|  | ||||
| AC_MSG_RESULT(${optimize_for-default}) | ||||
|  | ||||
| if test "$optimize_for" = "both" | ||||
| then | ||||
|     AC_MSG_ERROR(cannot optimize for both speed and accuracy) | ||||
| fi | ||||
|  | ||||
| AC_MSG_CHECKING(for architecture-specific fixed-point math routines) | ||||
| AC_ARG_ENABLE(fpm, AC_HELP_STRING([--enable-fpm=ARCH], | ||||
| 		   [use ARCH-specific fixed-point math routines | ||||
| 		    (one of: intel, arm, mips, sparc, ppc, 64bit, default)]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes)                             ;; | ||||
| 	no|default|approx) FPM="DEFAULT" ;; | ||||
| 	intel|i?86)        FPM="INTEL"   ;; | ||||
| 	arm)               FPM="ARM"     ;; | ||||
| 	mips)              FPM="MIPS"    ;; | ||||
| 	sparc)             FPM="SPARC"   ;; | ||||
| 	ppc|powerpc)       FPM="PPC"     ;; | ||||
| 	64bit)             FPM="64BIT"   ;; | ||||
| 	float)             FPM="FLOAT"   ;; | ||||
| 	*) | ||||
| 	    AC_MSG_RESULT(failed) | ||||
| 	    AC_MSG_ERROR([bad --enable-fpm option]) | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
|  | ||||
| if test -z "$FPM" && test "$GCC" = yes | ||||
| then | ||||
|     case "$host" in | ||||
| 	i?86-*)     FPM="INTEL"  ;; | ||||
| 	arm*-*)     FPM="ARM"    ;; | ||||
| 	mips*-*)    FPM="MIPS"   ;; | ||||
| 	sparc*-*)   FPM="SPARC"  ;; | ||||
| 	powerpc*-*) FPM="PPC"    ;; | ||||
| 	# FIXME: need to test for 64-bit long long... | ||||
|     esac | ||||
| fi | ||||
|  | ||||
| AC_MSG_RESULT(${FPM=DEFAULT}) | ||||
|  | ||||
| if test "$FPM" = "DEFAULT" | ||||
| then | ||||
|     AC_MSG_WARN([default fixed-point math will yield limited accuracy]) | ||||
| fi | ||||
|  | ||||
| FPM="-DFPM_$FPM" | ||||
|  | ||||
| AC_ARG_ENABLE(sso, AC_HELP_STRING([--enable-sso], | ||||
| 		   [use subband synthesis optimization]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    AC_DEFINE(OPT_SSO, 1, | ||||
|     [Define to enable a fast subband synthesis approximation optimization.]) | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
|  | ||||
| AC_ARG_ENABLE(aso, AC_HELP_STRING([--disable-aso], | ||||
| 		   [disable architecture-specific optimizations]), | ||||
|     [], [enable_aso=yes]) | ||||
|  | ||||
| if test "$enable_aso" = yes | ||||
| then | ||||
|     case "$host" in | ||||
| 	i?86-*) | ||||
| 	    : #ASO="$ASO -DASO_INTERLEAVE1" | ||||
| 	    ASO="$ASO -DASO_ZEROCHECK" | ||||
| 	    : #not yet #ASO="$ASO -DASO_SYNTH" | ||||
| 	    : #not yet #ASO_OBJS="synth_mmx.lo" | ||||
| 	    ;; | ||||
| 	arm*-*) | ||||
| 	    ASO="$ASO -DASO_INTERLEAVE1" | ||||
| 	    ASO="$ASO -DASO_IMDCT" | ||||
| 	    ASO_OBJS="imdct_l_arm.lo" | ||||
| 	    ;; | ||||
| 	mips*-*) | ||||
| 	    ASO="$ASO -DASO_INTERLEAVE2" | ||||
| 	    ASO="$ASO -DASO_ZEROCHECK" | ||||
| 	    ;; | ||||
|     esac | ||||
| fi | ||||
|  | ||||
| AC_MSG_CHECKING(for ISO/IEC interpretation) | ||||
| AC_ARG_ENABLE(strict-iso, AC_HELP_STRING([--enable-strict-iso], | ||||
| 			  [use strict ISO/IEC interpretations]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    AC_DEFINE(OPT_STRICT, 1, | ||||
|     [Define to influence a strict interpretation of the ISO/IEC standards, | ||||
|      even if this is in opposition with best accepted practices.]) | ||||
| 	    interpretation="strict" | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
| AC_MSG_RESULT(${interpretation-best accepted practices}) | ||||
|  | ||||
| AC_MSG_CHECKING(whether to enable profiling) | ||||
| AC_ARG_ENABLE(profiling, AC_HELP_STRING([--enable-profiling], | ||||
| 			 [generate profiling code]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) profile="-pg" ;; | ||||
|     esac | ||||
| ]) | ||||
| AC_MSG_RESULT(${enable_profiling-no}) | ||||
|  | ||||
| AC_MSG_CHECKING(whether to enable debugging) | ||||
| AC_ARG_ENABLE(debugging, AC_HELP_STRING([--enable-debugging], | ||||
| 			 [enable diagnostic debugging support]) | ||||
| AC_HELP_STRING([--disable-debugging], | ||||
| 	       [do not enable debugging and use more optimization]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    AC_DEFINE(DEBUG, 1, | ||||
| 		[Define to enable diagnostic debugging support.]) | ||||
| 	    optimize="" | ||||
| 	    ;; | ||||
| 	no) | ||||
| 	    if test -n "$profile" | ||||
| 	    then | ||||
|     AC_MSG_ERROR(--enable-profiling and --disable-debugging are incompatible) | ||||
| 	    fi | ||||
|  | ||||
| 	    AC_DEFINE(NDEBUG, 1, | ||||
| 		[Define to disable debugging assertions.]) | ||||
| 	    debug="" | ||||
| 	    if test "$GCC" = yes | ||||
| 	    then | ||||
| 		optimize="$optimize -fomit-frame-pointer" | ||||
| 	    fi | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
| AC_MSG_RESULT(${enable_debugging-default}) | ||||
|  | ||||
| AC_MSG_CHECKING(whether to enable experimental code) | ||||
| AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental], | ||||
| 			    [enable experimental code]), | ||||
| [ | ||||
|     case "$enableval" in | ||||
| 	yes) | ||||
| 	    AC_DEFINE(EXPERIMENTAL, 1, | ||||
| 		[Define to enable experimental code.]) | ||||
| 	    ;; | ||||
|     esac | ||||
| ]) | ||||
| AC_MSG_RESULT(${enable_experimental-no}) | ||||
|  | ||||
| dnl Create output files. | ||||
|  | ||||
| test -n "$arch"     && CFLAGS="$CFLAGS $arch" | ||||
| test -n "$debug"    && CFLAGS="$CFLAGS $debug" | ||||
| test -n "$optimize" && CFLAGS="$CFLAGS $optimize" | ||||
| test -n "$profile"  && CFLAGS="$CFLAGS $profile" LDFLAGS="$LDFLAGS $profile" | ||||
|  | ||||
| dnl LTLIBOBJS=`echo "$LIBOBJS" | sed -e 's/\.o/.lo/g'` | ||||
| dnl AC_SUBST(LTLIBOBJS) | ||||
|  | ||||
| AC_CONFIG_FILES([Makefile \ | ||||
| 	libmad.list]) | ||||
| AC_OUTPUT | ||||
							
								
								
									
										582
									
								
								src/libmad/decoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								src/libmad/decoder.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,582 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: decoder.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # ifdef HAVE_SYS_TYPES_H | ||||
| #  include <sys/types.h> | ||||
| # endif | ||||
|  | ||||
| # ifdef HAVE_SYS_WAIT_H | ||||
| #  include <sys/wait.h> | ||||
| # endif | ||||
|  | ||||
| # ifdef HAVE_UNISTD_H | ||||
| #  include <unistd.h> | ||||
| # endif | ||||
|  | ||||
| # ifdef HAVE_FCNTL_H | ||||
| #  include <fcntl.h> | ||||
| # endif | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # ifdef HAVE_ERRNO_H | ||||
| #  include <errno.h> | ||||
| # endif | ||||
|  | ||||
| # include "stream.h" | ||||
| # include "frame.h" | ||||
| # include "synth.h" | ||||
| # include "decoder.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	decoder->init() | ||||
|  * DESCRIPTION:	initialize a decoder object with callback routines | ||||
|  */ | ||||
| void mad_decoder_init(struct mad_decoder *decoder, void *data, | ||||
| 		      enum mad_flow (*input_func)(void *, | ||||
| 						  struct mad_stream *), | ||||
| 		      enum mad_flow (*header_func)(void *, | ||||
| 						   struct mad_header const *), | ||||
| 		      enum mad_flow (*filter_func)(void *, | ||||
| 						   struct mad_stream const *, | ||||
| 						   struct mad_frame *), | ||||
| 		      enum mad_flow (*output_func)(void *, | ||||
| 						   struct mad_header const *, | ||||
| 						   struct mad_pcm *), | ||||
| 		      enum mad_flow (*error_func)(void *, | ||||
| 						  struct mad_stream *, | ||||
| 						  struct mad_frame *), | ||||
| 		      enum mad_flow (*message_func)(void *, | ||||
| 						    void *, unsigned int *)) | ||||
| { | ||||
|   decoder->mode         = -1; | ||||
|  | ||||
|   decoder->options      = 0; | ||||
|  | ||||
|   decoder->async.pid    = 0; | ||||
|   decoder->async.in     = -1; | ||||
|   decoder->async.out    = -1; | ||||
|  | ||||
|   decoder->sync         = 0; | ||||
|  | ||||
|   decoder->cb_data      = data; | ||||
|  | ||||
|   decoder->input_func   = input_func; | ||||
|   decoder->header_func  = header_func; | ||||
|   decoder->filter_func  = filter_func; | ||||
|   decoder->output_func  = output_func; | ||||
|   decoder->error_func   = error_func; | ||||
|   decoder->message_func = message_func; | ||||
| } | ||||
|  | ||||
| int mad_decoder_finish(struct mad_decoder *decoder) | ||||
| { | ||||
| # if defined(USE_ASYNC) | ||||
|   if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) { | ||||
|     pid_t pid; | ||||
|     int status; | ||||
|  | ||||
|     close(decoder->async.in); | ||||
|  | ||||
|     do | ||||
|       pid = waitpid(decoder->async.pid, &status, 0); | ||||
|     while (pid == -1 && errno == EINTR); | ||||
|  | ||||
|     decoder->mode = -1; | ||||
|  | ||||
|     close(decoder->async.out); | ||||
|  | ||||
|     decoder->async.pid = 0; | ||||
|     decoder->async.in  = -1; | ||||
|     decoder->async.out = -1; | ||||
|  | ||||
|     if (pid == -1) | ||||
|       return -1; | ||||
|  | ||||
|     return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0; | ||||
|   } | ||||
| # endif | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| # if defined(USE_ASYNC) | ||||
| static | ||||
| enum mad_flow send_io(int fd, void const *data, size_t len) | ||||
| { | ||||
|   char const *ptr = data; | ||||
|   ssize_t count; | ||||
|  | ||||
|   while (len) { | ||||
|     do | ||||
|       count = write(fd, ptr, len); | ||||
|     while (count == -1 && errno == EINTR); | ||||
|  | ||||
|     if (count == -1) | ||||
|       return MAD_FLOW_BREAK; | ||||
|  | ||||
|     len -= count; | ||||
|     ptr += count; | ||||
|   } | ||||
|  | ||||
|   return MAD_FLOW_CONTINUE; | ||||
| } | ||||
|  | ||||
| static | ||||
| enum mad_flow receive_io(int fd, void *buffer, size_t len) | ||||
| { | ||||
|   char *ptr = buffer; | ||||
|   ssize_t count; | ||||
|  | ||||
|   while (len) { | ||||
|     do | ||||
|       count = read(fd, ptr, len); | ||||
|     while (count == -1 && errno == EINTR); | ||||
|  | ||||
|     if (count == -1) | ||||
|       return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK; | ||||
|     else if (count == 0) | ||||
|       return MAD_FLOW_STOP; | ||||
|  | ||||
|     len -= count; | ||||
|     ptr += count; | ||||
|   } | ||||
|  | ||||
|   return MAD_FLOW_CONTINUE; | ||||
| } | ||||
|  | ||||
| static | ||||
| enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len) | ||||
| { | ||||
|   int flags, blocking; | ||||
|   enum mad_flow result; | ||||
|  | ||||
|   flags = fcntl(fd, F_GETFL); | ||||
|   if (flags == -1) | ||||
|     return MAD_FLOW_BREAK; | ||||
|  | ||||
|   blocking = flags & ~O_NONBLOCK; | ||||
|  | ||||
|   if (blocking != flags && | ||||
|       fcntl(fd, F_SETFL, blocking) == -1) | ||||
|     return MAD_FLOW_BREAK; | ||||
|  | ||||
|   result = receive_io(fd, buffer, len); | ||||
|  | ||||
|   if (flags != blocking && | ||||
|       fcntl(fd, F_SETFL, flags) == -1) | ||||
|     return MAD_FLOW_BREAK; | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static | ||||
| enum mad_flow send(int fd, void const *message, unsigned int size) | ||||
| { | ||||
|   enum mad_flow result; | ||||
|  | ||||
|   /* send size */ | ||||
|  | ||||
|   result = send_io(fd, &size, sizeof(size)); | ||||
|  | ||||
|   /* send message */ | ||||
|  | ||||
|   if (result == MAD_FLOW_CONTINUE) | ||||
|     result = send_io(fd, message, size); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static | ||||
| enum mad_flow receive(int fd, void **message, unsigned int *size) | ||||
| { | ||||
|   enum mad_flow result; | ||||
|   unsigned int actual; | ||||
|  | ||||
|   if (*message == 0) | ||||
|     *size = 0; | ||||
|  | ||||
|   /* receive size */ | ||||
|  | ||||
|   result = receive_io(fd, &actual, sizeof(actual)); | ||||
|  | ||||
|   /* receive message */ | ||||
|  | ||||
|   if (result == MAD_FLOW_CONTINUE) { | ||||
|     if (actual > *size) | ||||
|       actual -= *size; | ||||
|     else { | ||||
|       *size  = actual; | ||||
|       actual = 0; | ||||
|     } | ||||
|  | ||||
|     if (*size > 0) { | ||||
|       if (*message == 0) { | ||||
| 	*message = malloc(*size); | ||||
| 	if (*message == 0) | ||||
| 	  return MAD_FLOW_BREAK; | ||||
|       } | ||||
|  | ||||
|       result = receive_io_blocking(fd, *message, *size); | ||||
|     } | ||||
|  | ||||
|     /* throw away remainder of message */ | ||||
|  | ||||
|     while (actual && result == MAD_FLOW_CONTINUE) { | ||||
|       char sink[256]; | ||||
|       unsigned int len; | ||||
|  | ||||
|       len = actual > sizeof(sink) ? sizeof(sink) : actual; | ||||
|  | ||||
|       result = receive_io_blocking(fd, sink, len); | ||||
|  | ||||
|       actual -= len; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static | ||||
| enum mad_flow check_message(struct mad_decoder *decoder) | ||||
| { | ||||
|   enum mad_flow result; | ||||
|   void *message = 0; | ||||
|   unsigned int size; | ||||
|  | ||||
|   result = receive(decoder->async.in, &message, &size); | ||||
|  | ||||
|   if (result == MAD_FLOW_CONTINUE) { | ||||
|     if (decoder->message_func == 0) | ||||
|       size = 0; | ||||
|     else { | ||||
|       result = decoder->message_func(decoder->cb_data, message, &size); | ||||
|  | ||||
|       if (result == MAD_FLOW_IGNORE || | ||||
| 	  result == MAD_FLOW_BREAK) | ||||
| 	size = 0; | ||||
|     } | ||||
|  | ||||
|     if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE) | ||||
|       result = MAD_FLOW_BREAK; | ||||
|   } | ||||
|  | ||||
|   if (message) | ||||
|     free(message); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
| # endif | ||||
|  | ||||
| static | ||||
| enum mad_flow error_default(void *data, struct mad_stream *stream, | ||||
| 			    struct mad_frame *frame) | ||||
| { | ||||
|   int *bad_last_frame = data; | ||||
|  | ||||
|   switch (stream->error) { | ||||
|   case MAD_ERROR_BADCRC: | ||||
|     if (*bad_last_frame) | ||||
|       mad_frame_mute(frame); | ||||
|     else | ||||
|       *bad_last_frame = 1; | ||||
|  | ||||
|     return MAD_FLOW_IGNORE; | ||||
|  | ||||
|   default: | ||||
|     return MAD_FLOW_CONTINUE; | ||||
|   } | ||||
| } | ||||
|  | ||||
| static | ||||
| int run_sync(struct mad_decoder *decoder) | ||||
| { | ||||
|   enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); | ||||
|   void *error_data; | ||||
|   int bad_last_frame = 0; | ||||
|   struct mad_stream *stream; | ||||
|   struct mad_frame *frame; | ||||
|   struct mad_synth *synth; | ||||
|   int result = 0; | ||||
|  | ||||
|   if (decoder->input_func == 0) | ||||
|     return 0; | ||||
|  | ||||
|   if (decoder->error_func) { | ||||
|     error_func = decoder->error_func; | ||||
|     error_data = decoder->cb_data; | ||||
|   } | ||||
|   else { | ||||
|     error_func = error_default; | ||||
|     error_data = &bad_last_frame; | ||||
|   } | ||||
|  | ||||
|   stream = &decoder->sync->stream; | ||||
|   frame  = &decoder->sync->frame; | ||||
|   synth  = &decoder->sync->synth; | ||||
|  | ||||
|   mad_stream_init(stream); | ||||
|   mad_frame_init(frame); | ||||
|   mad_synth_init(synth); | ||||
|  | ||||
|   mad_stream_options(stream, decoder->options); | ||||
|  | ||||
|   do { | ||||
|     switch (decoder->input_func(decoder->cb_data, stream)) { | ||||
|     case MAD_FLOW_STOP: | ||||
|       goto done; | ||||
|     case MAD_FLOW_BREAK: | ||||
|       goto fail; | ||||
|     case MAD_FLOW_IGNORE: | ||||
|       continue; | ||||
|     case MAD_FLOW_CONTINUE: | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     while (1) { | ||||
| # if defined(USE_ASYNC) | ||||
|       if (decoder->mode == MAD_DECODER_MODE_ASYNC) { | ||||
| 	switch (check_message(decoder)) { | ||||
| 	case MAD_FLOW_IGNORE: | ||||
| 	case MAD_FLOW_CONTINUE: | ||||
| 	  break; | ||||
| 	case MAD_FLOW_BREAK: | ||||
| 	  goto fail; | ||||
| 	case MAD_FLOW_STOP: | ||||
| 	  goto done; | ||||
| 	} | ||||
|       } | ||||
| # endif | ||||
|  | ||||
|       if (decoder->header_func) { | ||||
| 	if (mad_header_decode(&frame->header, stream) == -1) { | ||||
| 	  if (!MAD_RECOVERABLE(stream->error)) | ||||
| 	    break; | ||||
|  | ||||
| 	  switch (error_func(error_data, stream, frame)) { | ||||
| 	  case MAD_FLOW_STOP: | ||||
| 	    goto done; | ||||
| 	  case MAD_FLOW_BREAK: | ||||
| 	    goto fail; | ||||
| 	  case MAD_FLOW_IGNORE: | ||||
| 	  case MAD_FLOW_CONTINUE: | ||||
| 	  default: | ||||
| 	    continue; | ||||
| 	  } | ||||
| 	} | ||||
|  | ||||
| 	switch (decoder->header_func(decoder->cb_data, &frame->header)) { | ||||
| 	case MAD_FLOW_STOP: | ||||
| 	  goto done; | ||||
| 	case MAD_FLOW_BREAK: | ||||
| 	  goto fail; | ||||
| 	case MAD_FLOW_IGNORE: | ||||
| 	  continue; | ||||
| 	case MAD_FLOW_CONTINUE: | ||||
| 	  break; | ||||
| 	} | ||||
|       } | ||||
|  | ||||
|       if (mad_frame_decode(frame, stream) == -1) { | ||||
| 	if (!MAD_RECOVERABLE(stream->error)) | ||||
| 	  break; | ||||
|  | ||||
| 	switch (error_func(error_data, stream, frame)) { | ||||
| 	case MAD_FLOW_STOP: | ||||
| 	  goto done; | ||||
| 	case MAD_FLOW_BREAK: | ||||
| 	  goto fail; | ||||
| 	case MAD_FLOW_IGNORE: | ||||
| 	  break; | ||||
| 	case MAD_FLOW_CONTINUE: | ||||
| 	default: | ||||
| 	  continue; | ||||
| 	} | ||||
|       } | ||||
|       else | ||||
| 	bad_last_frame = 0; | ||||
|  | ||||
|       if (decoder->filter_func) { | ||||
| 	switch (decoder->filter_func(decoder->cb_data, stream, frame)) { | ||||
| 	case MAD_FLOW_STOP: | ||||
| 	  goto done; | ||||
| 	case MAD_FLOW_BREAK: | ||||
| 	  goto fail; | ||||
| 	case MAD_FLOW_IGNORE: | ||||
| 	  continue; | ||||
| 	case MAD_FLOW_CONTINUE: | ||||
| 	  break; | ||||
| 	} | ||||
|       } | ||||
|  | ||||
|       mad_synth_frame(synth, frame); | ||||
|  | ||||
|       if (decoder->output_func) { | ||||
| 	switch (decoder->output_func(decoder->cb_data, | ||||
| 				     &frame->header, &synth->pcm)) { | ||||
| 	case MAD_FLOW_STOP: | ||||
| 	  goto done; | ||||
| 	case MAD_FLOW_BREAK: | ||||
| 	  goto fail; | ||||
| 	case MAD_FLOW_IGNORE: | ||||
| 	case MAD_FLOW_CONTINUE: | ||||
| 	  break; | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   while (stream->error == MAD_ERROR_BUFLEN); | ||||
|  | ||||
|  fail: | ||||
|   result = -1; | ||||
|  | ||||
|  done: | ||||
|   mad_synth_finish(synth); | ||||
|   mad_frame_finish(frame); | ||||
|   mad_stream_finish(stream); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| # if defined(USE_ASYNC) | ||||
| static | ||||
| int run_async(struct mad_decoder *decoder) | ||||
| { | ||||
|   pid_t pid; | ||||
|   int ptoc[2], ctop[2], flags; | ||||
|  | ||||
|   if (pipe(ptoc) == -1) | ||||
|     return -1; | ||||
|  | ||||
|   if (pipe(ctop) == -1) { | ||||
|     close(ptoc[0]); | ||||
|     close(ptoc[1]); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   flags = fcntl(ptoc[0], F_GETFL); | ||||
|   if (flags == -1 || | ||||
|       fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) { | ||||
|     close(ctop[0]); | ||||
|     close(ctop[1]); | ||||
|     close(ptoc[0]); | ||||
|     close(ptoc[1]); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   pid = fork(); | ||||
|   if (pid == -1) { | ||||
|     close(ctop[0]); | ||||
|     close(ctop[1]); | ||||
|     close(ptoc[0]); | ||||
|     close(ptoc[1]); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   decoder->async.pid = pid; | ||||
|  | ||||
|   if (pid) { | ||||
|     /* parent */ | ||||
|  | ||||
|     close(ptoc[0]); | ||||
|     close(ctop[1]); | ||||
|  | ||||
|     decoder->async.in  = ctop[0]; | ||||
|     decoder->async.out = ptoc[1]; | ||||
|  | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   /* child */ | ||||
|  | ||||
|   close(ptoc[1]); | ||||
|   close(ctop[0]); | ||||
|  | ||||
|   decoder->async.in  = ptoc[0]; | ||||
|   decoder->async.out = ctop[1]; | ||||
|  | ||||
|   _exit(run_sync(decoder)); | ||||
|  | ||||
|   /* not reached */ | ||||
|   return -1; | ||||
| } | ||||
| # endif | ||||
|  | ||||
| /* | ||||
|  * NAME:	decoder->run() | ||||
|  * DESCRIPTION:	run the decoder thread either synchronously or asynchronously | ||||
|  */ | ||||
| int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode) | ||||
| { | ||||
|   int result; | ||||
|   int (*run)(struct mad_decoder *) = 0; | ||||
|  | ||||
|   switch (decoder->mode = mode) { | ||||
|   case MAD_DECODER_MODE_SYNC: | ||||
|     run = run_sync; | ||||
|     break; | ||||
|  | ||||
|   case MAD_DECODER_MODE_ASYNC: | ||||
| # if defined(USE_ASYNC) | ||||
|     run = run_async; | ||||
| # endif | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   if (run == 0) | ||||
|     return -1; | ||||
|  | ||||
|   decoder->sync = malloc(sizeof(*decoder->sync)); | ||||
|   if (decoder->sync == 0) | ||||
|     return -1; | ||||
|  | ||||
|   result = run(decoder); | ||||
|  | ||||
|   free(decoder->sync); | ||||
|   decoder->sync = 0; | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	decoder->message() | ||||
|  * DESCRIPTION:	send a message to and receive a reply from the decoder process | ||||
|  */ | ||||
| int mad_decoder_message(struct mad_decoder *decoder, | ||||
| 			void *message, unsigned int *len) | ||||
| { | ||||
| # if defined(USE_ASYNC) | ||||
|   if (decoder->mode != MAD_DECODER_MODE_ASYNC || | ||||
|       send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE || | ||||
|       receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE) | ||||
|     return -1; | ||||
|  | ||||
|   return 0; | ||||
| # else | ||||
|   return -1; | ||||
| # endif | ||||
| } | ||||
							
								
								
									
										91
									
								
								src/libmad/decoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/libmad/decoder.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: decoder.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_DECODER_H | ||||
| # define LIBMAD_DECODER_H | ||||
|  | ||||
| # include "stream.h" | ||||
| # include "frame.h" | ||||
| # include "synth.h" | ||||
|  | ||||
| enum mad_decoder_mode { | ||||
|   MAD_DECODER_MODE_SYNC  = 0, | ||||
|   MAD_DECODER_MODE_ASYNC | ||||
| }; | ||||
|  | ||||
| enum mad_flow { | ||||
|   MAD_FLOW_CONTINUE = 0x0000,	/* continue normally */ | ||||
|   MAD_FLOW_STOP     = 0x0010,	/* stop decoding normally */ | ||||
|   MAD_FLOW_BREAK    = 0x0011,	/* stop decoding and signal an error */ | ||||
|   MAD_FLOW_IGNORE   = 0x0020	/* ignore the current frame */ | ||||
| }; | ||||
|  | ||||
| struct mad_decoder { | ||||
|   enum mad_decoder_mode mode; | ||||
|  | ||||
|   int options; | ||||
|  | ||||
|   struct { | ||||
|     long pid; | ||||
|     int in; | ||||
|     int out; | ||||
|   } async; | ||||
|  | ||||
|   struct { | ||||
|     struct mad_stream stream; | ||||
|     struct mad_frame frame; | ||||
|     struct mad_synth synth; | ||||
|   } *sync; | ||||
|  | ||||
|   void *cb_data; | ||||
|  | ||||
|   enum mad_flow (*input_func)(void *, struct mad_stream *); | ||||
|   enum mad_flow (*header_func)(void *, struct mad_header const *); | ||||
|   enum mad_flow (*filter_func)(void *, | ||||
| 			       struct mad_stream const *, struct mad_frame *); | ||||
|   enum mad_flow (*output_func)(void *, | ||||
| 			       struct mad_header const *, struct mad_pcm *); | ||||
|   enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); | ||||
|   enum mad_flow (*message_func)(void *, void *, unsigned int *); | ||||
| }; | ||||
|  | ||||
| void mad_decoder_init(struct mad_decoder *, void *, | ||||
| 		      enum mad_flow (*)(void *, struct mad_stream *), | ||||
| 		      enum mad_flow (*)(void *, struct mad_header const *), | ||||
| 		      enum mad_flow (*)(void *, | ||||
| 					struct mad_stream const *, | ||||
| 					struct mad_frame *), | ||||
| 		      enum mad_flow (*)(void *, | ||||
| 					struct mad_header const *, | ||||
| 					struct mad_pcm *), | ||||
| 		      enum mad_flow (*)(void *, | ||||
| 					struct mad_stream *, | ||||
| 					struct mad_frame *), | ||||
| 		      enum mad_flow (*)(void *, void *, unsigned int *)); | ||||
| int mad_decoder_finish(struct mad_decoder *); | ||||
|  | ||||
| # define mad_decoder_options(decoder, opts)  \ | ||||
|     ((void) ((decoder)->options = (opts))) | ||||
|  | ||||
| int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode); | ||||
| int mad_decoder_message(struct mad_decoder *, void *, unsigned int *); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										81
									
								
								src/libmad/fixed.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/libmad/fixed.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: fixed.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include "fixed.h" | ||||
|  | ||||
| /* | ||||
|  * NAME:	fixed->abs() | ||||
|  * DESCRIPTION:	return absolute value of a fixed-point number | ||||
|  */ | ||||
| mad_fixed_t mad_f_abs(mad_fixed_t x) | ||||
| { | ||||
|   return x < 0 ? -x : x; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	fixed->div() | ||||
|  * DESCRIPTION:	perform division using fixed-point math | ||||
|  */ | ||||
| mad_fixed_t mad_f_div(mad_fixed_t x, mad_fixed_t y) | ||||
| { | ||||
|   mad_fixed_t q, r; | ||||
|   unsigned int bits; | ||||
|  | ||||
|   q = mad_f_abs(x / y); | ||||
|  | ||||
|   if (x < 0) { | ||||
|     x = -x; | ||||
|     y = -y; | ||||
|   } | ||||
|  | ||||
|   r = x % y; | ||||
|  | ||||
|   if (y < 0) { | ||||
|     x = -x; | ||||
|     y = -y; | ||||
|   } | ||||
|  | ||||
|   if (q > mad_f_intpart(MAD_F_MAX) && | ||||
|       !(q == -mad_f_intpart(MAD_F_MIN) && r == 0 && (x < 0) != (y < 0))) | ||||
|     return 0; | ||||
|  | ||||
|   for (bits = MAD_F_FRACBITS; bits && r; --bits) { | ||||
|     q <<= 1, r <<= 1; | ||||
|     if (r >= y) | ||||
|       r -= y, ++q; | ||||
|   } | ||||
|  | ||||
|   /* round */ | ||||
|   if (2 * r >= y) | ||||
|     ++q; | ||||
|  | ||||
|   /* fix sign */ | ||||
|   if ((x < 0) != (y < 0)) | ||||
|     q = -q; | ||||
|  | ||||
|   return q << bits; | ||||
| } | ||||
							
								
								
									
										484
									
								
								src/libmad/fixed.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								src/libmad/fixed.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,484 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: fixed.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_FIXED_H | ||||
| # define LIBMAD_FIXED_H | ||||
|  | ||||
| # if SIZEOF_INT >= 4 | ||||
| typedef   signed int mad_fixed_t; | ||||
|  | ||||
| typedef   signed int mad_fixed64hi_t; | ||||
| typedef unsigned int mad_fixed64lo_t; | ||||
| # else | ||||
| typedef   signed long mad_fixed_t; | ||||
|  | ||||
| typedef   signed long mad_fixed64hi_t; | ||||
| typedef unsigned long mad_fixed64lo_t; | ||||
| # endif | ||||
|  | ||||
| # if defined(_MSC_VER) | ||||
| #  define mad_fixed64_t  signed __int64 | ||||
| # elif 1 || defined(__GNUC__) | ||||
| #  define mad_fixed64_t  signed long long | ||||
| # endif | ||||
|  | ||||
| # if defined(FPM_FLOAT) | ||||
| typedef double mad_sample_t; | ||||
| # else | ||||
| typedef mad_fixed_t mad_sample_t; | ||||
| # endif | ||||
|  | ||||
| /* | ||||
|  * Fixed-point format: 0xABBBBBBB | ||||
|  * A == whole part      (sign + 3 bits) | ||||
|  * B == fractional part (28 bits) | ||||
|  * | ||||
|  * Values are signed two's complement, so the effective range is: | ||||
|  * 0x80000000 to 0x7fffffff | ||||
|  *       -8.0 to +7.9999999962747097015380859375 | ||||
|  * | ||||
|  * The smallest representable value is: | ||||
|  * 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9) | ||||
|  * | ||||
|  * 28 bits of fractional accuracy represent about | ||||
|  * 8.6 digits of decimal accuracy. | ||||
|  * | ||||
|  * Fixed-point numbers can be added or subtracted as normal | ||||
|  * integers, but multiplication requires shifting the 64-bit result | ||||
|  * from 56 fractional bits back to 28 (and rounding.) | ||||
|  * | ||||
|  * Changing the definition of MAD_F_FRACBITS is only partially | ||||
|  * supported, and must be done with care. | ||||
|  */ | ||||
|  | ||||
| # define MAD_F_FRACBITS		28 | ||||
|  | ||||
| # if MAD_F_FRACBITS == 28 | ||||
| #  define MAD_F(x)		((mad_fixed_t) (x##L)) | ||||
| # else | ||||
| #  if MAD_F_FRACBITS < 28 | ||||
| #   warning "MAD_F_FRACBITS < 28" | ||||
| #   define MAD_F(x)		((mad_fixed_t)  \ | ||||
| 				 (((x##L) +  \ | ||||
| 				   (1L << (28 - MAD_F_FRACBITS - 1))) >>  \ | ||||
| 				  (28 - MAD_F_FRACBITS))) | ||||
| #  elif MAD_F_FRACBITS > 28 | ||||
| #   error "MAD_F_FRACBITS > 28 not currently supported" | ||||
| #   define MAD_F(x)		((mad_fixed_t)  \ | ||||
| 				 ((x##L) << (MAD_F_FRACBITS - 28))) | ||||
| #  endif | ||||
| # endif | ||||
|  | ||||
| # define MAD_F_MIN		((mad_fixed_t) -0x80000000L) | ||||
| # define MAD_F_MAX		((mad_fixed_t) +0x7fffffffL) | ||||
|  | ||||
| # define MAD_F_ONE		MAD_F(0x10000000) | ||||
|  | ||||
| # define mad_f_tofixed(x)	((mad_fixed_t)  \ | ||||
| 				 ((x) * (double) (1L << MAD_F_FRACBITS) + 0.5)) | ||||
| # define mad_f_todouble(x)	((double)  \ | ||||
| 				 ((x) / (double) (1L << MAD_F_FRACBITS))) | ||||
|  | ||||
| # define mad_f_intpart(x)	((x) >> MAD_F_FRACBITS) | ||||
| # define mad_f_fracpart(x)	((x) & ((1L << MAD_F_FRACBITS) - 1)) | ||||
| 				/* (x should be positive) */ | ||||
|  | ||||
| # define mad_f_fromint(x)	((x) << MAD_F_FRACBITS) | ||||
|  | ||||
| # define mad_f_add(x, y)	((x) + (y)) | ||||
| # define mad_f_sub(x, y)	((x) - (y)) | ||||
|  | ||||
| # if defined(FPM_FLOAT) | ||||
| #  error "FPM_FLOAT not yet supported" | ||||
|  | ||||
| #  undef MAD_F | ||||
| #  define MAD_F(x)		mad_f_todouble(x) | ||||
|  | ||||
| #  define mad_f_mul(x, y)	((x) * (y)) | ||||
| #  define mad_f_scale64 | ||||
|  | ||||
| #  undef ASO_ZEROCHECK | ||||
|  | ||||
| # elif defined(FPM_64BIT) | ||||
|  | ||||
| /* | ||||
|  * This version should be the most accurate if 64-bit types are supported by | ||||
|  * the compiler, although it may not be the most efficient. | ||||
|  */ | ||||
| #  if defined(OPT_ACCURACY) | ||||
| #   define mad_f_mul(x, y)  \ | ||||
|     ((mad_fixed_t)  \ | ||||
|      ((((mad_fixed64_t) (x) * (y)) +  \ | ||||
|        (1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS)) | ||||
| #  else | ||||
| #   define mad_f_mul(x, y)  \ | ||||
|     ((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS)) | ||||
| #  endif | ||||
|  | ||||
| #  define MAD_F_SCALEBITS  MAD_F_FRACBITS | ||||
|  | ||||
| /* --- Intel --------------------------------------------------------------- */ | ||||
|  | ||||
| # elif defined(FPM_INTEL) | ||||
|  | ||||
| #  if defined(_MSC_VER) | ||||
| #   pragma warning(push) | ||||
| #   pragma warning(disable: 4035)  /* no return value */ | ||||
| static __forceinline | ||||
| mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y) | ||||
| { | ||||
|   enum { | ||||
|     fracbits = MAD_F_FRACBITS | ||||
|   }; | ||||
|  | ||||
|   __asm { | ||||
|     mov eax, x | ||||
|     imul y | ||||
|     shrd eax, edx, fracbits | ||||
|   } | ||||
|  | ||||
|   /* implicit return of eax */ | ||||
| } | ||||
| #   pragma warning(pop) | ||||
|  | ||||
| #   define mad_f_mul		mad_f_mul_inline | ||||
| #   define mad_f_scale64 | ||||
| #  else | ||||
| /* | ||||
|  * This Intel version is fast and accurate; the disposition of the least | ||||
|  * significant bit depends on OPT_ACCURACY via mad_f_scale64(). | ||||
|  */ | ||||
| #   define MAD_F_MLX(hi, lo, x, y)  \ | ||||
|     asm ("imull %3"  \ | ||||
| 	 : "=a" (lo), "=d" (hi)  \ | ||||
| 	 : "%a" (x), "rm" (y)  \ | ||||
| 	 : "cc") | ||||
|  | ||||
| #   if defined(OPT_ACCURACY) | ||||
| /* | ||||
|  * This gives best accuracy but is not very fast. | ||||
|  */ | ||||
| #    define MAD_F_MLA(hi, lo, x, y)  \ | ||||
|     ({ mad_fixed64hi_t __hi;  \ | ||||
|        mad_fixed64lo_t __lo;  \ | ||||
|        MAD_F_MLX(__hi, __lo, (x), (y));  \ | ||||
|        asm ("addl %2,%0\n\t"  \ | ||||
| 	    "adcl %3,%1"  \ | ||||
| 	    : "=rm" (lo), "=rm" (hi)  \ | ||||
| 	    : "r" (__lo), "r" (__hi), "0" (lo), "1" (hi)  \ | ||||
| 	    : "cc");  \ | ||||
|     }) | ||||
| #   endif  /* OPT_ACCURACY */ | ||||
|  | ||||
| #   if defined(OPT_ACCURACY) | ||||
| /* | ||||
|  * Surprisingly, this is faster than SHRD followed by ADC. | ||||
|  */ | ||||
| #    define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed64hi_t __hi_;  \ | ||||
|        mad_fixed64lo_t __lo_;  \ | ||||
|        mad_fixed_t __result;  \ | ||||
|        asm ("addl %4,%2\n\t"  \ | ||||
| 	    "adcl %5,%3"  \ | ||||
| 	    : "=rm" (__lo_), "=rm" (__hi_)  \ | ||||
| 	    : "0" (lo), "1" (hi),  \ | ||||
| 	      "ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0)  \ | ||||
| 	    : "cc");  \ | ||||
|        asm ("shrdl %3,%2,%1"  \ | ||||
| 	    : "=rm" (__result)  \ | ||||
| 	    : "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| #    else | ||||
| #    define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed_t __result;  \ | ||||
|        asm ("shrdl %3,%2,%1"  \ | ||||
| 	    : "=rm" (__result)  \ | ||||
| 	    : "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| #   endif  /* OPT_ACCURACY */ | ||||
|  | ||||
| #   define MAD_F_SCALEBITS  MAD_F_FRACBITS | ||||
| #  endif | ||||
|  | ||||
| /* --- ARM ----------------------------------------------------------------- */ | ||||
|  | ||||
| # elif defined(FPM_ARM) | ||||
|  | ||||
| /*  | ||||
|  * This ARM V4 version is as accurate as FPM_64BIT but much faster. The | ||||
|  * least significant bit is properly rounded at no CPU cycle cost! | ||||
|  */ | ||||
| # if 1 | ||||
| /* | ||||
|  * This is faster than the default implementation via MAD_F_MLX() and | ||||
|  * mad_f_scale64(). | ||||
|  */ | ||||
| #  define mad_f_mul(x, y)  \ | ||||
|     ({ mad_fixed64hi_t __hi;  \ | ||||
|        mad_fixed64lo_t __lo;  \ | ||||
|        mad_fixed_t __result;  \ | ||||
|        asm ("smull	%0, %1, %3, %4\n\t"  \ | ||||
| 	    "movs	%0, %0, lsr %5\n\t"  \ | ||||
| 	    "adc	%2, %0, %1, lsl %6"  \ | ||||
| 	    : "=&r" (__lo), "=&r" (__hi), "=r" (__result)  \ | ||||
| 	    : "%r" (x), "r" (y),  \ | ||||
| 	      "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| # endif | ||||
|  | ||||
| #  define MAD_F_MLX(hi, lo, x, y)  \ | ||||
|     asm ("smull	%0, %1, %2, %3"  \ | ||||
| 	 : "=&r" (lo), "=&r" (hi)  \ | ||||
| 	 : "%r" (x), "r" (y)) | ||||
|  | ||||
| #  define MAD_F_MLA(hi, lo, x, y)  \ | ||||
|     asm ("smlal	%0, %1, %2, %3"  \ | ||||
| 	 : "+r" (lo), "+r" (hi)  \ | ||||
| 	 : "%r" (x), "r" (y)) | ||||
|  | ||||
| #  define MAD_F_MLN(hi, lo)  \ | ||||
|     asm ("rsbs	%0, %2, #0\n\t"  \ | ||||
| 	 "rsc	%1, %3, #0"  \ | ||||
| 	 : "=r" (lo), "=r" (hi)  \ | ||||
| 	 : "0" (lo), "1" (hi)  \ | ||||
| 	 : "cc") | ||||
|  | ||||
| #  define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed_t __result;  \ | ||||
|        asm ("movs	%0, %1, lsr %3\n\t"  \ | ||||
| 	    "adc	%0, %0, %2, lsl %4"  \ | ||||
| 	    : "=&r" (__result)  \ | ||||
| 	    : "r" (lo), "r" (hi),  \ | ||||
| 	      "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS)  \ | ||||
| 	    : "cc");  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
|  | ||||
| #  define MAD_F_SCALEBITS  MAD_F_FRACBITS | ||||
|  | ||||
| /* --- MIPS ---------------------------------------------------------------- */ | ||||
|  | ||||
| # elif defined(FPM_MIPS) | ||||
|  | ||||
| /* | ||||
|  * This MIPS version is fast and accurate; the disposition of the least | ||||
|  * significant bit depends on OPT_ACCURACY via mad_f_scale64(). | ||||
|  */ | ||||
| #  define MAD_F_MLX(hi, lo, x, y)  \ | ||||
|     asm ("mult	%2,%3"  \ | ||||
| 	 : "=l" (lo), "=h" (hi)  \ | ||||
| 	 : "%r" (x), "r" (y)) | ||||
|  | ||||
| # if defined(HAVE_MADD_ASM) | ||||
| #  define MAD_F_MLA(hi, lo, x, y)  \ | ||||
|     asm ("madd	%2,%3"  \ | ||||
| 	 : "+l" (lo), "+h" (hi)  \ | ||||
| 	 : "%r" (x), "r" (y)) | ||||
| # elif defined(HAVE_MADD16_ASM) | ||||
| /* | ||||
|  * This loses significant accuracy due to the 16-bit integer limit in the | ||||
|  * multiply/accumulate instruction. | ||||
|  */ | ||||
| #  define MAD_F_ML0(hi, lo, x, y)  \ | ||||
|     asm ("mult	%2,%3"  \ | ||||
| 	 : "=l" (lo), "=h" (hi)  \ | ||||
| 	 : "%r" ((x) >> 12), "r" ((y) >> 16)) | ||||
| #  define MAD_F_MLA(hi, lo, x, y)  \ | ||||
|     asm ("madd16	%2,%3"  \ | ||||
| 	 : "+l" (lo), "+h" (hi)  \ | ||||
| 	 : "%r" ((x) >> 12), "r" ((y) >> 16)) | ||||
| #  define MAD_F_MLZ(hi, lo)  ((mad_fixed_t) (lo)) | ||||
| # endif | ||||
|  | ||||
| # if defined(OPT_SPEED) | ||||
| #  define mad_f_scale64(hi, lo)  \ | ||||
|     ((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS))) | ||||
| #  define MAD_F_SCALEBITS  MAD_F_FRACBITS | ||||
| # endif | ||||
|  | ||||
| /* --- SPARC --------------------------------------------------------------- */ | ||||
|  | ||||
| # elif defined(FPM_SPARC) | ||||
|  | ||||
| /* | ||||
|  * This SPARC V8 version is fast and accurate; the disposition of the least | ||||
|  * significant bit depends on OPT_ACCURACY via mad_f_scale64(). | ||||
|  */ | ||||
| #  define MAD_F_MLX(hi, lo, x, y)  \ | ||||
|     asm ("smul %2, %3, %0\n\t"  \ | ||||
| 	 "rd %%y, %1"  \ | ||||
| 	 : "=r" (lo), "=r" (hi)  \ | ||||
| 	 : "%r" (x), "rI" (y)) | ||||
|  | ||||
| /* --- PowerPC ------------------------------------------------------------- */ | ||||
|  | ||||
| # elif defined(FPM_PPC) | ||||
|  | ||||
| /* | ||||
|  * This PowerPC version is fast and accurate; the disposition of the least | ||||
|  * significant bit depends on OPT_ACCURACY via mad_f_scale64(). | ||||
|  */ | ||||
| #  define MAD_F_MLX(hi, lo, x, y)  \ | ||||
|     do {  \ | ||||
|       asm ("mullw %0,%1,%2"  \ | ||||
| 	   : "=r" (lo)  \ | ||||
| 	   : "%r" (x), "r" (y));  \ | ||||
|       asm ("mulhw %0,%1,%2"  \ | ||||
| 	   : "=r" (hi)  \ | ||||
| 	   : "%r" (x), "r" (y));  \ | ||||
|     }  \ | ||||
|     while (0) | ||||
|  | ||||
| #  if defined(OPT_ACCURACY) | ||||
| /* | ||||
|  * This gives best accuracy but is not very fast. | ||||
|  */ | ||||
| #   define MAD_F_MLA(hi, lo, x, y)  \ | ||||
|     ({ mad_fixed64hi_t __hi;  \ | ||||
|        mad_fixed64lo_t __lo;  \ | ||||
|        MAD_F_MLX(__hi, __lo, (x), (y));  \ | ||||
|        asm ("addc %0,%2,%3\n\t"  \ | ||||
| 	    "adde %1,%4,%5"  \ | ||||
| 	    : "=r" (lo), "=r" (hi)  \ | ||||
| 	    : "%r" (lo), "r" (__lo),  \ | ||||
| 	      "%r" (hi), "r" (__hi)  \ | ||||
| 	    : "xer");  \ | ||||
|     }) | ||||
| #  endif | ||||
|  | ||||
| #  if defined(OPT_ACCURACY) | ||||
| /* | ||||
|  * This is slower than the truncating version below it. | ||||
|  */ | ||||
| #   define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed_t __result, __round;  \ | ||||
|        asm ("rotrwi %0,%1,%2"  \ | ||||
| 	    : "=r" (__result)  \ | ||||
| 	    : "r" (lo), "i" (MAD_F_SCALEBITS));  \ | ||||
|        asm ("extrwi %0,%1,1,0"  \ | ||||
| 	    : "=r" (__round)  \ | ||||
| 	    : "r" (__result));  \ | ||||
|        asm ("insrwi %0,%1,%2,0"  \ | ||||
| 	    : "+r" (__result)  \ | ||||
| 	    : "r" (hi), "i" (MAD_F_SCALEBITS));  \ | ||||
|        asm ("add %0,%1,%2"  \ | ||||
| 	    : "=r" (__result)  \ | ||||
| 	    : "%r" (__result), "r" (__round));  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| #  else | ||||
| #   define mad_f_scale64(hi, lo)  \ | ||||
|     ({ mad_fixed_t __result;  \ | ||||
|        asm ("rotrwi %0,%1,%2"  \ | ||||
| 	    : "=r" (__result)  \ | ||||
| 	    : "r" (lo), "i" (MAD_F_SCALEBITS));  \ | ||||
|        asm ("insrwi %0,%1,%2,0"  \ | ||||
| 	    : "+r" (__result)  \ | ||||
| 	    : "r" (hi), "i" (MAD_F_SCALEBITS));  \ | ||||
|        __result;  \ | ||||
|     }) | ||||
| #  endif | ||||
|  | ||||
| #  define MAD_F_SCALEBITS  MAD_F_FRACBITS | ||||
|  | ||||
| /* --- Default ------------------------------------------------------------- */ | ||||
|  | ||||
| # elif defined(FPM_DEFAULT) | ||||
|  | ||||
| /* | ||||
|  * This version is the most portable but it loses significant accuracy. | ||||
|  * Furthermore, accuracy is biased against the second argument, so care | ||||
|  * should be taken when ordering operands. | ||||
|  * | ||||
|  * The scale factors are constant as this is not used with SSO. | ||||
|  * | ||||
|  * Pre-rounding is required to stay within the limits of compliance. | ||||
|  */ | ||||
| #  if defined(OPT_SPEED) | ||||
| #   define mad_f_mul(x, y)	(((x) >> 12) * ((y) >> 16)) | ||||
| #  else | ||||
| #   define mad_f_mul(x, y)	((((x) + (1L << 11)) >> 12) *  \ | ||||
| 				 (((y) + (1L << 15)) >> 16)) | ||||
| #  endif | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| # else | ||||
| #  error "no FPM selected" | ||||
| # endif | ||||
|  | ||||
| /* default implementations */ | ||||
|  | ||||
| # if !defined(mad_f_mul) | ||||
| #  define mad_f_mul(x, y)  \ | ||||
|     ({ register mad_fixed64hi_t __hi;  \ | ||||
|        register mad_fixed64lo_t __lo;  \ | ||||
|        MAD_F_MLX(__hi, __lo, (x), (y));  \ | ||||
|        mad_f_scale64(__hi, __lo);  \ | ||||
|     }) | ||||
| # endif | ||||
|  | ||||
| # if !defined(MAD_F_MLA) | ||||
| #  define MAD_F_ML0(hi, lo, x, y)	((lo)  = mad_f_mul((x), (y))) | ||||
| #  define MAD_F_MLA(hi, lo, x, y)	((lo) += mad_f_mul((x), (y))) | ||||
| #  define MAD_F_MLN(hi, lo)		((lo)  = -(lo)) | ||||
| #  define MAD_F_MLZ(hi, lo)		((void) (hi), (mad_fixed_t) (lo)) | ||||
| # endif | ||||
|  | ||||
| # if !defined(MAD_F_ML0) | ||||
| #  define MAD_F_ML0(hi, lo, x, y)	MAD_F_MLX((hi), (lo), (x), (y)) | ||||
| # endif | ||||
|  | ||||
| # if !defined(MAD_F_MLN) | ||||
| #  define MAD_F_MLN(hi, lo)		((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi)) | ||||
| # endif | ||||
|  | ||||
| # if !defined(MAD_F_MLZ) | ||||
| #  define MAD_F_MLZ(hi, lo)		mad_f_scale64((hi), (lo)) | ||||
| # endif | ||||
|  | ||||
| # if !defined(mad_f_scale64) | ||||
| #  if defined(OPT_ACCURACY) | ||||
| #   define mad_f_scale64(hi, lo)  \ | ||||
|     ((((mad_fixed_t)  \ | ||||
|        (((hi) << (32 - (MAD_F_SCALEBITS - 1))) |  \ | ||||
| 	((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1) | ||||
| #  else | ||||
| #   define mad_f_scale64(hi, lo)  \ | ||||
|     ((mad_fixed_t)  \ | ||||
|      (((hi) << (32 - MAD_F_SCALEBITS)) |  \ | ||||
|       ((lo) >> MAD_F_SCALEBITS))) | ||||
| #  endif | ||||
| #  define MAD_F_SCALEBITS  MAD_F_FRACBITS | ||||
| # endif | ||||
|  | ||||
| /* C routines */ | ||||
|  | ||||
| mad_fixed_t mad_f_abs(mad_fixed_t); | ||||
| mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										502
									
								
								src/libmad/frame.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										502
									
								
								src/libmad/frame.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,502 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: frame.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # include <stdlib.h> | ||||
|  | ||||
| # include "bit.h" | ||||
| # include "stream.h" | ||||
| # include "frame.h" | ||||
| # include "timer.h" | ||||
| # include "layer12.h" | ||||
| # include "layer3.h" | ||||
|  | ||||
| static | ||||
| unsigned long const bitrate_table[5][15] = { | ||||
|   /* MPEG-1 */ | ||||
|   { 0,  32000,  64000,  96000, 128000, 160000, 192000, 224000,  /* Layer I   */ | ||||
|        256000, 288000, 320000, 352000, 384000, 416000, 448000 }, | ||||
|   { 0,  32000,  48000,  56000,  64000,  80000,  96000, 112000,  /* Layer II  */ | ||||
|        128000, 160000, 192000, 224000, 256000, 320000, 384000 }, | ||||
|   { 0,  32000,  40000,  48000,  56000,  64000,  80000,  96000,  /* Layer III */ | ||||
|        112000, 128000, 160000, 192000, 224000, 256000, 320000 }, | ||||
|  | ||||
|   /* MPEG-2 LSF */ | ||||
|   { 0,  32000,  48000,  56000,  64000,  80000,  96000, 112000,  /* Layer I   */ | ||||
|        128000, 144000, 160000, 176000, 192000, 224000, 256000 }, | ||||
|   { 0,   8000,  16000,  24000,  32000,  40000,  48000,  56000,  /* Layers    */ | ||||
|         64000,  80000,  96000, 112000, 128000, 144000, 160000 } /* II & III  */ | ||||
| }; | ||||
|  | ||||
| static | ||||
| unsigned int const samplerate_table[3] = { 44100, 48000, 32000 }; | ||||
|  | ||||
| static | ||||
| int (*const decoder_table[3])(struct mad_stream *, struct mad_frame *) = { | ||||
|   mad_layer_I, | ||||
|   mad_layer_II, | ||||
|   mad_layer_III | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * NAME:	header->init() | ||||
|  * DESCRIPTION:	initialize header struct | ||||
|  */ | ||||
| void mad_header_init(struct mad_header *header) | ||||
| { | ||||
|   header->layer          = 0; | ||||
|   header->mode           = 0; | ||||
|   header->mode_extension = 0; | ||||
|   header->emphasis       = 0; | ||||
|  | ||||
|   header->bitrate        = 0; | ||||
|   header->samplerate     = 0; | ||||
|  | ||||
|   header->crc_check      = 0; | ||||
|   header->crc_target     = 0; | ||||
|  | ||||
|   header->flags          = 0; | ||||
|   header->private_bits   = 0; | ||||
|  | ||||
|   header->duration       = mad_timer_zero; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->init() | ||||
|  * DESCRIPTION:	initialize frame struct | ||||
|  */ | ||||
| void mad_frame_init(struct mad_frame *frame) | ||||
| { | ||||
|   mad_header_init(&frame->header); | ||||
|  | ||||
|   frame->options = 0; | ||||
|  | ||||
|   frame->overlap = 0; | ||||
|   mad_frame_mute(frame); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->finish() | ||||
|  * DESCRIPTION:	deallocate any dynamic memory associated with frame | ||||
|  */ | ||||
| void mad_frame_finish(struct mad_frame *frame) | ||||
| { | ||||
|   mad_header_finish(&frame->header); | ||||
|  | ||||
|   if (frame->overlap) { | ||||
|     free(frame->overlap); | ||||
|     frame->overlap = 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	decode_header() | ||||
|  * DESCRIPTION:	read header data and following CRC word | ||||
|  */ | ||||
| static | ||||
| int decode_header(struct mad_header *header, struct mad_stream *stream) | ||||
| { | ||||
|   unsigned int index; | ||||
|  | ||||
|   header->flags        = 0; | ||||
|   header->private_bits = 0; | ||||
|  | ||||
|   /* header() */ | ||||
|  | ||||
|   /* syncword */ | ||||
|   mad_bit_skip(&stream->ptr, 11); | ||||
|  | ||||
|   /* MPEG 2.5 indicator (really part of syncword) */ | ||||
|   if (mad_bit_read(&stream->ptr, 1) == 0) | ||||
|     header->flags |= MAD_FLAG_MPEG_2_5_EXT; | ||||
|  | ||||
|   /* ID */ | ||||
|   if (mad_bit_read(&stream->ptr, 1) == 0) | ||||
|     header->flags |= MAD_FLAG_LSF_EXT; | ||||
|   else if (header->flags & MAD_FLAG_MPEG_2_5_EXT) { | ||||
|     stream->error = MAD_ERROR_LOSTSYNC; | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   /* layer */ | ||||
|   header->layer = 4 - mad_bit_read(&stream->ptr, 2); | ||||
|  | ||||
|   if (header->layer == 4) { | ||||
|     stream->error = MAD_ERROR_BADLAYER; | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   /* protection_bit */ | ||||
|   if (mad_bit_read(&stream->ptr, 1) == 0) { | ||||
|     header->flags    |= MAD_FLAG_PROTECTION; | ||||
|     header->crc_check = mad_bit_crc(stream->ptr, 16, 0xffff); | ||||
|   } | ||||
|  | ||||
|   /* bitrate_index */ | ||||
|   index = mad_bit_read(&stream->ptr, 4); | ||||
|  | ||||
|   if (index == 15) { | ||||
|     stream->error = MAD_ERROR_BADBITRATE; | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   if (header->flags & MAD_FLAG_LSF_EXT) | ||||
|     header->bitrate = bitrate_table[3 + (header->layer >> 1)][index]; | ||||
|   else | ||||
|     header->bitrate = bitrate_table[header->layer - 1][index]; | ||||
|  | ||||
|   /* sampling_frequency */ | ||||
|   index = mad_bit_read(&stream->ptr, 2); | ||||
|  | ||||
|   if (index == 3) { | ||||
|     stream->error = MAD_ERROR_BADSAMPLERATE; | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   header->samplerate = samplerate_table[index]; | ||||
|  | ||||
|   if (header->flags & MAD_FLAG_LSF_EXT) { | ||||
|     header->samplerate /= 2; | ||||
|  | ||||
|     if (header->flags & MAD_FLAG_MPEG_2_5_EXT) | ||||
|       header->samplerate /= 2; | ||||
|   } | ||||
|  | ||||
|   /* padding_bit */ | ||||
|   if (mad_bit_read(&stream->ptr, 1)) | ||||
|     header->flags |= MAD_FLAG_PADDING; | ||||
|  | ||||
|   /* private_bit */ | ||||
|   if (mad_bit_read(&stream->ptr, 1)) | ||||
|     header->private_bits |= MAD_PRIVATE_HEADER; | ||||
|  | ||||
|   /* mode */ | ||||
|   header->mode = 3 - mad_bit_read(&stream->ptr, 2); | ||||
|  | ||||
|   /* mode_extension */ | ||||
|   header->mode_extension = mad_bit_read(&stream->ptr, 2); | ||||
|  | ||||
|   /* copyright */ | ||||
|   if (mad_bit_read(&stream->ptr, 1)) | ||||
|     header->flags |= MAD_FLAG_COPYRIGHT; | ||||
|  | ||||
|   /* original/copy */ | ||||
|   if (mad_bit_read(&stream->ptr, 1)) | ||||
|     header->flags |= MAD_FLAG_ORIGINAL; | ||||
|  | ||||
|   /* emphasis */ | ||||
|   header->emphasis = mad_bit_read(&stream->ptr, 2); | ||||
|  | ||||
| # if defined(OPT_STRICT) | ||||
|   /* | ||||
|    * ISO/IEC 11172-3 says this is a reserved emphasis value, but | ||||
|    * streams exist which use it anyway. Since the value is not important | ||||
|    * to the decoder proper, we allow it unless OPT_STRICT is defined. | ||||
|    */ | ||||
|   if (header->emphasis == MAD_EMPHASIS_RESERVED) { | ||||
|     stream->error = MAD_ERROR_BADEMPHASIS; | ||||
|     return -1; | ||||
|   } | ||||
| # endif | ||||
|  | ||||
|   /* error_check() */ | ||||
|  | ||||
|   /* crc_check */ | ||||
|   if (header->flags & MAD_FLAG_PROTECTION) | ||||
|     header->crc_target = mad_bit_read(&stream->ptr, 16); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	free_bitrate() | ||||
|  * DESCRIPTION:	attempt to discover the bitstream's free bitrate | ||||
|  */ | ||||
| static | ||||
| int free_bitrate(struct mad_stream *stream, struct mad_header const *header) | ||||
| { | ||||
|   struct mad_bitptr keep_ptr; | ||||
|   unsigned long rate = 0; | ||||
|   unsigned int pad_slot, slots_per_frame; | ||||
|   unsigned char const *ptr = 0; | ||||
|  | ||||
|   keep_ptr = stream->ptr; | ||||
|  | ||||
|   pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0; | ||||
|   slots_per_frame = (header->layer == MAD_LAYER_III && | ||||
| 		     (header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144; | ||||
|  | ||||
|   while (mad_stream_sync(stream) == 0) { | ||||
|     struct mad_stream peek_stream; | ||||
|     struct mad_header peek_header; | ||||
|  | ||||
|     peek_stream = *stream; | ||||
|     peek_header = *header; | ||||
|  | ||||
|     if (decode_header(&peek_header, &peek_stream) == 0 && | ||||
| 	peek_header.layer == header->layer && | ||||
| 	peek_header.samplerate == header->samplerate) { | ||||
|       unsigned int N; | ||||
|  | ||||
|       ptr = mad_bit_nextbyte(&stream->ptr); | ||||
|  | ||||
|       N = ptr - stream->this_frame; | ||||
|  | ||||
|       if (header->layer == MAD_LAYER_I) { | ||||
| 	rate = (unsigned long) header->samplerate * | ||||
| 	  (N - 4 * pad_slot + 4) / 48 / 1000; | ||||
|       } | ||||
|       else { | ||||
| 	rate = (unsigned long) header->samplerate * | ||||
| 	  (N - pad_slot + 1) / slots_per_frame / 1000; | ||||
|       } | ||||
|  | ||||
|       if (rate >= 8) | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     mad_bit_skip(&stream->ptr, 8); | ||||
|   } | ||||
|  | ||||
|   stream->ptr = keep_ptr; | ||||
|  | ||||
|   if (rate < 8 || (header->layer == MAD_LAYER_III && rate > 640)) { | ||||
|     stream->error = MAD_ERROR_LOSTSYNC; | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   stream->freerate = rate * 1000; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	header->decode() | ||||
|  * DESCRIPTION:	read the next frame header from the stream | ||||
|  */ | ||||
| int mad_header_decode(struct mad_header *header, struct mad_stream *stream) | ||||
| { | ||||
|   register unsigned char const *ptr, *end; | ||||
|   unsigned int pad_slot, N; | ||||
|  | ||||
|   ptr = stream->next_frame; | ||||
|   end = stream->bufend; | ||||
|  | ||||
|   if (ptr == 0) { | ||||
|     stream->error = MAD_ERROR_BUFPTR; | ||||
|     goto fail; | ||||
|   } | ||||
|  | ||||
|   /* stream skip */ | ||||
|   if (stream->skiplen) { | ||||
|     if (!stream->sync) | ||||
|       ptr = stream->this_frame; | ||||
|  | ||||
|     if (end - ptr < stream->skiplen) { | ||||
|       stream->skiplen   -= end - ptr; | ||||
|       stream->next_frame = end; | ||||
|  | ||||
|       stream->error = MAD_ERROR_BUFLEN; | ||||
|       goto fail; | ||||
|     } | ||||
|  | ||||
|     ptr += stream->skiplen; | ||||
|     stream->skiplen = 0; | ||||
|  | ||||
|     stream->sync = 1; | ||||
|   } | ||||
|  | ||||
|  sync: | ||||
|   /* synchronize */ | ||||
|   if (stream->sync) { | ||||
|     if (end - ptr < MAD_BUFFER_GUARD) { | ||||
|       stream->next_frame = ptr; | ||||
|  | ||||
|       stream->error = MAD_ERROR_BUFLEN; | ||||
|       goto fail; | ||||
|     } | ||||
|     else if (!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) { | ||||
|       /* mark point where frame sync word was expected */ | ||||
|       stream->this_frame = ptr; | ||||
|       stream->next_frame = ptr + 1; | ||||
|  | ||||
|       stream->error = MAD_ERROR_LOSTSYNC; | ||||
|       goto fail; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     mad_bit_init(&stream->ptr, ptr); | ||||
|  | ||||
|     if (mad_stream_sync(stream) == -1) { | ||||
|       if (end - stream->next_frame >= MAD_BUFFER_GUARD) | ||||
| 	stream->next_frame = end - MAD_BUFFER_GUARD; | ||||
|  | ||||
|       stream->error = MAD_ERROR_BUFLEN; | ||||
|       goto fail; | ||||
|     } | ||||
|  | ||||
|     ptr = mad_bit_nextbyte(&stream->ptr); | ||||
|   } | ||||
|  | ||||
|   /* begin processing */ | ||||
|   stream->this_frame = ptr; | ||||
|   stream->next_frame = ptr + 1;  /* possibly bogus sync word */ | ||||
|  | ||||
|   mad_bit_init(&stream->ptr, stream->this_frame); | ||||
|  | ||||
|   if (decode_header(header, stream) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   /* calculate frame duration */ | ||||
|   mad_timer_set(&header->duration, 0, | ||||
| 		32 * MAD_NSBSAMPLES(header), header->samplerate); | ||||
|  | ||||
|   /* calculate free bit rate */ | ||||
|   if (header->bitrate == 0) { | ||||
|     if ((stream->freerate == 0 || !stream->sync) && | ||||
| 	free_bitrate(stream, header) == -1) | ||||
|       goto fail; | ||||
|  | ||||
|     header->bitrate = stream->freerate; | ||||
|     header->flags  |= MAD_FLAG_FREEFORMAT; | ||||
|   } | ||||
|  | ||||
|   /* calculate beginning of next frame */ | ||||
|   pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0; | ||||
|  | ||||
|   if (header->layer == MAD_LAYER_I) | ||||
|     N = ((12 * header->bitrate / header->samplerate) + pad_slot) * 4; | ||||
|   else { | ||||
|     unsigned int slots_per_frame; | ||||
|  | ||||
|     slots_per_frame = (header->layer == MAD_LAYER_III && | ||||
| 		       (header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144; | ||||
|  | ||||
|     N = (slots_per_frame * header->bitrate / header->samplerate) + pad_slot; | ||||
|   } | ||||
|  | ||||
|   /* verify there is enough data left in buffer to decode this frame */ | ||||
|   if (N + MAD_BUFFER_GUARD > end - stream->this_frame) { | ||||
|     stream->next_frame = stream->this_frame; | ||||
|  | ||||
|     stream->error = MAD_ERROR_BUFLEN; | ||||
|     goto fail; | ||||
|   } | ||||
|  | ||||
|   stream->next_frame = stream->this_frame + N; | ||||
|  | ||||
|   if (!stream->sync) { | ||||
|     /* check that a valid frame header follows this frame */ | ||||
|  | ||||
|     ptr = stream->next_frame; | ||||
|     if (!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) { | ||||
|       ptr = stream->next_frame = stream->this_frame + 1; | ||||
|       goto sync; | ||||
|     } | ||||
|  | ||||
|     stream->sync = 1; | ||||
|   } | ||||
|  | ||||
|   header->flags |= MAD_FLAG_INCOMPLETE; | ||||
|  | ||||
|   return 0; | ||||
|  | ||||
|  fail: | ||||
|   stream->sync = 0; | ||||
|  | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->decode() | ||||
|  * DESCRIPTION:	decode a single frame from a bitstream | ||||
|  */ | ||||
| int mad_frame_decode(struct mad_frame *frame, struct mad_stream *stream) | ||||
| { | ||||
|   frame->options = stream->options; | ||||
|  | ||||
|   /* header() */ | ||||
|   /* error_check() */ | ||||
|  | ||||
|   if (!(frame->header.flags & MAD_FLAG_INCOMPLETE) && | ||||
|       mad_header_decode(&frame->header, stream) == -1) | ||||
|     goto fail; | ||||
|  | ||||
|   /* audio_data() */ | ||||
|  | ||||
|   frame->header.flags &= ~MAD_FLAG_INCOMPLETE; | ||||
|  | ||||
|   if (decoder_table[frame->header.layer - 1](stream, frame) == -1) { | ||||
|     if (!MAD_RECOVERABLE(stream->error)) | ||||
|       stream->next_frame = stream->this_frame; | ||||
|  | ||||
|     goto fail; | ||||
|   } | ||||
|  | ||||
|   /* ancillary_data() */ | ||||
|  | ||||
|   if (frame->header.layer != MAD_LAYER_III) { | ||||
|     struct mad_bitptr next_frame; | ||||
|  | ||||
|     mad_bit_init(&next_frame, stream->next_frame); | ||||
|  | ||||
|     stream->anc_ptr    = stream->ptr; | ||||
|     stream->anc_bitlen = mad_bit_length(&stream->ptr, &next_frame); | ||||
|  | ||||
|     mad_bit_finish(&next_frame); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
|  | ||||
|  fail: | ||||
|   stream->anc_bitlen = 0; | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	frame->mute() | ||||
|  * DESCRIPTION:	zero all subband values so the frame becomes silent | ||||
|  */ | ||||
| void mad_frame_mute(struct mad_frame *frame) | ||||
| { | ||||
|   unsigned int s, sb; | ||||
|  | ||||
|   for (s = 0; s < 36; ++s) { | ||||
|     for (sb = 0; sb < 32; ++sb) { | ||||
|       frame->sbsample[0][s][sb] = | ||||
|       frame->sbsample[1][s][sb] = 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (frame->overlap) { | ||||
|     for (s = 0; s < 18; ++s) { | ||||
|       for (sb = 0; sb < 32; ++sb) { | ||||
| 	(*frame->overlap)[0][sb][s] = | ||||
| 	(*frame->overlap)[1][sb][s] = 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										118
									
								
								src/libmad/frame.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/libmad/frame.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: frame.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_FRAME_H | ||||
| # define LIBMAD_FRAME_H | ||||
|  | ||||
| # include "fixed.h" | ||||
| # include "timer.h" | ||||
| # include "stream.h" | ||||
|  | ||||
| enum mad_layer { | ||||
|   MAD_LAYER_I   = 1,			/* Layer I */ | ||||
|   MAD_LAYER_II  = 2,			/* Layer II */ | ||||
|   MAD_LAYER_III = 3			/* Layer III */ | ||||
| }; | ||||
|  | ||||
| enum mad_mode { | ||||
|   MAD_MODE_SINGLE_CHANNEL = 0,		/* single channel */ | ||||
|   MAD_MODE_DUAL_CHANNEL	  = 1,		/* dual channel */ | ||||
|   MAD_MODE_JOINT_STEREO	  = 2,		/* joint (MS/intensity) stereo */ | ||||
|   MAD_MODE_STEREO	  = 3		/* normal LR stereo */ | ||||
| }; | ||||
|  | ||||
| enum mad_emphasis { | ||||
|   MAD_EMPHASIS_NONE	  = 0,		/* no emphasis */ | ||||
|   MAD_EMPHASIS_50_15_US	  = 1,		/* 50/15 microseconds emphasis */ | ||||
|   MAD_EMPHASIS_CCITT_J_17 = 3,		/* CCITT J.17 emphasis */ | ||||
|   MAD_EMPHASIS_RESERVED   = 2		/* unknown emphasis */ | ||||
| }; | ||||
|  | ||||
| struct mad_header { | ||||
|   enum mad_layer layer;			/* audio layer (1, 2, or 3) */ | ||||
|   enum mad_mode mode;			/* channel mode (see above) */ | ||||
|   int mode_extension;			/* additional mode info */ | ||||
|   enum mad_emphasis emphasis;		/* de-emphasis to use (see above) */ | ||||
|  | ||||
|   unsigned long bitrate;		/* stream bitrate (bps) */ | ||||
|   unsigned int samplerate;		/* sampling frequency (Hz) */ | ||||
|  | ||||
|   unsigned short crc_check;		/* frame CRC accumulator */ | ||||
|   unsigned short crc_target;		/* final target CRC checksum */ | ||||
|  | ||||
|   int flags;				/* flags (see below) */ | ||||
|   int private_bits;			/* private bits (see below) */ | ||||
|  | ||||
|   mad_timer_t duration;			/* audio playing time of frame */ | ||||
| }; | ||||
|  | ||||
| struct mad_frame { | ||||
|   struct mad_header header;		/* MPEG audio header */ | ||||
|  | ||||
|   int options;				/* decoding options (from stream) */ | ||||
|  | ||||
|   mad_fixed_t sbsample[2][36][32];	/* synthesis subband filter samples */ | ||||
|   mad_fixed_t (*overlap)[2][32][18];	/* Layer III block overlap data */ | ||||
| }; | ||||
|  | ||||
| # define MAD_NCHANNELS(header)		((header)->mode ? 2 : 1) | ||||
| # define MAD_NSBSAMPLES(header)  \ | ||||
|   ((header)->layer == MAD_LAYER_I ? 12 :  \ | ||||
|    (((header)->layer == MAD_LAYER_III &&  \ | ||||
|      ((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36)) | ||||
|  | ||||
| enum { | ||||
|   MAD_FLAG_NPRIVATE_III	= 0x0007,	/* number of Layer III private bits */ | ||||
|   MAD_FLAG_INCOMPLETE	= 0x0008,	/* header but not data is decoded */ | ||||
|  | ||||
|   MAD_FLAG_PROTECTION	= 0x0010,	/* frame has CRC protection */ | ||||
|   MAD_FLAG_COPYRIGHT	= 0x0020,	/* frame is copyright */ | ||||
|   MAD_FLAG_ORIGINAL	= 0x0040,	/* frame is original (else copy) */ | ||||
|   MAD_FLAG_PADDING	= 0x0080,	/* frame has additional slot */ | ||||
|  | ||||
|   MAD_FLAG_I_STEREO	= 0x0100,	/* uses intensity joint stereo */ | ||||
|   MAD_FLAG_MS_STEREO	= 0x0200,	/* uses middle/side joint stereo */ | ||||
|   MAD_FLAG_FREEFORMAT	= 0x0400,	/* uses free format bitrate */ | ||||
|  | ||||
|   MAD_FLAG_LSF_EXT	= 0x1000,	/* lower sampling freq. extension */ | ||||
|   MAD_FLAG_MC_EXT	= 0x2000,	/* multichannel audio extension */ | ||||
|   MAD_FLAG_MPEG_2_5_EXT	= 0x4000	/* MPEG 2.5 (unofficial) extension */ | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   MAD_PRIVATE_HEADER	= 0x0100,	/* header private bit */ | ||||
|   MAD_PRIVATE_III	= 0x001f	/* Layer III private bits (up to 5) */ | ||||
| }; | ||||
|  | ||||
| void mad_header_init(struct mad_header *); | ||||
|  | ||||
| # define mad_header_finish(header)  /* nothing */ | ||||
|  | ||||
| int mad_header_decode(struct mad_header *, struct mad_stream *); | ||||
|  | ||||
| void mad_frame_init(struct mad_frame *); | ||||
| void mad_frame_finish(struct mad_frame *); | ||||
|  | ||||
| int mad_frame_decode(struct mad_frame *, struct mad_stream *); | ||||
|  | ||||
| void mad_frame_mute(struct mad_frame *); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										58
									
								
								src/libmad/global.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/libmad/global.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: global.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_GLOBAL_H | ||||
| # define LIBMAD_GLOBAL_H | ||||
|  | ||||
| /* conditional debugging */ | ||||
|  | ||||
| # if defined(DEBUG) && defined(NDEBUG) | ||||
| #  error "cannot define both DEBUG and NDEBUG" | ||||
| # endif | ||||
|  | ||||
| # if defined(DEBUG) | ||||
| #  include <stdio.h> | ||||
| # endif | ||||
|  | ||||
| /* conditional features */ | ||||
|  | ||||
| # if defined(OPT_SPEED) && defined(OPT_ACCURACY) | ||||
| #  error "cannot optimize for both speed and accuracy" | ||||
| # endif | ||||
|  | ||||
| # if defined(OPT_SPEED) && !defined(OPT_SSO) | ||||
| #  define OPT_SSO | ||||
| # endif | ||||
|  | ||||
| # if defined(HAVE_UNISTD_H) && defined(HAVE_WAITPID) &&  \ | ||||
|     defined(HAVE_FCNTL) && defined(HAVE_PIPE) && defined(HAVE_FORK) | ||||
| #  define USE_ASYNC | ||||
| # endif | ||||
|  | ||||
| # if !defined(HAVE_ASSERT_H) | ||||
| #  if defined(NDEBUG) | ||||
| #   define assert(x)	/* nothing */ | ||||
| #  else | ||||
| #   define assert(x)	do { if (!(x)) abort(); } while (0) | ||||
| #  endif | ||||
| # endif | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										3098
									
								
								src/libmad/huffman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3098
									
								
								src/libmad/huffman.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										66
									
								
								src/libmad/huffman.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/libmad/huffman.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: huffman.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_HUFFMAN_H | ||||
| # define LIBMAD_HUFFMAN_H | ||||
|  | ||||
| union huffquad { | ||||
|   struct { | ||||
|     unsigned short final  :  1; | ||||
|     unsigned short bits   :  3; | ||||
|     unsigned short offset : 12; | ||||
|   } ptr; | ||||
|   struct { | ||||
|     unsigned short final  :  1; | ||||
|     unsigned short hlen   :  3; | ||||
|     unsigned short v      :  1; | ||||
|     unsigned short w      :  1; | ||||
|     unsigned short x      :  1; | ||||
|     unsigned short y      :  1; | ||||
|   } value; | ||||
|   unsigned short final    :  1; | ||||
| }; | ||||
|  | ||||
| union huffpair { | ||||
|   struct { | ||||
|     unsigned short final  :  1; | ||||
|     unsigned short bits   :  3; | ||||
|     unsigned short offset : 12; | ||||
|   } ptr; | ||||
|   struct { | ||||
|     unsigned short final  :  1; | ||||
|     unsigned short hlen   :  3; | ||||
|     unsigned short x      :  4; | ||||
|     unsigned short y      :  4; | ||||
|   } value; | ||||
|   unsigned short final    :  1; | ||||
| }; | ||||
|  | ||||
| struct hufftable { | ||||
|   union huffpair const *table; | ||||
|   unsigned short linbits; | ||||
|   unsigned short startbits; | ||||
| }; | ||||
|  | ||||
| extern union huffquad const *const mad_huff_quad_table[2]; | ||||
| extern struct hufftable const mad_huff_pair_table[32]; | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										1000
									
								
								src/libmad/imdct_l_arm.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1000
									
								
								src/libmad/imdct_l_arm.S
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										62
									
								
								src/libmad/imdct_s.dat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/libmad/imdct_s.dat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: imdct_s.dat,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
|   /*  0 */  {  MAD_F(0x09bd7ca0) /*  0.608761429 */, | ||||
| 	      -MAD_F(0x0ec835e8) /* -0.923879533 */, | ||||
| 	      -MAD_F(0x0216a2a2) /* -0.130526192 */, | ||||
| 	       MAD_F(0x0fdcf549) /*  0.991444861 */, | ||||
| 	      -MAD_F(0x061f78aa) /* -0.382683432 */, | ||||
| 	      -MAD_F(0x0cb19346) /* -0.793353340 */ }, | ||||
|  | ||||
|   /*  6 */  { -MAD_F(0x0cb19346) /* -0.793353340 */, | ||||
| 	       MAD_F(0x061f78aa) /*  0.382683432 */, | ||||
| 	       MAD_F(0x0fdcf549) /*  0.991444861 */, | ||||
| 	       MAD_F(0x0216a2a2) /*  0.130526192 */, | ||||
| 	      -MAD_F(0x0ec835e8) /* -0.923879533 */, | ||||
| 	      -MAD_F(0x09bd7ca0) /* -0.608761429 */ }, | ||||
|  | ||||
|   /*  1 */  {  MAD_F(0x061f78aa) /*  0.382683432 */, | ||||
| 	      -MAD_F(0x0ec835e8) /* -0.923879533 */, | ||||
| 	       MAD_F(0x0ec835e8) /*  0.923879533 */, | ||||
| 	      -MAD_F(0x061f78aa) /* -0.382683432 */, | ||||
| 	      -MAD_F(0x061f78aa) /* -0.382683432 */, | ||||
| 	       MAD_F(0x0ec835e8) /*  0.923879533 */ }, | ||||
|  | ||||
|   /*  7 */  { -MAD_F(0x0ec835e8) /* -0.923879533 */, | ||||
| 	      -MAD_F(0x061f78aa) /* -0.382683432 */, | ||||
| 	       MAD_F(0x061f78aa) /*  0.382683432 */, | ||||
| 	       MAD_F(0x0ec835e8) /*  0.923879533 */, | ||||
| 	       MAD_F(0x0ec835e8) /*  0.923879533 */, | ||||
| 	       MAD_F(0x061f78aa) /*  0.382683432 */ }, | ||||
|  | ||||
|   /*  2 */  {  MAD_F(0x0216a2a2) /*  0.130526192 */, | ||||
| 	      -MAD_F(0x061f78aa) /* -0.382683432 */, | ||||
| 	       MAD_F(0x09bd7ca0) /*  0.608761429 */, | ||||
| 	      -MAD_F(0x0cb19346) /* -0.793353340 */, | ||||
| 	       MAD_F(0x0ec835e8) /*  0.923879533 */, | ||||
| 	      -MAD_F(0x0fdcf549) /* -0.991444861 */ }, | ||||
|  | ||||
|   /*  8 */  { -MAD_F(0x0fdcf549) /* -0.991444861 */, | ||||
| 	      -MAD_F(0x0ec835e8) /* -0.923879533 */, | ||||
| 	      -MAD_F(0x0cb19346) /* -0.793353340 */, | ||||
| 	      -MAD_F(0x09bd7ca0) /* -0.608761429 */, | ||||
| 	      -MAD_F(0x061f78aa) /* -0.382683432 */, | ||||
| 	      -MAD_F(0x0216a2a2) /* -0.130526192 */ } | ||||
							
								
								
									
										510
									
								
								src/libmad/layer12.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								src/libmad/layer12.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,510 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: layer12.c,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifdef HAVE_CONFIG_H | ||||
| #  include "config.h" | ||||
| # endif | ||||
|  | ||||
| # include "global.h" | ||||
|  | ||||
| # ifdef HAVE_LIMITS_H | ||||
| #  include <limits.h> | ||||
| # else | ||||
| #  define CHAR_BIT  8 | ||||
| # endif | ||||
|  | ||||
| # include "fixed.h" | ||||
| # include "bit.h" | ||||
| # include "stream.h" | ||||
| # include "frame.h" | ||||
| # include "layer12.h" | ||||
|  | ||||
| /* | ||||
|  * scalefactor table | ||||
|  * used in both Layer I and Layer II decoding | ||||
|  */ | ||||
| static | ||||
| mad_fixed_t const sf_table[64] = { | ||||
| # include "sf_table.dat" | ||||
| }; | ||||
|  | ||||
| /* --- Layer I ------------------------------------------------------------- */ | ||||
|  | ||||
| /* linear scaling table */ | ||||
| static | ||||
| mad_fixed_t const linear_table[14] = { | ||||
|   MAD_F(0x15555555),  /* 2^2  / (2^2  - 1) == 1.33333333333333 */ | ||||
|   MAD_F(0x12492492),  /* 2^3  / (2^3  - 1) == 1.14285714285714 */ | ||||
|   MAD_F(0x11111111),  /* 2^4  / (2^4  - 1) == 1.06666666666667 */ | ||||
|   MAD_F(0x10842108),  /* 2^5  / (2^5  - 1) == 1.03225806451613 */ | ||||
|   MAD_F(0x10410410),  /* 2^6  / (2^6  - 1) == 1.01587301587302 */ | ||||
|   MAD_F(0x10204081),  /* 2^7  / (2^7  - 1) == 1.00787401574803 */ | ||||
|   MAD_F(0x10101010),  /* 2^8  / (2^8  - 1) == 1.00392156862745 */ | ||||
|   MAD_F(0x10080402),  /* 2^9  / (2^9  - 1) == 1.00195694716243 */ | ||||
|   MAD_F(0x10040100),  /* 2^10 / (2^10 - 1) == 1.00097751710655 */ | ||||
|   MAD_F(0x10020040),  /* 2^11 / (2^11 - 1) == 1.00048851978505 */ | ||||
|   MAD_F(0x10010010),  /* 2^12 / (2^12 - 1) == 1.00024420024420 */ | ||||
|   MAD_F(0x10008004),  /* 2^13 / (2^13 - 1) == 1.00012208521548 */ | ||||
|   MAD_F(0x10004001),  /* 2^14 / (2^14 - 1) == 1.00006103888177 */ | ||||
|   MAD_F(0x10002000)   /* 2^15 / (2^15 - 1) == 1.00003051850948 */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * NAME:	I_sample() | ||||
|  * DESCRIPTION:	decode one requantized Layer I sample from a bitstream | ||||
|  */ | ||||
| static | ||||
| mad_fixed_t I_sample(struct mad_bitptr *ptr, unsigned int nb) | ||||
| { | ||||
|   mad_fixed_t sample; | ||||
|  | ||||
|   sample = mad_bit_read(ptr, nb); | ||||
|  | ||||
|   /* invert most significant bit, extend sign, then scale to fixed format */ | ||||
|  | ||||
|   sample ^= 1 << (nb - 1); | ||||
|   sample |= -(sample & (1 << (nb - 1))); | ||||
|  | ||||
|   sample <<= MAD_F_FRACBITS - (nb - 1); | ||||
|  | ||||
|   /* requantize the sample */ | ||||
|  | ||||
|   /* s'' = (2^nb / (2^nb - 1)) * (s''' + 2^(-nb + 1)) */ | ||||
|  | ||||
|   sample += MAD_F_ONE >> (nb - 1); | ||||
|  | ||||
|   return mad_f_mul(sample, linear_table[nb - 2]); | ||||
|  | ||||
|   /* s' = factor * s'' */ | ||||
|   /* (to be performed by caller) */ | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	layer->I() | ||||
|  * DESCRIPTION:	decode a single Layer I frame | ||||
|  */ | ||||
| int mad_layer_I(struct mad_stream *stream, struct mad_frame *frame) | ||||
| { | ||||
|   struct mad_header *header = &frame->header; | ||||
|   unsigned int nch, bound, ch, s, sb, nb; | ||||
|   unsigned char allocation[2][32], scalefactor[2][32]; | ||||
|  | ||||
|   nch = MAD_NCHANNELS(header); | ||||
|  | ||||
|   bound = 32; | ||||
|   if (header->mode == MAD_MODE_JOINT_STEREO) { | ||||
|     header->flags |= MAD_FLAG_I_STEREO; | ||||
|     bound = 4 + header->mode_extension * 4; | ||||
|   } | ||||
|  | ||||
|   /* check CRC word */ | ||||
|  | ||||
|   if (header->flags & MAD_FLAG_PROTECTION) { | ||||
|     header->crc_check = | ||||
|       mad_bit_crc(stream->ptr, 4 * (bound * nch + (32 - bound)), | ||||
| 		  header->crc_check); | ||||
|  | ||||
|     if (header->crc_check != header->crc_target && | ||||
| 	!(frame->options & MAD_OPTION_IGNORECRC)) { | ||||
|       stream->error = MAD_ERROR_BADCRC; | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* decode bit allocations */ | ||||
|  | ||||
|   for (sb = 0; sb < bound; ++sb) { | ||||
|     for (ch = 0; ch < nch; ++ch) { | ||||
|       nb = mad_bit_read(&stream->ptr, 4); | ||||
|  | ||||
|       if (nb == 15) { | ||||
| 	stream->error = MAD_ERROR_BADBITALLOC; | ||||
| 	return -1; | ||||
|       } | ||||
|  | ||||
|       allocation[ch][sb] = nb ? nb + 1 : 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (sb = bound; sb < 32; ++sb) { | ||||
|     nb = mad_bit_read(&stream->ptr, 4); | ||||
|  | ||||
|     if (nb == 15) { | ||||
|       stream->error = MAD_ERROR_BADBITALLOC; | ||||
|       return -1; | ||||
|     } | ||||
|  | ||||
|     allocation[0][sb] = | ||||
|     allocation[1][sb] = nb ? nb + 1 : 0; | ||||
|   } | ||||
|  | ||||
|   /* decode scalefactors */ | ||||
|  | ||||
|   for (sb = 0; sb < 32; ++sb) { | ||||
|     for (ch = 0; ch < nch; ++ch) { | ||||
|       if (allocation[ch][sb]) { | ||||
| 	scalefactor[ch][sb] = mad_bit_read(&stream->ptr, 6); | ||||
|  | ||||
| # if defined(OPT_STRICT) | ||||
| 	/* | ||||
| 	 * Scalefactor index 63 does not appear in Table B.1 of | ||||
| 	 * ISO/IEC 11172-3. Nonetheless, other implementations accept it, | ||||
| 	 * so we only reject it if OPT_STRICT is defined. | ||||
| 	 */ | ||||
| 	if (scalefactor[ch][sb] == 63) { | ||||
| 	  stream->error = MAD_ERROR_BADSCALEFACTOR; | ||||
| 	  return -1; | ||||
| 	} | ||||
| # endif | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* decode samples */ | ||||
|  | ||||
|   for (s = 0; s < 12; ++s) { | ||||
|     for (sb = 0; sb < bound; ++sb) { | ||||
|       for (ch = 0; ch < nch; ++ch) { | ||||
| 	nb = allocation[ch][sb]; | ||||
| 	frame->sbsample[ch][s][sb] = nb ? | ||||
| 	  mad_f_mul(I_sample(&stream->ptr, nb), | ||||
| 		    sf_table[scalefactor[ch][sb]]) : 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     for (sb = bound; sb < 32; ++sb) { | ||||
|       if ((nb = allocation[0][sb])) { | ||||
| 	mad_fixed_t sample; | ||||
|  | ||||
| 	sample = I_sample(&stream->ptr, nb); | ||||
|  | ||||
| 	for (ch = 0; ch < nch; ++ch) { | ||||
| 	  frame->sbsample[ch][s][sb] = | ||||
| 	    mad_f_mul(sample, sf_table[scalefactor[ch][sb]]); | ||||
| 	} | ||||
|       } | ||||
|       else { | ||||
| 	for (ch = 0; ch < nch; ++ch) | ||||
| 	  frame->sbsample[ch][s][sb] = 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* --- Layer II ------------------------------------------------------------ */ | ||||
|  | ||||
| /* possible quantization per subband table */ | ||||
| static | ||||
| struct { | ||||
|   unsigned int sblimit; | ||||
|   unsigned char const offsets[30]; | ||||
| } const sbquant_table[5] = { | ||||
|   /* ISO/IEC 11172-3 Table B.2a */ | ||||
|   { 27, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3,	/* 0 */ | ||||
| 	  3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 } }, | ||||
|   /* ISO/IEC 11172-3 Table B.2b */ | ||||
|   { 30, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3,	/* 1 */ | ||||
| 	  3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 } }, | ||||
|   /* ISO/IEC 11172-3 Table B.2c */ | ||||
|   {  8, { 5, 5, 2, 2, 2, 2, 2, 2 } },				/* 2 */ | ||||
|   /* ISO/IEC 11172-3 Table B.2d */ | ||||
|   { 12, { 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } },		/* 3 */ | ||||
|   /* ISO/IEC 13818-3 Table B.1 */ | ||||
|   { 30, { 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,	/* 4 */ | ||||
| 	  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } } | ||||
| }; | ||||
|  | ||||
| /* bit allocation table */ | ||||
| static | ||||
| struct { | ||||
|   unsigned short nbal; | ||||
|   unsigned short offset; | ||||
| } const bitalloc_table[8] = { | ||||
|   { 2, 0 },  /* 0 */ | ||||
|   { 2, 3 },  /* 1 */ | ||||
|   { 3, 3 },  /* 2 */ | ||||
|   { 3, 1 },  /* 3 */ | ||||
|   { 4, 2 },  /* 4 */ | ||||
|   { 4, 3 },  /* 5 */ | ||||
|   { 4, 4 },  /* 6 */ | ||||
|   { 4, 5 }   /* 7 */ | ||||
| }; | ||||
|  | ||||
| /* offsets into quantization class table */ | ||||
| static | ||||
| unsigned char const offset_table[6][15] = { | ||||
|   { 0, 1, 16                                             },  /* 0 */ | ||||
|   { 0, 1,  2, 3, 4, 5, 16                                },  /* 1 */ | ||||
|   { 0, 1,  2, 3, 4, 5,  6, 7,  8,  9, 10, 11, 12, 13, 14 },  /* 2 */ | ||||
|   { 0, 1,  3, 4, 5, 6,  7, 8,  9, 10, 11, 12, 13, 14, 15 },  /* 3 */ | ||||
|   { 0, 1,  2, 3, 4, 5,  6, 7,  8,  9, 10, 11, 12, 13, 16 },  /* 4 */ | ||||
|   { 0, 2,  4, 5, 6, 7,  8, 9, 10, 11, 12, 13, 14, 15, 16 }   /* 5 */ | ||||
| }; | ||||
|  | ||||
| /* quantization class table */ | ||||
| static | ||||
| struct quantclass { | ||||
|   unsigned short nlevels; | ||||
|   unsigned char group; | ||||
|   unsigned char bits; | ||||
|   mad_fixed_t C; | ||||
|   mad_fixed_t D; | ||||
| } const qc_table[17] = { | ||||
| # include "qc_table.dat" | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * NAME:	II_samples() | ||||
|  * DESCRIPTION:	decode three requantized Layer II samples from a bitstream | ||||
|  */ | ||||
| static | ||||
| void II_samples(struct mad_bitptr *ptr, | ||||
| 		struct quantclass const *quantclass, | ||||
| 		mad_fixed_t output[3]) | ||||
| { | ||||
|   unsigned int nb, s, sample[3]; | ||||
|  | ||||
|   if ((nb = quantclass->group)) { | ||||
|     unsigned int c, nlevels; | ||||
|  | ||||
|     /* degrouping */ | ||||
|     c = mad_bit_read(ptr, quantclass->bits); | ||||
|     nlevels = quantclass->nlevels; | ||||
|  | ||||
|     for (s = 0; s < 3; ++s) { | ||||
|       sample[s] = c % nlevels; | ||||
|       c /= nlevels; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     nb = quantclass->bits; | ||||
|  | ||||
|     for (s = 0; s < 3; ++s) | ||||
|       sample[s] = mad_bit_read(ptr, nb); | ||||
|   } | ||||
|  | ||||
|   for (s = 0; s < 3; ++s) { | ||||
|     mad_fixed_t requantized; | ||||
|  | ||||
|     /* invert most significant bit, extend sign, then scale to fixed format */ | ||||
|  | ||||
|     requantized  = sample[s] ^ (1 << (nb - 1)); | ||||
|     requantized |= -(requantized & (1 << (nb - 1))); | ||||
|  | ||||
|     requantized <<= MAD_F_FRACBITS - (nb - 1); | ||||
|  | ||||
|     /* requantize the sample */ | ||||
|  | ||||
|     /* s'' = C * (s''' + D) */ | ||||
|  | ||||
|     output[s] = mad_f_mul(requantized + quantclass->D, quantclass->C); | ||||
|  | ||||
|     /* s' = factor * s'' */ | ||||
|     /* (to be performed by caller) */ | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * NAME:	layer->II() | ||||
|  * DESCRIPTION:	decode a single Layer II frame | ||||
|  */ | ||||
| int mad_layer_II(struct mad_stream *stream, struct mad_frame *frame) | ||||
| { | ||||
|   struct mad_header *header = &frame->header; | ||||
|   struct mad_bitptr start; | ||||
|   unsigned int index, sblimit, nbal, nch, bound, gr, ch, s, sb; | ||||
|   unsigned char const *offsets; | ||||
|   unsigned char allocation[2][32], scfsi[2][32], scalefactor[2][32][3]; | ||||
|   mad_fixed_t samples[3]; | ||||
|  | ||||
|   nch = MAD_NCHANNELS(header); | ||||
|  | ||||
|   if (header->flags & MAD_FLAG_LSF_EXT) | ||||
|     index = 4; | ||||
|   else { | ||||
|     switch (nch == 2 ? header->bitrate / 2 : header->bitrate) { | ||||
|     case 32000: | ||||
|     case 48000: | ||||
|       index = (header->samplerate == 32000) ? 3 : 2; | ||||
|       break; | ||||
|  | ||||
|     case 56000: | ||||
|     case 64000: | ||||
|     case 80000: | ||||
|       index = 0; | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       index = (header->samplerate == 48000) ? 0 : 1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   sblimit = sbquant_table[index].sblimit; | ||||
|   offsets = sbquant_table[index].offsets; | ||||
|  | ||||
|   bound = 32; | ||||
|   if (header->mode == MAD_MODE_JOINT_STEREO) { | ||||
|     header->flags |= MAD_FLAG_I_STEREO; | ||||
|     bound = 4 + header->mode_extension * 4; | ||||
|   } | ||||
|  | ||||
|   if (bound > sblimit) | ||||
|     bound = sblimit; | ||||
|  | ||||
|   start = stream->ptr; | ||||
|  | ||||
|   /* decode bit allocations */ | ||||
|  | ||||
|   for (sb = 0; sb < bound; ++sb) { | ||||
|     nbal = bitalloc_table[offsets[sb]].nbal; | ||||
|  | ||||
|     for (ch = 0; ch < nch; ++ch) | ||||
|       allocation[ch][sb] = mad_bit_read(&stream->ptr, nbal); | ||||
|   } | ||||
|  | ||||
|   for (sb = bound; sb < sblimit; ++sb) { | ||||
|     nbal = bitalloc_table[offsets[sb]].nbal; | ||||
|  | ||||
|     allocation[0][sb] = | ||||
|     allocation[1][sb] = mad_bit_read(&stream->ptr, nbal); | ||||
|   } | ||||
|  | ||||
|   /* decode scalefactor selection info */ | ||||
|  | ||||
|   for (sb = 0; sb < sblimit; ++sb) { | ||||
|     for (ch = 0; ch < nch; ++ch) { | ||||
|       if (allocation[ch][sb]) | ||||
| 	scfsi[ch][sb] = mad_bit_read(&stream->ptr, 2); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* check CRC word */ | ||||
|  | ||||
|   if (header->flags & MAD_FLAG_PROTECTION) { | ||||
|     header->crc_check = | ||||
|       mad_bit_crc(start, mad_bit_length(&start, &stream->ptr), | ||||
| 		  header->crc_check); | ||||
|  | ||||
|     if (header->crc_check != header->crc_target && | ||||
| 	!(frame->options & MAD_OPTION_IGNORECRC)) { | ||||
|       stream->error = MAD_ERROR_BADCRC; | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* decode scalefactors */ | ||||
|  | ||||
|   for (sb = 0; sb < sblimit; ++sb) { | ||||
|     for (ch = 0; ch < nch; ++ch) { | ||||
|       if (allocation[ch][sb]) { | ||||
| 	scalefactor[ch][sb][0] = mad_bit_read(&stream->ptr, 6); | ||||
|  | ||||
| 	switch (scfsi[ch][sb]) { | ||||
| 	case 2: | ||||
| 	  scalefactor[ch][sb][2] = | ||||
| 	  scalefactor[ch][sb][1] = | ||||
| 	  scalefactor[ch][sb][0]; | ||||
| 	  break; | ||||
|  | ||||
| 	case 0: | ||||
| 	  scalefactor[ch][sb][1] = mad_bit_read(&stream->ptr, 6); | ||||
| 	  /* fall through */ | ||||
|  | ||||
| 	case 1: | ||||
| 	case 3: | ||||
| 	  scalefactor[ch][sb][2] = mad_bit_read(&stream->ptr, 6); | ||||
| 	} | ||||
|  | ||||
| 	if (scfsi[ch][sb] & 1) | ||||
| 	  scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1]; | ||||
|  | ||||
| # if defined(OPT_STRICT) | ||||
| 	/* | ||||
| 	 * Scalefactor index 63 does not appear in Table B.1 of | ||||
| 	 * ISO/IEC 11172-3. Nonetheless, other implementations accept it, | ||||
| 	 * so we only reject it if OPT_STRICT is defined. | ||||
| 	 */ | ||||
| 	if (scalefactor[ch][sb][0] == 63 || | ||||
| 	    scalefactor[ch][sb][1] == 63 || | ||||
| 	    scalefactor[ch][sb][2] == 63) { | ||||
| 	  stream->error = MAD_ERROR_BADSCALEFACTOR; | ||||
| 	  return -1; | ||||
| 	} | ||||
| # endif | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* decode samples */ | ||||
|  | ||||
|   for (gr = 0; gr < 12; ++gr) { | ||||
|     for (sb = 0; sb < bound; ++sb) { | ||||
|       for (ch = 0; ch < nch; ++ch) { | ||||
| 	if ((index = allocation[ch][sb])) { | ||||
| 	  index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1]; | ||||
|  | ||||
| 	  II_samples(&stream->ptr, &qc_table[index], samples); | ||||
|  | ||||
| 	  for (s = 0; s < 3; ++s) { | ||||
| 	    frame->sbsample[ch][3 * gr + s][sb] = | ||||
| 	      mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]); | ||||
| 	  } | ||||
| 	} | ||||
| 	else { | ||||
| 	  for (s = 0; s < 3; ++s) | ||||
| 	    frame->sbsample[ch][3 * gr + s][sb] = 0; | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     for (sb = bound; sb < sblimit; ++sb) { | ||||
|       if ((index = allocation[0][sb])) { | ||||
| 	index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1]; | ||||
|  | ||||
| 	II_samples(&stream->ptr, &qc_table[index], samples); | ||||
|  | ||||
| 	for (ch = 0; ch < nch; ++ch) { | ||||
| 	  for (s = 0; s < 3; ++s) { | ||||
| 	    frame->sbsample[ch][3 * gr + s][sb] = | ||||
| 	      mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]); | ||||
| 	  } | ||||
| 	} | ||||
|       } | ||||
|       else { | ||||
| 	for (ch = 0; ch < nch; ++ch) { | ||||
| 	  for (s = 0; s < 3; ++s) | ||||
| 	    frame->sbsample[ch][3 * gr + s][sb] = 0; | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     for (ch = 0; ch < nch; ++ch) { | ||||
|       for (s = 0; s < 3; ++s) { | ||||
| 	for (sb = sblimit; sb < 32; ++sb) | ||||
| 	  frame->sbsample[ch][3 * gr + s][sb] = 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										31
									
								
								src/libmad/layer12.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/libmad/layer12.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: layer12.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_LAYER12_H | ||||
| # define LIBMAD_LAYER12_H | ||||
|  | ||||
| # include "stream.h" | ||||
| # include "frame.h" | ||||
|  | ||||
| int mad_layer_I(struct mad_stream *, struct mad_frame *); | ||||
| int mad_layer_II(struct mad_stream *, struct mad_frame *); | ||||
|  | ||||
| # endif | ||||
							
								
								
									
										2502
									
								
								src/libmad/layer3.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2502
									
								
								src/libmad/layer3.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										30
									
								
								src/libmad/layer3.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/libmad/layer3.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * libmad - MPEG audio decoder library | ||||
|  * Copyright (C) 2000-2003 Underbit Technologies, Inc. | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * $Id: layer3.h,v 1.1 2003/08/14 03:57:13 shank Exp $ | ||||
|  */ | ||||
|  | ||||
| # ifndef LIBMAD_LAYER3_H | ||||
| # define LIBMAD_LAYER3_H | ||||
|  | ||||
| # include "stream.h" | ||||
| # include "frame.h" | ||||
|  | ||||
| int mad_layer_III(struct mad_stream *, struct mad_frame *); | ||||
|  | ||||
| # endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 Warren Dukes
					Warren Dukes