From cc2160de5cc05dc3aa77f3a34358e66f6193c8c9 Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Tue, 26 Jun 2012 20:35:30 +0200 Subject: Add support for AAC. --- faad2/src/common/faad/aacinfo.c | 372 +++++++++++ faad2/src/common/faad/aacinfo.h | 53 ++ faad2/src/common/faad/aacinfo.sln | 19 + faad2/src/common/faad/aacinfo.vcproj | 224 +++++++ faad2/src/common/faad/filestream.c | 470 ++++++++++++++ faad2/src/common/faad/filestream.h | 57 ++ faad2/src/common/faad/getopt.c | 755 +++++++++++++++++++++++ faad2/src/common/faad/getopt.h | 130 ++++ faad2/src/common/faad/id3v2tag.c | 1124 ++++++++++++++++++++++++++++++++++ faad2/src/common/faad/id3v2tag.h | 54 ++ 10 files changed, 3258 insertions(+) create mode 100644 faad2/src/common/faad/aacinfo.c create mode 100644 faad2/src/common/faad/aacinfo.h create mode 100644 faad2/src/common/faad/aacinfo.sln create mode 100644 faad2/src/common/faad/aacinfo.vcproj create mode 100644 faad2/src/common/faad/filestream.c create mode 100644 faad2/src/common/faad/filestream.h create mode 100644 faad2/src/common/faad/getopt.c create mode 100644 faad2/src/common/faad/getopt.h create mode 100644 faad2/src/common/faad/id3v2tag.c create mode 100644 faad2/src/common/faad/id3v2tag.h (limited to 'faad2/src/common/faad') diff --git a/faad2/src/common/faad/aacinfo.c b/faad2/src/common/faad/aacinfo.c new file mode 100644 index 0000000..1cfbab2 --- /dev/null +++ b/faad2/src/common/faad/aacinfo.c @@ -0,0 +1,372 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: aacinfo.c,v 1.4 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include +#include "filestream.h" +#include "aacinfo.h" + +#define ADIF_MAX_SIZE 30 /* Should be enough */ +#define ADTS_MAX_SIZE 10 /* Should be enough */ + +static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000}; + +static int read_ADIF_header(FILE_STREAM *file, faadAACInfo *info) +{ + int bitstream; + unsigned char buffer[ADIF_MAX_SIZE]; + int skip_size = 0; + int sf_idx; + + /* Get ADIF header data */ + info->headertype = 1; + + if(read_buffer_filestream(file, buffer, ADIF_MAX_SIZE) < 0) + return -1; + + /* copyright string */ + if(buffer[0] & 0x80) + skip_size += 9; /* skip 9 bytes */ + + bitstream = buffer[0 + skip_size] & 0x10; + info->bitrate = ((unsigned int)(buffer[0 + skip_size] & 0x0F)<<19)| + ((unsigned int)buffer[1 + skip_size]<<11)| + ((unsigned int)buffer[2 + skip_size]<<3)| + ((unsigned int)buffer[3 + skip_size] & 0xE0); + + if (bitstream == 0) + { + info->object_type = ((buffer[6 + skip_size]&0x01)<<1)|((buffer[7 + skip_size]&0x80)>>7); + sf_idx = (buffer[7 + skip_size]&0x78)>>3; + } else { + info->object_type = (buffer[4 + skip_size] & 0x18)>>3; + sf_idx = ((buffer[4 + skip_size] & 0x07)<<1)|((buffer[5 + skip_size] & 0x80)>>7); + } + info->sampling_rate = sample_rates[sf_idx]; + + return 0; +} + +static int read_ADTS_header(FILE_STREAM *file, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int tagsize, int no_seek_table) +{ + /* Get ADTS header data */ + unsigned char buffer[ADTS_MAX_SIZE]; + int frames, framesinsec=0, t_framelength = 0, frame_length, sr_idx, ID; + int second = 0, pos; + int i; + float frames_per_sec = 0; + unsigned long bytes; + unsigned long *tmp_seek_table = NULL; + + info->headertype = 2; + + /* Read all frames to ensure correct time and bitrate */ + for(frames=0; /* */; frames++, framesinsec++) + { + /* If streaming, only go until we hit 5 seconds worth */ + if(file->http) + { + if(frames >= 43 * 5) + { + break; + } + } + + pos = tell_filestream(file); + + /* 12 bit SYNCWORD */ + bytes = read_buffer_filestream(file, buffer, ADTS_MAX_SIZE); + + if(bytes != ADTS_MAX_SIZE) + { + /* Bail out if no syncword found */ + break; + } + + /* check syncword */ + if (!((buffer[0] == 0xFF)&&((buffer[1] & 0xF6) == 0xF0))) + break; + + if(!frames) + { + /* fixed ADTS header is the same for every frame, so we read it only once */ + /* Syncword found, proceed to read in the fixed ADTS header */ + ID = buffer[1] & 0x08; + info->object_type = (buffer[2]&0xC0)>>6; + sr_idx = (buffer[2]&0x3C)>>2; + info->channels = ((buffer[2]&0x01)<<2)|((buffer[3]&0xC0)>>6); + + frames_per_sec = sample_rates[sr_idx] / 1024.f; + } + + /* ...and the variable ADTS header */ + if (ID == 0) { + info->version = 4; + } else { /* MPEG-2 */ + info->version = 2; + } + frame_length = ((((unsigned int)buffer[3] & 0x3)) << 11) + | (((unsigned int)buffer[4]) << 3) | (buffer[5] >> 5); + + t_framelength += frame_length; + + if(!file->http) + { + if(framesinsec == 43) + framesinsec = 0; + + if(framesinsec == 0 && seek_table_len) + { + tmp_seek_table = (unsigned long *) realloc(tmp_seek_table, (second + 1) * sizeof(unsigned long)); + tmp_seek_table[second] = pos; + } + if(framesinsec == 0) + second++; + } + + /* NOTE: While simply skipping ahead by reading may seem to be more work than seeking, + it is actually much faster, and keeps compatibility with streaming */ + for(i=0; i < frame_length - ADTS_MAX_SIZE; i++) + { + if(read_byte_filestream(file) < 0) + break; + } + } + + if(seek_table_len) + { + *seek_table_len = second; + *seek_table = tmp_seek_table; + } + + info->sampling_rate = sample_rates[sr_idx]; + info->bitrate = (int)(((t_framelength / frames) * (info->sampling_rate/1024.0)) +0.5)*8; + + if(file->http) + { + /* Since we only use 5 seconds of aac data to get a rough bitrate, we must use a different + method of calculating the overall length */ + if(filelength_filestream(file)) + { + info->length = (int)((filelength_filestream(file)/(((info->bitrate*8)/1024)*16))*1000); + } + else + { + /* Since the server didnt tell us how long the file is, + we have no way of determining length */ + info->length = 0; + } + } + else + { + info->length = (int)((float)(frames/frames_per_sec))*1000; + } + + return 0; +} + +int get_AAC_format(char *filename, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int no_seek_table) +{ + unsigned long tagsize; + FILE_STREAM *file; + char buffer[10]; + unsigned long file_len; + unsigned char adxx_id[5]; + unsigned long tmp; + + memset(info, 0, sizeof(faadAACInfo)); + + file = open_filestream(filename); + + if(file == NULL) + return -1; + + file_len = filelength_filestream(file); + + /* Skip the tag, if it's there */ + tmp = read_buffer_filestream(file, buffer, 10); + + if (StringComp(buffer, "ID3", 3) == 0) + { + unsigned int i; + + /* high bit is not used */ + tagsize = (buffer[6] << 21) | (buffer[7] << 14) | + (buffer[8] << 7) | (buffer[9] << 0); + + for(i=0; i < tagsize; i++) + if(read_byte_filestream(file) < 0) + return -1; + + tagsize += 10; + } + else + { + tagsize = 0; + + /* Simple hack to reset to the beginning */ + file->buffer_offset = 0; + file->file_offset = 0; + } + + if(file_len) + file_len -= tagsize; + + tmp = read_buffer_filestream(file, adxx_id, 2); + //seek_filestream(file, tagsize, FILE_BEGIN); + + adxx_id[5-1] = 0; + info->length = 0; + + /* Determine the header type of the file, check the first two bytes */ + if(StringComp(adxx_id, "AD", 2) == 0) + { + /* We think its an ADIF header, but check the rest just to make sure */ + tmp = read_buffer_filestream(file, adxx_id + 2, 2); + + if(StringComp(adxx_id, "ADIF", 4) == 0) + { + read_ADIF_header(file, info); + } + } + else + { + /* No ADIF, check for ADTS header */ + if ((adxx_id[0] == 0xFF)&&((adxx_id[1] & 0xF6) == 0xF0)) + { + /* ADTS header located */ + /* Since this routine must work for streams, we can't use the seek function to go backwards, thus + we have to use a quick hack as seen below to go back where we need to. */ + + if(file->buffer_offset >= 2) + { + // simple seeking hack, though not really safe, the probability of it causing a problem is low. + file->buffer_offset -= 2; + file->file_offset -= 2; + } + + read_ADTS_header(file, info, seek_table, seek_table_len, tagsize, + no_seek_table); + } + else + { + /* Unknown/headerless AAC file, assume format: */ + info->version = 2; + info->bitrate = 128000; + info->sampling_rate = 44100; + info->channels = 2; + info->headertype = 0; + info->object_type = 1; + } + } + + close_filestream(file); + + return 0; +} + +int StringComp(char const *str1, char const *str2, unsigned long len) +{ + signed int c1 = 0, c2 = 0; + + while (len--) { + c1 = *str1++; + c2 = *str2++; + + if (c1 == 0 || c1 != c2) + break; + } + + return c1 - c2; +} + +#ifdef TEST +/* Program to test aacinfo functionality */ + +#include + +void main(int argc, char *argv[]) +{ + faadAACInfo info; + unsigned long *seek_table = NULL; + int seek_table_len = 0; + char *header, *object; + + if (argc < 2) + { + fprintf(stderr, "USAGE: aacinfo aacfile.aac\n"); + return; + } + + get_AAC_format(argv[1], &info, &seek_table, &seek_table_len, 0); + + fprintf(stdout, "MPEG version: %d\n", info.version); + fprintf(stdout, "channels: %d\n", info.channels); + fprintf(stdout, "sampling_rate: %d\n", info.sampling_rate); + fprintf(stdout, "bitrate: %d\n", info.bitrate); + fprintf(stdout, "length: %.3f\n", (float)info.length/1000.0); + + switch (info.object_type) + { + case 0: + object = "MAIN"; + break; + case 1: + object = "LC"; + break; + case 2: + object = "SSR"; + break; + case 3: + object = "LTP"; + break; + } + fprintf(stdout, "object_type: %s\n", object); + + switch (info.headertype) + { + case 0: + header = "RAW"; + break; + case 1: + header = "ADIF"; + break; + case 2: + header = "ADTS"; + break; + } + fprintf(stdout, "headertype: %s\n", header); +} + +#endif \ No newline at end of file diff --git a/faad2/src/common/faad/aacinfo.h b/faad2/src/common/faad/aacinfo.h new file mode 100644 index 0000000..c0257a8 --- /dev/null +++ b/faad2/src/common/faad/aacinfo.h @@ -0,0 +1,53 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: aacinfo.h,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifndef AACINFO_H__ +#define AACINFO_H__ + +#include "filestream.h" + +typedef struct { + int version; + int channels; + int sampling_rate; + int bitrate; + int length; + int object_type; + int headertype; +} faadAACInfo; + +int get_AAC_format(char *filename, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int no_seek_table); + +static int read_ADIF_header(FILE_STREAM *file, faadAACInfo *info); +static int read_ADTS_header(FILE_STREAM *file, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int tagsize, int no_seek_table); +int StringComp(char const *str1, char const *str2, unsigned long len); + +#endif diff --git a/faad2/src/common/faad/aacinfo.sln b/faad2/src/common/faad/aacinfo.sln new file mode 100644 index 0000000..68a8a36 --- /dev/null +++ b/faad2/src/common/faad/aacinfo.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aacinfo", "aacinfo.vcproj", "{FE985E4D-79DB-4DD3-BFED-824B4677A161}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Debug|Win32.Build.0 = Debug|Win32 + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Release|Win32.ActiveCfg = Release|Win32 + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/faad2/src/common/faad/aacinfo.vcproj b/faad2/src/common/faad/aacinfo.vcproj new file mode 100644 index 0000000..bb0984c --- /dev/null +++ b/faad2/src/common/faad/aacinfo.vcproj @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faad2/src/common/faad/filestream.c b/faad2/src/common/faad/filestream.c new file mode 100644 index 0000000..0f82bdf --- /dev/null +++ b/faad2/src/common/faad/filestream.c @@ -0,0 +1,470 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: filestream.c,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +/* Not very portable yet */ + +#include // Note: Must be *before* windows.h +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include "filestream.h" +#include "aacinfo.h" + +/* TEMPROARY HACK */ +#define CommonExit(A) MessageBox(NULL, A, "FAAD Plugin", MB_OK) + +int winsock_init=0; // 0=winsock not initialized, 1=success +long m_local_buffer_size = 64; +long m_stream_buffer_size = 128; + +FILE_STREAM *open_filestream(char *filename) +{ + FILE_STREAM *fs; + + if(StringComp(filename,"http://", 7) == 0) + { + fs = (FILE_STREAM *)LocalAlloc(LPTR, sizeof(FILE_STREAM) + m_stream_buffer_size * 1024); + + if(fs == NULL) + return NULL; + + fs->data = (unsigned char *)&fs[1]; + + if(http_file_open(filename, fs) < 0) + { + LocalFree(fs); + return NULL; + } + + fs->http = 1; + } + else + { + fs = (FILE_STREAM*)LocalAlloc(LPTR, sizeof(FILE_STREAM) + m_local_buffer_size * 1024); + + if(fs == NULL) + return NULL; + + fs->data = (unsigned char *)&fs[1]; + + fs->stream = CreateFile(filename, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); + if (fs->stream == INVALID_HANDLE_VALUE) + { + LocalFree(fs); + return NULL; + } + + fs->http = 0; + } + + fs->buffer_length = 0; + fs->buffer_offset = 0; + fs->file_offset = 0; + + return fs; +} + +int read_byte_filestream(FILE_STREAM *fs) +{ + if(fs->buffer_offset == fs->buffer_length) + { + fs->buffer_offset = 0; + + if(fs->http) + fs->buffer_length = recv(fs->inetStream, fs->data, m_stream_buffer_size * 1024, 0); + else + ReadFile(fs->stream, fs->data, m_local_buffer_size * 1024, &fs->buffer_length, 0); + + if(fs->buffer_length <= 0) + { + if(fs->http) + { + int x; + x = WSAGetLastError(); + + if(x == 0) + { + /* Equivalent of a successful EOF for HTTP */ + } + } + + fs->buffer_length = 0; + return -1; + } + } + + fs->file_offset++; + + return fs->data[fs->buffer_offset++]; +} + +int read_buffer_filestream(FILE_STREAM *fs, void *data, int length) +{ + int i, tmp; + unsigned char *data2 = (unsigned char *)data; + + for(i=0; i < length; i++) + { + if((tmp = read_byte_filestream(fs)) < 0) + { + if(i) + { + break; + } + else + { + return -1; + } + } + data2[i] = tmp; + } + + return i; +} + +unsigned long filelength_filestream(FILE_STREAM *fs) +{ + unsigned long fsize; + + if (fs->http) + { + fsize = fs->http_file_length; + } + else + { + fsize = GetFileSize(fs->stream, NULL); + } + + return fsize; +} + +void seek_filestream(FILE_STREAM *fs, unsigned long offset, int mode) +{ + if(fs->http) + { + return; + } + + SetFilePointer(fs->stream, offset, NULL, mode); + + if(mode == FILE_CURRENT) + fs->file_offset += offset; + else if(mode == FILE_END) + fs->file_offset = filelength_filestream(fs) + offset; + else + fs->file_offset = offset; + + fs->buffer_length = 0; + fs->buffer_offset = 0; +} + +unsigned long tell_filestream(FILE_STREAM *fs) +{ + return fs->file_offset; +} + +void close_filestream(FILE_STREAM *fs) +{ + if(fs) + { + if (fs->http) + { + if (fs->inetStream) + { + /* The 'proper' way to close a TCP connection */ + if(fs->inetStream) + { + CloseTCP(fs->inetStream); + } + } + } + else + { + if(fs->stream) + CloseHandle(fs->stream); + } + + LocalFree(fs); + fs = NULL; + } +} + +int WinsockInit() +{ + /* Before using winsock, you must load the DLL... */ + WSADATA wsaData; + + /* Load version 2.0 */ + if (WSAStartup( MAKEWORD( 2, 0 ), &wsaData )) + { + /* Disable streaming */ + return -1; + } + + winsock_init = 1; + + return 0; +} + +void WinsockDeInit() +{ + /* Unload the DLL */ + + if(winsock_init) + WSACleanup(); +} + +int FindCRLF(char *str) +{ + int i; + + for(i=0; i != lstrlen(str) && str[i] != '\r'; i++); + + return i; +} + +void CloseTCP(int s) +{ + char tempbuf[1024]; + + /* Set the socket to ignore any new incoming data */ + shutdown(s, 1); + + /* Get any old remaining data */ + while(recv(s, tempbuf, 1024, 0) > 0); + + /* Deallocate the socket */ + closesocket(s); +} + +int resolve_host(char *host, SOCKADDR_IN *sck_addr, unsigned short remote_port) +{ + HOSTENT *hp; + + if (isalpha(host[0])) + { + /* server address is a name */ + hp = gethostbyname(host); + } + else + { + unsigned long addr; + /* Convert nnn.nnn address to a usable one */ + addr = inet_addr(host); + hp = gethostbyaddr((char *)&addr, 4, AF_INET); + } + + if (hp == NULL) + { + char tmp[128]; + wsprintf(tmp, "Error resolving host address [%s]!\n", host); + CommonExit(tmp); + return -1; + } + + ZeroMemory(sck_addr, sizeof(SOCKADDR_IN)); + sck_addr->sin_family = AF_INET; + sck_addr->sin_port = htons(remote_port); + CopyMemory(&sck_addr->sin_addr, hp->h_addr, hp->h_length); + + return 0; +} + +int http_file_open(char *url, FILE_STREAM *fs) +{ + SOCKET sck; + SOCKADDR_IN host; + char server[1024], file[1024], request[1024], *temp = NULL, *tmpfile = NULL; + int i, j, port = 80, bytes_recv, http_code; + + /* No winsock, no streaming */ + if(!winsock_init) + { + return -1; + } + + url += 7; // Skip over http:// + + /* Extract data from the URL */ + for(i=0; url[i] != '/' && url[i] != ':' && url[i] != 0; i++); + + ZeroMemory(server, 1024); + CopyMemory(server, url, i); + + if(url[i] == ':') + { + /* A certain port was specified */ + port = atol(url + (i + 1)); + } + + for(; url[i] != '/' && url[i] != 0; i++); + + ZeroMemory(file, 1024); + + CopyMemory(file, url + i, lstrlen(url)); + + /* END OF URL PARSING */ + + /* Create a TCP/IP socket */ + sck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(sck == INVALID_SOCKET) + { + CommonExit("Error creating TCP/IP new socket"); + return -1; + } + + /* Resolve the host address (turn www.blah.com into an IP) */ + if(resolve_host(server, &host, (unsigned short)port)) + { + CommonExit("Error resolving host address"); + CloseTCP(sck); + return -1; + } + + /* Connect to the server */ + if(connect(sck, (SOCKADDR *)&host, sizeof(SOCKADDR)) == SOCKET_ERROR) + { + CommonExit("Error connecting to remote server"); + CloseTCP(sck); + return -1; + } + + tmpfile = calloc(1, (strlen(file) * 3) + 1); + + /* Encode URL */ + for(i=0, j=0; i < (int)strlen(file); i++) + { + if((unsigned char)file[i] <= 31 || (unsigned char)file[i] >= 127) + { + /* encode ASCII-control characters */ + wsprintf(tmpfile + j, "%%%X", (unsigned char)file[i]); + j += 3; + continue; + } + else + { + switch(file[i]) + { + /* encode characters that could confuse some servers */ + case ' ': + case '"': + case '>': + case '<': + case '#': + case '%': + case '{': + case '}': + case '|': + case '\\': + case '^': + case '~': + case '[': + case ']': + case '`': + + wsprintf(tmpfile + j, "%%%X", (unsigned char)file[i]); + j += 3; + continue; + } + } + + tmpfile[j] = file[i]; + j++; + } + + wsprintf(request, "GET %s\r\n\r\n", tmpfile); + + free(tmpfile); + + /* Send the request */ + if(send(sck, request, lstrlen(request), 0) <= 0) + { + /* Error sending data */ + CloseTCP(sck); + return -1; + } + + ZeroMemory(request, 1024); + + /* Send the request */ + if((bytes_recv = recv(sck, request, 1024, 0)) <= 0) + { + /* Error sending data */ + CloseTCP(sck); + return -1; + } + + if(StringComp(request,"HTTP/1.", 7) != 0) + { + /* Invalid header */ + CloseTCP(sck); + return -1; + } + + http_code = atol(request + 9); + + if(http_code < 200 || http_code > 299) + { + /* HTTP error */ + CloseTCP(sck); + return -1; + } + + // Search for a length field + fs->http_file_length = 0; + + /* Limit search to only 20 loops */ + if((temp = strstr(request, "Content-Length: ")) != NULL) + { + /* Has a content-length field, copy into structure */ + fs->http_file_length = atol(temp + 16); + } + + /* Copy the handle data into the structure */ + fs->inetStream = sck; + + /* Copy any excess data beyond the header into the filestream buffers */ + temp = strstr(request, "\r\n\r\n"); + + if(temp) + { + temp += 4; + } + + if(temp - request < bytes_recv) + { + memcpy(fs->data, temp, (temp - request) - bytes_recv); + fs->buffer_length = (temp - request) - bytes_recv; + fs->buffer_offset = 0; + } + + return 0; +} diff --git a/faad2/src/common/faad/filestream.h b/faad2/src/common/faad/filestream.h new file mode 100644 index 0000000..58e40b9 --- /dev/null +++ b/faad2/src/common/faad/filestream.h @@ -0,0 +1,57 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: filestream.h,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifndef FILESTREAM_H +#define FILESTREAM_H + +typedef struct { + HANDLE stream; + unsigned short inetStream; + unsigned char *data; + int http; + int buffer_offset; + int buffer_length; + int file_offset; + int http_file_length; +} FILE_STREAM; + +extern long m_local_buffer_size; +extern long m_stream_buffer_size; + +FILE_STREAM *open_filestream(char *filename); +int read_byte_filestream(FILE_STREAM *fs); +int read_buffer_filestream(FILE_STREAM *fs, void *data, int length); +unsigned long filelength_filestream(FILE_STREAM *fs); +void close_filestream(FILE_STREAM *fs); +void seek_filestream(FILE_STREAM *fs, unsigned long offset, int mode); +unsigned long tell_filestream(FILE_STREAM *fs); +int http_file_open(char *url, FILE_STREAM *fs); + +int WinsockInit(); +void WinsockDeInit(); +void CloseTCP(int s); +#endif \ No newline at end of file diff --git a/faad2/src/common/faad/getopt.c b/faad2/src/common/faad/getopt.c new file mode 100644 index 0000000..6c21d73 --- /dev/null +++ b/faad2/src/common/faad/getopt.c @@ -0,0 +1,755 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef __STDC__ +# ifndef const +# define const +# endif +#endif + +/* This tells Alpha OSF/1 not to define a getopt prototype in . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || !__MacOSX__ + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#endif /* GNU C library. */ + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +/* #define GETOPT_COMPAT */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +#define BAD_OPTION '\0' +int optopt = BAD_OPTION; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#define my_strlen strlen +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#if __STDC__ || defined(PROTO) +extern char *getenv(const char *name); +extern int strcmp (const char *s1, const char *s2); +extern int strncmp(const char *s1, const char *s2, unsigned int n); + +static int my_strlen(const char *s); +static char *my_index (const char *str, int chr); +#else +extern char *getenv (); +#endif + +static int +my_strlen (str) + const char *str; +{ + int n = 0; + while (*str++) + n++; + return n; +} + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. + + To perform the swap, we first reverse the order of all elements. So + all options now come before all non options, but they are in the + wrong order. So we put back the options and non options in original + order by reversing them again. For example: + original input: a b c -x -y + reverse all: -y -x c b a + reverse options: -x -y c b a + reverse non options: -x -y a b c +*/ + +#if __STDC__ || defined(PROTO) +static void exchange (char **argv); +#endif + +static void +exchange (argv) + char **argv; +{ + char *temp, **first, **last; + + /* Reverse all the elements [first_nonopt, optind) */ + first = &argv[first_nonopt]; + last = &argv[optind-1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + /* Put back the options in order */ + first = &argv[first_nonopt]; + first_nonopt += (optind - last_nonopt); + last = &argv[first_nonopt - 1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + + /* Put back the non options in order */ + first = &argv[first_nonopt]; + last_nonopt = optind; + last = &argv[last_nonopt-1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return BAD_OPTION after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return BAD_OPTION. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound = 0; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == my_strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += my_strlen (nextchar); + optind++; + return BAD_OPTION; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += my_strlen (nextchar); + return BAD_OPTION; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += my_strlen (nextchar); + return optstring[0] == ':' ? ':' : BAD_OPTION; + } + } + nextchar += my_strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return BAD_OPTION; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { +#if 0 + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); +#endif + } + optopt = c; + return BAD_OPTION; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { +#if 0 + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = BAD_OPTION; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case BAD_OPTION: + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/faad2/src/common/faad/getopt.h b/faad2/src/common/faad/getopt.h new file mode 100644 index 0000000..ea03d28 --- /dev/null +++ b/faad2/src/common/faad/getopt.h @@ -0,0 +1,130 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MacOSX__ + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; +#endif + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +//#if __STDC__ || defined(PROTO) +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +//#else /* not __STDC__ */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +//extern int getopt_long (); +//extern int getopt_long_only (); + +//extern int _getopt_internal (); +//#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/faad2/src/common/faad/id3v2tag.c b/faad2/src/common/faad/id3v2tag.c new file mode 100644 index 0000000..ec4af9f --- /dev/null +++ b/faad2/src/common/faad/id3v2tag.c @@ -0,0 +1,1124 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: id3v2tag.c,v 1.4 2003/07/29 08:20:11 menno Exp $ +**/ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include + +#include + +HWND m_hwndList; + +LPSTR ID3Frames[] = +{ + "No known frame", + "Audio encryption", + "Attached picture", + "Comments", + "Commercial frame", + "Encryption method registration", + "Equalization", + "Event timing codes", + "General encapsulated object", + "Group identification registration", + "Involved people list", + "Linked information", + "Music CD identifier", + "MPEG location lookup table", + "Ownership frame", + "Private frame", + "Play counter", + "Popularimeter", + "Position synchronisation frame", + "Recommended buffer size", + "Relative volume adjustment", + "Reverb", + "Synchronized lyric", + "Synchronized tempo codes", + "Album title", + "BPM (beats per minute)", + "Composer", + "Genre", //"Content type", + "Copyright message", + "Date", + "Playlist delay", + "Encoded by", + "Lyricist", + "File type", + "Time", + "Content group description", + "Title", + "Subtitle", + "Initial key", + "Language(s)", + "Length", + "Media type", + "Original album title", + "Original filename", + "Original lyricist(s)", + "Original artist(s)", + "Original release year", + "File owner", + "Lead performer(s)", + "Band/orchestra/accompaniment", + "Conductor/performer refinement", + "Interpreted, remixed, or otherwise modified by", + "Part of a set", + "Publisher", + "Track number", + "Recording dates", + "Internet radio station name", + "Internet radio station owner", + "Size", + "ISRC (international standard recording code)", + "Software/Hardware and settings used for encoding", + "User defined text information", + "Year", + "Unique file identifier", + "Terms of use", + "Unsynchronized lyric", + "Commercial information", + "Copyright/Legal information", + "Official audio file webpage", + "Official artist webpage", + "Official audio source webpage", + "Official internet radio station homepage", + "Payment", + "Official publisher webpage", + "User defined URL link", + "Encrypted meta frame (id3v2.2.x)", + "Compressed meta frame (id3v2.2.1)" +}; + +ID3GENRES ID3Genres[]= +{ + 123, "Acapella", + 34, "Acid", + 74, "Acid Jazz", + 73, "Acid Punk", + 99, "Acoustic", + 20, "Alternative", + 40, "AlternRock", + 26, "Ambient", + 90, "Avantgarde", + 116, "Ballad", + 41, "Bass", + 85, "Bebob", + 96, "Big Band", + 89, "Bluegrass", + 0, "Blues", + 107, "Booty Bass", + 65, "Cabaret", + 88, "Celtic", + 104, "Chamber Music", + 102, "Chanson", + 97, "Chorus", + 61, "Christian Rap", + 1, "Classic Rock", + 32, "Classical", + 112, "Club", + 57, "Comedy", + 2, "Country", + 58, "Cult", + 3, "Dance", + 125, "Dance Hall", + 50, "Darkwave", + 254, "Data", + 22, "Death Metal", + 4, "Disco", + 55, "Dream", + 122, "Drum Solo", + 120, "Duet", + 98, "Easy Listening", + 52, "Electronic", + 48, "Ethnic", + 124, "Euro-House", + 25, "Euro-Techno", + 54, "Eurodance", + 84, "Fast Fusion", + 80, "Folk", + 81, "Folk-Rock", + 115, "Folklore", + 119, "Freestyle", + 5, "Funk", + 30, "Fusion", + 36, "Game", + 59, "Gangsta", + 38, "Gospel", + 49, "Gothic", + 91, "Gothic Rock", + 6, "Grunge", + 79, "Hard Rock", + 7, "Hip-Hop", + 35, "House", + 100, "Humour", + 19, "Industrial", + 33, "Instrumental", + 46, "Instrumental Pop", + 47, "Instrumental Rock", + 8, "Jazz", + 29, "Jazz+Funk", + 63, "Jungle", + 86, "Latin", + 71, "Lo-Fi", + 45, "Meditative", + 9, "Metal", + 77, "Musical", + 82, "National Folk", + 64, "Native American", + 10, "New Age", + 66, "New Wave", + 39, "Noise", + 255, "Not Set", + 11, "Oldies", + 103, "Opera", + 12, "Other", + 75, "Polka", + 13, "Pop", + 62, "Pop/Funk", + 53, "Pop-Folk", + 109, "Porn Groove", + 117, "Power Ballad", + 23, "Pranks", + 108, "Primus", + 92, "Progressive Rock", + 67, "Psychadelic", + 93, "Psychedelic Rock", + 43, "Punk", + 121, "Punk Rock", + 14, "R&B", + 15, "Rap", + 68, "Rave", + 16, "Reggae", + 76, "Retro", + 87, "Revival", + 118, "Rhythmic Soul", + 17, "Rock", + 78, "Rock & Roll", + 114, "Samba", + 110, "Satire", + 69, "Showtunes", + 21, "Ska", + 111, "Slow Jam", + 95, "Slow Rock", + 105, "Sonata", + 42, "Soul", + 37, "Sound Clip", + 24, "Soundtrack", + 56, "Southern Rock", + 44, "Space", + 101, "Speech", + 83, "Swing", + 94, "Symphonic Rock", + 106, "Symphony", + 113, "Tango", + 18, "Techno", + 51, "Techno-Industrial", + 60, "Top 40", + 70, "Trailer", + 31, "Trance", + 72, "Tribal", + 27, "Trip-Hop", + 28, "Vocal" +}; + +const int NUMFRAMES = sizeof(ID3Frames)/sizeof(ID3Frames[0]); +const int NUMGENRES = sizeof(ID3Genres)/sizeof(ID3Genres[0]); + + +LPSTR DupString(LPSTR lpsz) +{ + int cb = lstrlen(lpsz) + 1; + LPSTR lpszNew = LocalAlloc(LMEM_FIXED, cb); + if (lpszNew != NULL) + CopyMemory(lpszNew, lpsz, cb); + return lpszNew; +} + +LPSTR GetFrameDesc(ID3_FrameID id) +{ + return DupString(ID3Frames[id]); +} + +LPSTR GetGenre(LPSTR lpsz) +{ + int id = atoi(lpsz + 1); + int i; + + if ((*(lpsz + 1) > '0') && (*(lpsz + 1) < '9')) + { + for (i = 0; i < NUMGENRES; i++) + { + if (id == ID3Genres[i].id) + return DupString(ID3Genres[i].name); + } + } + return DupString(lpsz); +} + +void FillID3List(HWND hwndDlg, HWND hwndList, char *filename) +{ + ID3Tag *tag; + ID3Frame *frame; + ID3Field *field; + ID3_FrameID eFrameID; + char info[1024]; + int numFrames; + int i; + int iItem = 0; + + + if ((tag = ID3Tag_New()) != NULL) + { + ID3Tag_Link(tag, filename); + + numFrames = ID3Tag_NumFrames(tag); + + for (i = 0; i < numFrames; i++) + { + iItem++; + + frame = ID3Tag_GetFrameNum(tag, i); + eFrameID = ID3Frame_GetID(frame); + + switch (eFrameID) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_CONTENTTYPE: + case ID3FID_COPYRIGHT: case ID3FID_DATE: + case ID3FID_PLAYLISTDELAY: case ID3FID_ENCODEDBY: + case ID3FID_LYRICIST: case ID3FID_FILETYPE: + case ID3FID_TIME: case ID3FID_CONTENTGROUP: + case ID3FID_TITLE: case ID3FID_SUBTITLE: + case ID3FID_INITIALKEY: case ID3FID_LANGUAGE: + case ID3FID_SONGLEN: case ID3FID_MEDIATYPE: + case ID3FID_ORIGALBUM: case ID3FID_ORIGFILENAME: + case ID3FID_ORIGLYRICIST: case ID3FID_ORIGARTIST: + case ID3FID_ORIGYEAR: case ID3FID_FILEOWNER: + case ID3FID_LEADARTIST: case ID3FID_BAND: + case ID3FID_CONDUCTOR: case ID3FID_MIXARTIST: + case ID3FID_PARTINSET: case ID3FID_PUBLISHER: + case ID3FID_TRACKNUM: case ID3FID_RECORDINGDATES: + case ID3FID_NETRADIOSTATION: case ID3FID_NETRADIOOWNER: + case ID3FID_SIZE: case ID3FID_ISRC: + case ID3FID_ENCODERSETTINGS: case ID3FID_YEAR: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + pItem->aCols[0] = GetFrameDesc(eFrameID); + + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_GetASCII(field, info, 1024, 1); + if (eFrameID == ID3FID_CONTENTTYPE) + pItem->aCols[1] = GetGenre(info); + else + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + case ID3FID_USERTEXT: + case ID3FID_COMMENT: /* Can also contain an extra language field (but not used now) */ + case ID3FID_UNSYNCEDLYRICS: /* Can also contain an extra language field (but not used now) */ + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[0] = DupString(info); + + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + case ID3FID_WWWAUDIOFILE: case ID3FID_WWWARTIST: + case ID3FID_WWWAUDIOSOURCE: case ID3FID_WWWCOMMERCIALINFO: + case ID3FID_WWWCOPYRIGHT: case ID3FID_WWWPUBLISHER: + case ID3FID_WWWPAYMENT: case ID3FID_WWWRADIOPAGE: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + + pItem->aCols[0] = GetFrameDesc(eFrameID); + + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + case ID3FID_WWWUSER: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[0] = DupString(info); + + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + default: + break; + } + } + ID3Tag_Delete(tag); + } +} + +BOOL CALLBACK AddFrameProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + int i, cursel; + + switch (message) { + case WM_INITDIALOG: + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + + /* Note: FRAMEID is the index in the combo box + 1 */ + for (i = 1; i < NUMFRAMES; i++) + { + SendMessage(GetDlgItem(hwndDlg, IDC_FRAMETYPE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)ID3Frames[i]); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_FRAMETYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + cursel = SendMessage(GetDlgItem(hwndDlg, IDC_FRAMETYPE), CB_GETCURSEL, 0, 0); + + switch (cursel + 1) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_COPYRIGHT: + case ID3FID_DATE: case ID3FID_PLAYLISTDELAY: + case ID3FID_ENCODEDBY: case ID3FID_LYRICIST: + case ID3FID_FILETYPE: case ID3FID_TIME: + case ID3FID_CONTENTGROUP: case ID3FID_TITLE: + case ID3FID_SUBTITLE: case ID3FID_INITIALKEY: + case ID3FID_LANGUAGE: case ID3FID_SONGLEN: + case ID3FID_MEDIATYPE: case ID3FID_ORIGALBUM: + case ID3FID_ORIGFILENAME: case ID3FID_ORIGLYRICIST: + case ID3FID_ORIGARTIST: case ID3FID_ORIGYEAR: + case ID3FID_FILEOWNER: case ID3FID_LEADARTIST: + case ID3FID_BAND: case ID3FID_CONDUCTOR: + case ID3FID_MIXARTIST: case ID3FID_PARTINSET: + case ID3FID_PUBLISHER: case ID3FID_TRACKNUM: + case ID3FID_RECORDINGDATES: case ID3FID_NETRADIOSTATION: + case ID3FID_NETRADIOOWNER: case ID3FID_SIZE: + case ID3FID_ISRC: case ID3FID_ENCODERSETTINGS: + case ID3FID_YEAR: case ID3FID_WWWAUDIOFILE: + case ID3FID_WWWARTIST: case ID3FID_WWWAUDIOSOURCE: + case ID3FID_WWWCOMMERCIALINFO: case ID3FID_WWWCOPYRIGHT: + case ID3FID_WWWPUBLISHER: case ID3FID_WWWPAYMENT: + case ID3FID_WWWRADIOPAGE: case ID3FID_CONTENTTYPE: + { + SetDlgItemText(hwndDlg, IDC_COL0, ID3Frames[cursel+1]); + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); + break; + } + case ID3FID_USERTEXT: case ID3FID_COMMENT: + case ID3FID_UNSYNCEDLYRICS: case ID3FID_WWWUSER: + { + SetDlgItemText(hwndDlg, IDC_COL0, ID3Frames[cursel+1]); + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); + break; + } + default: + MessageBox(hwndDlg, "Sorry, this frame type cannot be added (yet).", "Sorry", MB_OK); + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + break; + } + } + return TRUE; + case IDOK: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + char *col0 = LocalAlloc(LPTR, 1024); + char *col1 = LocalAlloc(LPTR, 1024); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = ListView_GetItemCount(m_hwndList) + 1; + lvi.iSubItem = 0; + + cursel = SendMessage(GetDlgItem(hwndDlg, IDC_FRAMETYPE), CB_GETCURSEL, 0, 0); + pItem->frameId = cursel + 1; + GetDlgItemText(hwndDlg, IDC_COL0, col0, 1024); + GetDlgItemText(hwndDlg, IDC_COL1, col1, 1024); + pItem->aCols[0] = col0; + pItem->aCols[1] = col1; + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(m_hwndList, &lvi); + ListView_Update(m_hwndList, lvi.iItem); + } + case IDCANCEL: + EndDialog(hwndDlg, wParam); + return TRUE; + } + } + return FALSE; +} + +BOOL List_AddFrame(HWND hwndApp, HWND hwndList) +{ + int result; + + m_hwndList = hwndList; + + result = DialogBox(hInstance_for_id3editor, MAKEINTRESOURCE(IDD_ADDFRAME), + hwndApp, AddFrameProc); + + if (LOWORD(result) == IDOK) + return TRUE; + return FALSE; +} + + +void InsertTextFrame(HWND dlg, HWND list, int control, int item, int frame_id) +{ + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = item; + lvi.iSubItem = 0; + + pItem->frameId = frame_id; + pItem->aCols[0] = GetFrameDesc(frame_id); + + pItem->aCols[1] = LocalAlloc(LPTR, 1024); + GetDlgItemText(dlg, control, pItem->aCols[1], 1024); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(list, &lvi); +} + +void AddFrameFromRAWData(HWND hwndList, int frameId, LPSTR data1, LPSTR data2) +{ + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + int nextItem; + + nextItem = ListView_GetItemCount(hwndList); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = nextItem; + lvi.iSubItem = 0; + + pItem->frameId = frameId; + + pItem->aCols[0] = LocalAlloc(LPTR, 1024); + pItem->aCols[1] = LocalAlloc(LPTR, 1024); + + lstrcpy(pItem->aCols[0], data1); + lstrcpy(pItem->aCols[1], data2); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); +} + +HWND m_hwndDlg; +int changed; + +BOOL CALLBACK AddStandardProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + int added = 0; + + switch (message) { + case WM_INITDIALOG: + changed = 0; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TRACK)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_TRACK, ListView_GetItemCount(m_hwndList)+1, ID3FID_TRACKNUM); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TITLE)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_TITLE, ListView_GetItemCount(m_hwndList)+1, ID3FID_TITLE); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ARTIST)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ARTIST, ListView_GetItemCount(m_hwndList)+1, ID3FID_LEADARTIST); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ALBUM)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ALBUM, ListView_GetItemCount(m_hwndList)+1, ID3FID_ALBUM); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_YEAR)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_YEAR, ListView_GetItemCount(m_hwndList)+1, ID3FID_YEAR); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GENRE)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_GENRE, ListView_GetItemCount(m_hwndList)+1, ID3FID_CONTENTTYPE); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_COMMENT)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_COMMENT, ListView_GetItemCount(m_hwndList)+1, ID3FID_COMMENT); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_COMPOSER)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_COMPOSER, ListView_GetItemCount(m_hwndList)+1, ID3FID_COMPOSER); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ORIGARTIST)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ORIGARTIST, ListView_GetItemCount(m_hwndList)+1, ID3FID_ORIGARTIST); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_COPYRIGHT)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_COPYRIGHT, ListView_GetItemCount(m_hwndList)+1, ID3FID_COPYRIGHT); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_URL)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_URL, ListView_GetItemCount(m_hwndList)+1, ID3FID_WWWARTIST); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ENCBY)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ENCBY, ListView_GetItemCount(m_hwndList)+1, ID3FID_ENCODEDBY); + added++; + } + + if (added > 0) + changed = 1; + } + case IDCANCEL: + EndDialog(hwndDlg, changed); + return TRUE; + } + } + return FALSE; +} + + +BOOL List_AddStandardFrames(HWND hwndApp, HWND hwndList) +{ + int result; + + m_hwndList = hwndList; + m_hwndDlg = hwndApp; + + result = DialogBox(hInstance_for_id3editor, MAKEINTRESOURCE(IDD_ADDSTANDARD), + hwndApp, AddStandardProc); + + return result?TRUE:FALSE; +} + + +/* List_OnGetDispInfo - processes the LVN_GETDISPINFO */ +/* notification message. */ +/* pnmv - value of lParam (points to an LV_DISPINFO structure) */ +void List_OnGetDispInfo(LV_DISPINFO *pnmv) +{ + /* Provide the item or subitem's text, if requested. */ + if (pnmv->item.mask & LVIF_TEXT) { + ID3ITEM *pItem = (ID3ITEM *) (pnmv->item.lParam); + lstrcpy(pnmv->item.pszText, + pItem->aCols[pnmv->item.iSubItem]); + } +} + +ID3ITEM *pItem; +int editItemIndex; + +BOOL CALLBACK EditTextFrameProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + LV_ITEM lvi; + + switch (message) { + case WM_INITDIALOG: + SetDlgItemText(hwndDlg, IDC_TEXTFRAMENAME, pItem->aCols[0]); + SetDlgItemText(hwndDlg, IDC_EDITTEXTFRAME, pItem->aCols[1]); + + switch (pItem->frameId) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_COPYRIGHT: + case ID3FID_DATE: case ID3FID_PLAYLISTDELAY: + case ID3FID_ENCODEDBY: case ID3FID_LYRICIST: + case ID3FID_FILETYPE: case ID3FID_TIME: + case ID3FID_CONTENTGROUP: case ID3FID_TITLE: + case ID3FID_SUBTITLE: case ID3FID_INITIALKEY: + case ID3FID_LANGUAGE: case ID3FID_SONGLEN: + case ID3FID_MEDIATYPE: case ID3FID_ORIGALBUM: + case ID3FID_ORIGFILENAME: case ID3FID_ORIGLYRICIST: + case ID3FID_ORIGARTIST: case ID3FID_ORIGYEAR: + case ID3FID_FILEOWNER: case ID3FID_LEADARTIST: + case ID3FID_BAND: case ID3FID_CONDUCTOR: + case ID3FID_MIXARTIST: case ID3FID_PARTINSET: + case ID3FID_PUBLISHER: case ID3FID_TRACKNUM: + case ID3FID_RECORDINGDATES: case ID3FID_NETRADIOSTATION: + case ID3FID_NETRADIOOWNER: case ID3FID_SIZE: + case ID3FID_ISRC: case ID3FID_ENCODERSETTINGS: + case ID3FID_YEAR: case ID3FID_WWWAUDIOFILE: + case ID3FID_WWWARTIST: case ID3FID_WWWAUDIOSOURCE: + case ID3FID_WWWCOMMERCIALINFO: case ID3FID_WWWCOPYRIGHT: + case ID3FID_WWWPUBLISHER: case ID3FID_WWWPAYMENT: + case ID3FID_WWWRADIOPAGE: case ID3FID_CONTENTTYPE: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTFRAMENAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTEXTFRAME), TRUE); + break; + } + case ID3FID_USERTEXT: case ID3FID_COMMENT: + case ID3FID_UNSYNCEDLYRICS: case ID3FID_WWWUSER: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTFRAMENAME), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTEXTFRAME), TRUE); + break; + } + default: + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTFRAMENAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTEXTFRAME), FALSE); + break; + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + GetDlgItemText(hwndDlg, IDC_TEXTFRAMENAME, pItem->aCols[0], 1024); + GetDlgItemText(hwndDlg, IDC_EDITTEXTFRAME, pItem->aCols[1], 1024); + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = editItemIndex; + lvi.iSubItem = 0; + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_SetItem(m_hwndList, &lvi); + ListView_Update(m_hwndList, editItemIndex); + } /* Fall through */ + case IDCANCEL: + EndDialog(hwndDlg, wParam); + return TRUE; + } + } + return FALSE; +} + + +/* Double clicking means editing a frame */ +BOOL List_EditData(HWND hwndApp, HWND hwndList) +{ + LV_ITEM lvi; + BOOL result; + + /* First get the selected item */ + int index = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); + + m_hwndList = hwndList; + + if (index != -1) + { + lvi.mask = LVIF_PARAM; + lvi.iItem = index; + lvi.iSubItem = 0; + + if (ListView_GetItem(hwndList, &lvi) == TRUE) + { + pItem = (ID3ITEM*)lvi.lParam; + editItemIndex = lvi.iItem; + + result = DialogBox(hInstance_for_id3editor, MAKEINTRESOURCE(IDD_EDITTEXTFRAME), + hwndApp, EditTextFrameProc); + if (LOWORD(result) == IDOK) + return TRUE; + } + } + return FALSE; +} + + +/* Delete the selected frame */ +BOOL List_DeleteSelected(HWND hwndApp, HWND hwndList) +{ + int items; + + /* First get the selected item */ + int index = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); + + if (index != -1) + ListView_DeleteItem(hwndList, index); + + items = ListView_GetItemCount(hwndList); + if (index != -1) return TRUE; + else return FALSE; +} + + +/* Save the ID3 to the file */ +void List_SaveID3(HWND hwndApp, HWND hwndList, char *filename) +{ + LV_ITEM lvi; + ID3ITEM *pItem1; + int i, items; + ID3Tag *tag; + ID3Frame *frame; + ID3Field *field; + + /* Strip the tag first, before completely rewriting it */ + if ((tag = ID3Tag_New()) != NULL) + { + ID3Tag_Link(tag, filename); + ID3Tag_Strip(tag, ID3TT_ALL); + ID3Tag_Clear(tag); + + if (SendMessage(GetDlgItem(hwndApp, IDC_ID3V2TAG), BM_GETCHECK, 0, 0) == BST_UNCHECKED) + { + /* No frames saved */ + ID3Tag_Delete(tag); + EnableWindow(GetDlgItem(hwndApp, IDC_ID3V2TAG), FALSE); + ListView_DeleteAllItems(hwndList); + return; + } + + /* First get the number of items */ + items = ListView_GetItemCount(hwndList); + + if (items > 0) + { + for (i = 0; i < items; i++) + { + lvi.mask = LVIF_PARAM; + lvi.iItem = i; + lvi.iSubItem = 0; + + if (ListView_GetItem(hwndList, &lvi) == TRUE) + { + pItem1 = (ID3ITEM*)lvi.lParam; + + frame = ID3Frame_NewID(pItem1->frameId); + + switch (pItem1->frameId) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_CONTENTTYPE: + case ID3FID_COPYRIGHT: case ID3FID_DATE: + case ID3FID_PLAYLISTDELAY: case ID3FID_ENCODEDBY: + case ID3FID_LYRICIST: case ID3FID_FILETYPE: + case ID3FID_TIME: case ID3FID_CONTENTGROUP: + case ID3FID_TITLE: case ID3FID_SUBTITLE: + case ID3FID_INITIALKEY: case ID3FID_LANGUAGE: + case ID3FID_SONGLEN: case ID3FID_MEDIATYPE: + case ID3FID_ORIGALBUM: case ID3FID_ORIGFILENAME: + case ID3FID_ORIGLYRICIST: case ID3FID_ORIGARTIST: + case ID3FID_ORIGYEAR: case ID3FID_FILEOWNER: + case ID3FID_LEADARTIST: case ID3FID_BAND: + case ID3FID_CONDUCTOR: case ID3FID_MIXARTIST: + case ID3FID_PARTINSET: case ID3FID_PUBLISHER: + case ID3FID_TRACKNUM: case ID3FID_RECORDINGDATES: + case ID3FID_NETRADIOSTATION: case ID3FID_NETRADIOOWNER: + case ID3FID_SIZE: case ID3FID_ISRC: + case ID3FID_ENCODERSETTINGS: case ID3FID_YEAR: + { + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + case ID3FID_USERTEXT: + case ID3FID_COMMENT: /* Can also contain an extra language field (but not used now) */ + case ID3FID_UNSYNCEDLYRICS: /* Can also contain an extra language field (but not used now) */ + { + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_SetASCII(field, pItem1->aCols[0]); + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + case ID3FID_WWWAUDIOFILE: case ID3FID_WWWARTIST: + case ID3FID_WWWAUDIOSOURCE: case ID3FID_WWWCOMMERCIALINFO: + case ID3FID_WWWCOPYRIGHT: case ID3FID_WWWPUBLISHER: + case ID3FID_WWWPAYMENT: case ID3FID_WWWRADIOPAGE: + { + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + case ID3FID_WWWUSER: + { + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_SetASCII(field, pItem1->aCols[0]); + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + default: + break; + } + } + } + ID3Tag_UpdateByTagType(tag, ID3TT_ID3V2); + } + + ID3Tag_Delete(tag); + } +} + +/* Get the title from the file */ +void GetID3FileTitle(char *filename, char *title, char *format) +{ + ID3Tag *tag; + ID3Frame *frame; + ID3Field *field; + char buffer[255]; + int some_info = 0; + char *in = format; + char *out = title; + char *bound = out + (MAX_PATH - 10 - 1); + + + if ((tag = ID3Tag_New()) != NULL) + { + ID3Tag_Link(tag, filename); + + while (*in && out < bound) + { + switch (*in) { + case '%': + ++in; + break; + + default: + *out++ = *in++; + continue; + } + + /* handle % escape sequence */ + switch (*in++) { + case '0': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_TRACKNUM)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '1': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_LEADARTIST)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '2': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_TITLE)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '3': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_ALBUM)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '4': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_YEAR)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '5': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_COMMENT)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '6': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_CONTENTTYPE)) != NULL) { + int size; char *tmp; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + tmp = GetGenre(buffer); + lstrcpy(out, tmp); out += size; + some_info = 1; + } + break; + case '7': + { + char *p=filename+lstrlen(filename); + int len = 0; + while (*p != '\\' && p >= filename) { p--; len++; } + lstrcpy(out, ++p); out += len; + some_info = 1; + break; + } + } + } + + *out = '\0'; + ID3Tag_Delete(tag); + } + + if (!some_info) + { + char *p=filename+lstrlen(filename); + while (*p != '\\' && p >= filename) p--; + lstrcpy(title,++p); + } +} + diff --git a/faad2/src/common/faad/id3v2tag.h b/faad2/src/common/faad/id3v2tag.h new file mode 100644 index 0000000..041f524 --- /dev/null +++ b/faad2/src/common/faad/id3v2tag.h @@ -0,0 +1,54 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: id3v2tag.h,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifndef __ID3V2TAG_H__ +#define __ID3V2TAG_H__ + +void GetID3FileTitle(char *filename, char *title, char *format); +void FillID3List(HWND hwndDlg, HWND hwndList, char *filename); +void List_OnGetDispInfo(LV_DISPINFO *pnmv); +BOOL List_EditData(HWND hwndApp, HWND hwndList); +void List_SaveID3(HWND hwndApp, HWND hwndList, char *filename); +BOOL List_DeleteSelected(HWND hwndApp, HWND hwndList); +BOOL List_AddFrame(HWND hwndApp, HWND hwndList); +BOOL List_AddStandardFrames(HWND hwndApp, HWND hwndList); +void AddFrameFromRAWData(HWND hwndList, int frameId, LPSTR data1, LPSTR data2); + +HINSTANCE hInstance_for_id3editor; + +typedef struct ID3GENRES_TAG +{ + BYTE id; + char name[30]; +} ID3GENRES; + +typedef struct id3item_tag { + int frameId; + LPSTR aCols[2]; +} ID3ITEM; + +#endif \ No newline at end of file -- cgit v1.2.3