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