471 lines
9.9 KiB
C
471 lines
9.9 KiB
C
/*
|
|
** 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$
|
|
**/
|
|
|
|
/* Not very portable yet */
|
|
|
|
#include <winsock2.h> // Note: Must be *before* windows.h
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#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;
|
|
}
|