⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http_win32.c

📁 betaplayer的源码 tcpmp的老版本
💻 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 + -