📄 http_win32.c
字号:
/*****************************************************************************
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: http_win32.c 201 2005-01-15 08:42:20Z picard $
*
* BetaPlayer Core
* Copyright (c) 2004 Gabor Kovacs
*
****************************************************************************/
#include "../stdafx.h"
#if defined(_WIN32)
#ifndef STRICT
#define STRICT
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define SEEK_READ 65536
typedef HANDLE HINTERNET;
#define HTTP_QUERY_CONTENT_TYPE 1
#define HTTP_QUERY_CONTENT_LENGTH 5
#define HTTP_QUERY_STATUS_TEXT 20
#define HTTP_QUERY_RAW_HEADERS 21
#define HTTP_QUERY_RAW_HEADERS_CRLF 22
#define HTTP_QUERY_ACCEPT_RANGES 42
#define HTTP_QUERY_CUSTOM 65535
#define INTERNET_OPEN_TYPE_DIRECT 1
#define INTERNET_FLAG_NO_CACHE_WRITE 0x04000000
#define INTERNET_OPTION_CONNECT_TIMEOUT 2
typedef struct http
{
stream VMT;
pin Comments;
tchar_t URL[MAXPATH];
HINTERNET Internet;
HINTERNET Handle;
int Length;
int Pos;
bool_t Silent;
HMODULE DLL;
tchar_t ContentType[MAXPATH];
bool_t Ranges;
uint32_t MetaInt;
uint32_t MetaLeft;
char* EnumBuffer;
char* EnumPos;
const tchar_t* Exts;
bool_t ExtFilter;
BOOL (WINAPI *InternetReadFile)(HINTERNET hFile,LPVOID lpBuffer,DWORD dwNumberOfBytesToRead,LPDWORD lpdwNumberOfBytesRead);
HINTERNET (WINAPI *InternetOpen)(LPCTSTR lpszAgent, DWORD dwAccessType, LPCTSTR lpszProxy , LPCTSTR lpszProxyBypass , DWORD dwFlags);
HINTERNET (WINAPI *InternetOpenUrl)( HINTERNET hInternetSession, LPCTSTR lpszUrl, LPCTSTR lpszHeaders , DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext);
BOOL (WINAPI *InternetCloseHandle)(HINTERNET hInternet);
BOOL (WINAPI *HttpQueryInfo)(HINTERNET hRequest,DWORD dwInfoLevel, LPVOID lpBuffer , LPDWORD lpdwBufferLength, LPDWORD lpdwIndex );
BOOL (WINAPI *InternetSetOption)(HINTERNET hInternet,DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength);
} http;
static int EnumType( http* p, int No, datadef* Param )
{
return NodeEnumType(&No,Param,NodeParams,StreamParams,NULL);
}
static int Get( http* p, int No, void* Data, int Size )
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case NODE_ID: GETVALUE(HTTP_ID,int); break;
case STREAM_URL: GETSTRING(p->URL); break;
case STREAM_SILENT: GETVALUE(p->Silent,bool_t); break;
case STREAM_LENGTH: GETVALUECOND(p->Length,int,p->Length>=0); break;
case STREAM_CONTENTTYPE: GETSTRING(p->ContentType); break;
case STREAM_COMMENT: GETVALUE(p->Comments,pin); break;
}
return Result;
}
static int Open( http* p, const tchar_t* URL, bool_t ReOpen, bool_t ShoutCast )
{
if (p->Handle)
{
p->InternetCloseHandle(p->Handle);
p->Handle = 0;
}
if (p->Internet)
{
p->InternetCloseHandle(p->Internet);
p->Internet = 0;
}
p->ContentType[0] = 0;
p->Length = -1;
if (!ReOpen)
p->URL[0] = 0;
else
Sleep(200);
Free(p->EnumBuffer);
p->EnumBuffer = NULL;
p->EnumPos = NULL;
p->MetaInt = 0;
p->MetaLeft = 0;
if (URL && URL[0])
{
tchar_t s[128+1];
DWORD n;
p->Internet = p->InternetOpen(T("BetaPlayer"),INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
n = 15000;
p->InternetSetOption(p->Internet,INTERNET_OPTION_CONNECT_TIMEOUT,&n,sizeof(n));
s[0] = 0;
if (ReOpen && p->Ranges && p->Pos>0)
stprintf(s,T("Range: bytes=%d-\n"),p->Pos);
else
p->Pos = 0;
if (ShoutCast)
tcscat(s,T("Icy-MetaData:1\n"));
p->Handle = p->InternetOpenUrl(p->Internet, URL, s, (DWORD)-1, INTERNET_FLAG_NO_CACHE_WRITE, 1);
if (!p->Handle)
{
if (!ReOpen && !p->Silent)
NodeError(NULL,ERR_ID,ERR_CONNECT_FAILED,URL);
return ERR_FILE_NOT_FOUND;
}
TcsNCpy(p->URL,URL,MAXPATH);
n = sizeof(p->ContentType)/sizeof(tchar_t);
if (!p->HttpQueryInfo(p->Handle, HTTP_QUERY_CONTENT_TYPE , p->ContentType, &n, NULL))
p->ContentType[0] = 0;
TcsUpr(p->ContentType);
n = 128;
if (p->HttpQueryInfo(p->Handle, HTTP_QUERY_CONTENT_LENGTH , &s, &n, NULL) && n>0)
{
s[n] = 0; // just to make sure
n = StringToInt(s,0);
if (n>0)
p->Length = n;
}
if (!ReOpen)
{
p->Ranges = 0;
n = 128;
if (p->HttpQueryInfo(p->Handle, HTTP_QUERY_ACCEPT_RANGES, s, &n, NULL) && n>0)
{
s[n] = 0; // just to make sure
TcsUpr(s);
p->Ranges = tcsstr(s,T("BYTES")) != NULL;
}
}
}
else
p->Length = -1;
return ERR_NONE;
}
static int Set( http* p, int No, const void* Data, int Size )
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case STREAM_MIME:
if (Data && TcsICmp(Data,T("http"))==0)
Result = ERR_NONE;
break;
case STREAM_COMMENT: SETVALUE(p->Comments,pin,ERR_NONE); break;
case STREAM_SILENT: SETVALUE(p->Silent,bool_t,ERR_NONE); break;
case STREAM_URL:
Result = Open(p,(const tchar_t*)Data,0,1);
break;
}
return Result;
}
static char* GetLine(char* s,tchar_t* Out,int OutLen)
{
char Save;
char* End;
while (*s==' ') ++s;
for (End=s;*End && *End!=10 && *End!=13;++End);
Save = *End;
*End = 0;
StrToTcs(Out,s,OutLen);
*End = Save;
return End-1;
}
static void ProcessMeta(http* p,char* Meta,int Size)
{
tchar_t s[128];
char *i,*j;
for (i=Meta;i<Meta+Size;i++)
if (memcmp(i,"StreamTitle='",13)==0 && i[13]!='\'')
{
for (j=i+13;j<Meta+Size;++j)
if (*j=='\'')
break;
*j=0;
tcscpy(s,T("TITLE="));
StrToTcs(s+6,i+13,128-6);
if (p->Comments.Node)
p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
break;
}
}
static int Read(http* p,void* Data,int Size)
{
DWORD Readed;
DWORD Error;
if (p->InternetReadFile(p->Handle,Data,Size,&Readed))
{
p->Pos += Readed;
if (p->Pos == (int)Readed && Readed > 16)
{
char* ch;
int Code;
if (sscanf(Data,"ICY %d",&Code)==1)
{
if (Code!=200)
return -1;
tcscpy(p->ContentType,T("audio/mpeg")); // default
for (ch=(char*)Data;ch<(char*)Data+Readed-32;++ch)
{
tchar_t s[128];
if (memcmp(ch,"Content-Type:",13)==0 || memcmp(ch,"content-type:",13)==0)
ch = GetLine(ch+13,p->ContentType,MAXPATH);
else
if (memcmp(ch,"icy-genre:",10)==0)
{
tcscpy(s,T("GENRE="));
ch = GetLine(ch+10,s+6,128-6);
if (p->Comments.Node)
p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
}
else
if (memcmp(ch,"icy-name:",9)==0)
{
tcscpy(s,T("TITLE="));
GetLine(ch+9,s+6,128-6);
if (p->Comments.Node)
p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
}
else
if (memcmp(ch,"icy-metaint:",12)==0)
{
ch = GetLine(ch+12,s,128);
p->MetaLeft = p->MetaInt = StringToInt(s,0);
}
else
if (ch[0]==10 && ch[1]==10)
{
ch += 2;
break;
}
if (ch[0]==10 && ch[1]==13 && ch[2]==10)
{
ch += 3;
break;
}
}
if (ch<(char*)Data+Readed-32)
{
Readed -= ch - (char*)Data;
memmove(Data,ch,Readed);
}
}
}
if (p->MetaInt>0)
{
if (p->MetaLeft < Readed)
{
uint32_t Len;
uint8_t* b = (uint8_t*)Data;
while (p->MetaLeft < Readed)
{
// skip data bytes
b += p->MetaLeft;
Readed -= p->MetaLeft;
Len = *b * 16;
if (--Readed < Len)
{
// need more meta data
char Meta[16*255+1];
memcpy(Meta,b+1,Readed);
if (p->InternetReadFile(p->Handle,Meta+Readed,Len-Readed,&Readed))
{
p->Pos += Readed;
ProcessMeta(p,Meta,Len);
}
Readed = 0;
}
else
{
Readed -= Len;
if (Len)
ProcessMeta(p,(char*)(b+1),Len);
memmove(b,b+1+Len,Readed);
}
p->MetaLeft = p->MetaInt;
}
p->MetaLeft -= Readed;
b += Readed;
Len = b-(uint8_t*)Data;
Readed = Read(p,b,Size-Len);
if (Readed>=0)
Readed += Len;
}
else
p->MetaLeft -= Readed;
}
return Readed;
}
Error = GetLastError();
if (Error == ERROR_NOT_CONNECTED || Error == ERROR_INVALID_HANDLE)
Open(p,p->URL,1,1);
return -1;
}
static int Seek(http* p,int Pos,int SeekMode)
{
int Length;
switch (SeekMode)
{
case SEEK_CUR:
Pos += p->Pos;
break;
case SEEK_END:
if (p->Length<0)
return -1;
Pos += p->Length;
break;
}
Length = Pos - p->Pos;
if (Length<0 && Pos < SEEK_READ)
{
p->Pos = 0;
Open(p,p->URL,1,1);
Length = Pos - p->Pos;
}
if (Length == 0)
return p->Pos;
if (Length > 0 && Length < SEEK_READ)
{
void* Buffer = Alloc(Length);
if (Buffer)
{
Read(p,Buffer,Length);
Free(Buffer);
if (p->Pos == Pos)
return Pos;
}
}
if (p->Ranges)
{
p->Pos = Pos;
if (Open(p,p->URL,1,1) == ERR_NONE)
return p->Pos;
}
return -1;
}
static char* FindUpper(char* p,const char* s)
{
int i;
for (i=0;*p && s[i];++p)
if (toupper(p[0]) == s[i])
++i;
else
i=0;
return s[i] ? NULL:p;
}
#define hex(i) (((i)>='0' && (i)<='9')?(i)-'0':toupper(i)-'A'+10)
static int EnumDir(http* p,const tchar_t* URL,const tchar_t* Exts,bool_t ExtFilter,streamdir* Item)
{
if (URL)
{
int Pos;
int Result = Open(p,URL,0,0);
if (Result != ERR_NONE)
return Result;
if (!tcsstr(p->ContentType,T("TEXT/HTML")))
{
Open(p,NULL,0,0);
return ERR_NOT_DIRECTORY;
}
if (p->Length<=0)
p->Length = 256*1024-1;
if (p->Length >= 512*1024)
p->Length = 512*1024-1;
p->EnumBuffer = Alloc(p->Length+1);
if (!p->EnumBuffer)
return ERR_OUT_OF_MEMORY;
Pos = 0;
while (Pos<p->Length)
{
int Size = Read(p,p->EnumBuffer+Pos,p->Length-Pos);
if (Size <= 0)
break;
Pos += Size;
}
p->EnumBuffer[Pos] = 0;
p->EnumPos = p->EnumBuffer;
p->Exts = Exts;
p->ExtFilter = ExtFilter;
}
while (p->EnumPos && (p->EnumPos = FindUpper(p->EnumPos,"<A "))!=NULL)
{
char* End;
p->EnumPos = FindUpper(p->EnumPos,"HREF=");
if (!p->EnumPos)
break;
if (*p->EnumPos=='"' || *p->EnumPos=='\'')
{
++p->EnumPos;
End = strchr(p->EnumPos,p->EnumPos[-1]);
}
else
End = strchr(p->EnumPos,'>');
if (End)
{
int Len;
char* ch;
*End=0;
for (ch=p->EnumPos;*ch;++ch)
if (ch[0]=='%')
{
ch[0]=(char)((hex(ch[1])<<4)+hex(ch[2]));
memmove(ch+1,ch+3,strlen(ch+3)+1);
}
AsciiToTcs(Item->FileName,p->EnumPos,MAXPATH);
p->EnumPos = End+1;
Item->Date = -1;
Item->Size = -1;
Len = tcslen(Item->FileName);
if (Len && Item->FileName[Len-1]=='/')
{
Item->FileName[Len-1]=0;
return ERR_NONE;
}
if (CheckExts(Item->FileName,T("html:H;htm:H;asp:H;php:H")))
return ERR_NONE;
Item->Type = CheckExts(Item->FileName,p->Exts);
Item->Size = 0;
if (Item->Type || !p->ExtFilter)
return ERR_NONE;
}
}
Open(p,NULL,0,0);
return ERR_END_OF_FILE;
}
static void* Create( http* p )
{
http* i = (http*) CAlloc(sizeof(http),1);
if (i)
{
i->VMT = p->VMT;
i->InternetCloseHandle = p->InternetCloseHandle;
i->InternetReadFile = p->InternetReadFile;
i->InternetOpen = p->InternetOpen;
i->InternetOpenUrl = p->InternetOpenUrl;
i->HttpQueryInfo = p->HttpQueryInfo;
i->InternetSetOption = p->InternetSetOption;
}
return i;
}
static void Delete( http* p )
{
Open(p,NULL,0,0);
Free(p);
}
static http HTTP =
{
EnumType,
Get,
Set,
Create,
Delete,
Read,
Seek,
EnumDir,
NULL,
};
void HTTP_Init()
{
http* p = &HTTP;
p->DLL = LoadLibrary(T("wininet.dll"));
GetProc(&p->DLL,&p->InternetReadFile,T("InternetReadFile"),0);
GetProc(&p->DLL,&p->InternetCloseHandle,T("InternetCloseHandle"),0);
#ifdef UNICODE
GetProc(&p->DLL,&p->InternetOpen,T("InternetOpenW"),0);
GetProc(&p->DLL,&p->InternetOpenUrl,T("InternetOpenUrlW"),0);
GetProc(&p->DLL,&p->HttpQueryInfo,T("HttpQueryInfoW"),0);
GetProc(&p->DLL,&p->InternetSetOption,T("InternetSetOptionW"),0);
#else
GetProc(&p->DLL,&p->InternetOpen,T("InternetOpenA"),0);
GetProc(&p->DLL,&p->InternetOpenUrl,T("InternetOpenUrlA"),0);
GetProc(&p->DLL,&p->HttpQueryInfo,T("HttpQueryInfoA"),0);
GetProc(&p->DLL,&p->InternetSetOption,T("InternetSetOptionA"),0);
#endif
if (p->DLL)
NodeRegister((node*)p,PRI_MINIMUM);
}
void HTTP_Done()
{
http* p = &HTTP;
if (p->DLL)
{
NodeUnRegister((node*)p);
FreeLibrary(p->DLL);
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -