http_win32.c
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:22k
源码类别:
Windows CE
开发平台:
C/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 615 2006-01-26 16:57:51Z picard $
- *
- * The Core Pocket Media Player
- * Copyright (c) 2004-2005 Gabor Kovacs
- *
- ****************************************************************************/
- #include "../common/common.h"
- #include "http.h"
- //#define DUMPHTTP
- #define TIMEOUT_CONNECT 30
- #define TIMEOUT_READ 180
- #if defined(TARGET_WIN32) || defined(TARGET_WINCE)
- #ifndef STRICT
- #define STRICT
- #endif
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #if _MSC_VER > 1000
- #pragma warning(disable : 4201)
- #endif
- #include <wininet.h>
- #define MAXPRAGMA 512
- #define SEEK_READ 65536
- typedef HANDLE HINTERNET;
- #define HTTP_QUERY_CONTENT_TYPE 1
- #define HTTP_QUERY_CONTENT_LENGTH 5
- #define HTTP_QUERY_STATUS_CODE 19
- #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_PRAGMA 17
- #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 Stream;
- HINTERNET Internet;
- HINTERNET Handle;
- filepos_t Length;
- filepos_t Pos;
- bool_t Silent;
- bool_t Ranges;
- bool_t ReOpen;
- pin Comments;
- bool_t Pending;
- void* Complete;
- DWORD CompleteResult;
- DWORD Avail;
- uint32_t MetaInt;
- uint32_t MetaLeft;
- char* EnumBuffer;
- char* EnumPos;
- int EnumType;
- const tchar_t* Exts;
- bool_t ExtFilter;
- int AccessType;
- int CodePage;
- tchar_t URL[MAXPATH];
- tchar_t Base[MAXPATH];
- tchar_t ContentType[MAXPATH];
- tchar_t PragmaSend[MAXPRAGMA];
- tchar_t PragmaGet[MAXPRAGMA];
- BOOL (WINAPI* InternetGoOnline)(LPCTSTR, HWND, DWORD);
- } http;
- static int Get(http* p, int No, void* Data, int Size)
- {
- int Result = ERR_INVALID_PARAM;
- switch (No)
- {
- case STREAM_URL: GETSTRING(p->URL); break;
- case STREAM_BASE: GETSTRING(p->Base); 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;
- case STREAM_PRAGMA_SEND: GETSTRING(p->PragmaSend); break;
- case STREAM_PRAGMA_GET: GETSTRING(p->PragmaGet); break;
- }
- return Result;
- }
- static NOINLINE void GetLine(const tchar_t* In,tchar_t* Out,int OutLen)
- {
- while (IsSpace(*In)) ++In;
- for (;*In && *In!=10 && *In!=13 && OutLen>1;++In,++Out,--OutLen)
- *Out = *In;
- *Out=0;
- }
- static void ProcessHead(http* p,const tchar_t* Head)
- {
- tchar_t s[128];
- #ifdef DUMPHTTP
- FILE* Dump;
- Dump = fopen("\dumphttp.head","wb+");
- if (Dump)
- {
- fwrite(Head,1,tcslen(Head)*sizeof(tchar_t),Dump);
- fclose(Dump);
- }
- #endif
- while (*Head)
- {
- if (tcsncmp(Head,T("Content-Type:"),13)==0 || tcsncmp(Head,T("content-type:"),13)==0)
- {
- GetLine(Head+13,p->ContentType,MAXPATH);
- tcsupr(p->ContentType);
- }
- if (tcsncmp(Head,T("icy-genre:"),10)==0)
- {
- tcscpy_s(s,TSIZEOF(s),T("GENRE="));
- GetLine(Head+10,s+6,128-6);
- if (p->Comments.Node)
- p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
- }
- else
- if (tcsncmp(Head,T("icy-name:"),9)==0)
- {
- tcscpy_s(s,TSIZEOF(s),T("TITLE="));
- GetLine(Head+9,s+6,128-6);
- if (p->Comments.Node)
- p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
- }
- else
- if (tcsncmp(Head,T("icy-metaint:"),12)==0)
- {
- GetLine(Head+12,s,128);
- p->MetaLeft = p->MetaInt = StringToInt(s,0);
- }
- while (*Head && *Head != 10)
- ++Head;
- if (*Head == 10)
- ++Head;
- }
- }
- #ifdef DUMPHTTP
- static FILE* Dump = NULL;
- #endif
- static void CALLBACK InternetCallback(HINTERNET hInternet,
- DWORD dwContext,
- DWORD dwInternetStatus,
- LPVOID lpvStatusInformation,
- DWORD dwStatusInformationLength)
- {
- if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
- {
- INTERNET_ASYNC_RESULT *Result = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
- http *p = (http*)dwContext;
- p->CompleteResult = Result->dwResult;
- EventSet(p->Complete);
- }
- }
- static DWORD Pending(http* p,DWORD v,int Timeout)
- {
- if (v || GetLastError()!=ERROR_IO_PENDING)
- return v;
- p->Pending = 1;
- if (EventWait(p->Complete,GetTimeFreq()*Timeout))
- {
- int Result = p->CompleteResult;
- p->Pending = 0;
- return Result;
- }
- return 0;
- }
- static int Open(http* p, const tchar_t* URL, bool_t ReOpen, bool_t UsePragma)
- {
- int Again = 0;
- again:
- if (p->Handle)
- {
- InternetCloseHandle(p->Handle);
- p->Handle = 0;
- }
- if (p->Internet)
- {
- InternetCloseHandle(p->Internet);
- p->Internet = 0;
- }
- //DEBUG_MSG(-1,T("closed %d"),p->Pending);
- if (p->Pending)
- {
- EventWait(p->Complete,GetTimeFreq());
- p->Pending = 0;
- }
- p->ContentType[0] = 0;
- p->Length = -1;
- if (!ReOpen)
- {
- p->AccessType = INTERNET_OPEN_TYPE_DIRECT;
- p->URL[0] = 0;
- }
- else
- Sleep(200);
- free(p->EnumBuffer);
- p->EnumBuffer = NULL;
- p->EnumPos = NULL;
- p->EnumType =0;
- p->MetaInt = 0;
- p->MetaLeft = 0;
- p->ReOpen = 0;
- #ifdef DUMPHTTP
- if (Dump)
- {
- fclose(Dump);
- Dump = NULL;
- }
- #endif
- if (URL && URL[0])
- {
- tchar_t URL2[MAXPATH];
- tchar_t s[MAXPRAGMA+32];
- DWORD n;
- int Secure = 0;
- #ifdef DUMPHTTP
- Dump = fopen("\dumphttp.asf","wb+");
- #endif
- if (tcsnicmp(URL,T("https"),5)==0)
- Secure = INTERNET_FLAG_SECURE|INTERNET_FLAG_KEEP_CONNECTION;
- if (tcsnicmp(URL,T("mms://"),6)==0)
- {
- tcscpy_s(URL2,TSIZEOF(URL2),T("http://"));
- tcscat_s(URL2,TSIZEOF(URL2),URL+6);
- URL = URL2;
- }
- if (!ReOpen && p->InternetGoOnline)
- p->InternetGoOnline(URL,Context()->Wnd,0);
- retry:
- //WMP9 p->Internet = InternetOpen(T("NSPlayer/4.1.0.3928"),p->AccessType,NULL,NULL,INTERNET_FLAG_ASYNC);
- p->Internet = InternetOpen(T("NSPlayer/10.0.0.3802"),p->AccessType,NULL,NULL,INTERNET_FLAG_ASYNC);
- InternetSetStatusCallback(p->Internet,InternetCallback);
- s[0] = 0;
- if (ReOpen && p->Ranges && p->Pos>0)
- stprintf_s(s,TSIZEOF(s),T("Range: bytes=%d-n"),p->Pos);
- else
- p->Pos = 0;
- if (UsePragma)
- tcscat_s(s,TSIZEOF(s),p->PragmaSend);
- //DEBUG_MSG1(-1,T("open %d"),p->Pending);
- p->Handle = (HANDLE)Pending(p,(DWORD)InternetOpenUrl(p->Internet, URL, s, (DWORD)-1, INTERNET_FLAG_NO_CACHE_WRITE|Secure, (DWORD)p),TIMEOUT_CONNECT);
- if (!p->Handle)
- {
- if (!ReOpen && p->AccessType == INTERNET_OPEN_TYPE_DIRECT)
- {
- p->AccessType = INTERNET_OPEN_TYPE_PRECONFIG;
- InternetCloseHandle(p->Internet);
- goto retry;
- }
- if (!ReOpen && !p->Silent)
- {
- if (URL2==URL)
- ShowError(0,ERR_ID,ERR_MIME_NOT_FOUND,T("MMS"));
- else
- ShowError(0,ERR_ID,ERR_CONNECT_FAILED,URL);
- }
- return ERR_FILE_NOT_FOUND;
- }
- n = sizeof(p->URL);
- if (!InternetQueryOption(p->Handle, INTERNET_OPTION_URL, p->URL, &n))
- tcscpy_s(p->URL,TSIZEOF(p->URL),URL);
- SplitURL(p->URL,p->Base,TSIZEOF(p->Base),p->Base,TSIZEOF(p->Base),NULL,0,NULL,0);
- n = sizeof(p->ContentType);
- if (!HttpQueryInfo(p->Handle, HTTP_QUERY_CONTENT_TYPE , p->ContentType, &n, NULL))
- p->ContentType[0] = 0;
- tcsupr(p->ContentType);
- n = sizeof(s);
- if (HttpQueryInfo(p->Handle, HTTP_QUERY_STATUS_CODE , &s, &n, NULL) && n>0)
- {
- n = StringToInt(s,0);
- //DEBUG_MSG1(-1,T("HTTP status %d"),n);
- if (n>=400 && n<500) // client error
- {
- if (Again<5 && n!=404 && n!=410)
- {
- ++Again;
- if (!ReOpen)
- Sleep(200);
- goto again;
- }
- if (!ReOpen && !p->Silent)
- switch (n)
- {
- case 401:
- ShowError(0,ERR_ID,ERR_UNAUTHORIZED);
- break;
- case 404:
- case 410:
- ShowError(0,ERR_ID,ERR_FILE_NOT_FOUND,URL);
- break;
- default:
- ShowError(0,ERR_ID,ERR_CONNECT_FAILED);
- break;
- }
- return ERR_FILE_NOT_FOUND;
- }
- }
- n = sizeof(s);
- if (HttpQueryInfo(p->Handle, HTTP_QUERY_CONTENT_LENGTH , &s, &n, NULL) && n>0)
- {
- n = StringToInt(s,0);
- if (n>0)
- p->Length = n + p->Pos;
- }
- if (UsePragma)
- {
- DWORD No = 0;
- p->PragmaGet[0] = 0;
- for (;;)
- {
- n = (TSIZEOF(p->PragmaGet) - tcslen(p->PragmaGet) - 2)*sizeof(tchar_t);
- if (!HttpQueryInfo(p->Handle, HTTP_QUERY_PRAGMA, p->PragmaGet+tcslen(p->PragmaGet), &n, &No) || n<=0)
- break;
- tcscat_s(p->PragmaGet,TSIZEOF(p->PragmaGet),T(","));
- ++No;
- }
- {
- tchar_t* Head;
- n = 0;
- HttpQueryInfo(p->Handle, HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &n, NULL);
- if (n>0 && (Head = (tchar_t*)malloc(n))!=NULL)
- {
- if (HttpQueryInfo(p->Handle, HTTP_QUERY_RAW_HEADERS_CRLF, Head, &n, NULL))
- ProcessHead(p,Head);
- free(Head);
- }
- }
- }
- if (!ReOpen)
- {
- n = sizeof(s);
- if (HttpQueryInfo(p->Handle, HTTP_QUERY_ACCEPT_RANGES, s, &n, NULL) && n>0)
- {
- tcsupr(s);
- p->Ranges = tcsstr(s,T("BYTES")) != NULL;
- }
- else
- p->Ranges = p->Length>0; // assume range support for fixed length files
- }
- }
- 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_COMMENT: SETVALUE(p->Comments,pin,ERR_NONE); break;
- case STREAM_SILENT: SETVALUE(p->Silent,bool_t,ERR_NONE); break;
- case STREAM_PRAGMA_SEND: SETSTRING(p->PragmaSend); p->ReOpen = 1; break;
- case STREAM_PRAGMA_GET: SETSTRING(p->PragmaGet); break;
- case STREAM_URL:
- tcscpy_s(p->PragmaSend,TSIZEOF(p->PragmaSend),
- T("Icy-MetaData:1n")
- T("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=1,max-duration=2147492981n"));
- Result = Open(p,(const tchar_t*)Data,0,1);
- break;
- }
- return Result;
- }
- 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(s,TSIZEOF(s),T("TITLE="));
- StrToTcs(s+6,TSIZEOF(s)-6,i+13);
- if (p->Comments.Node)
- p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
- break;
- }
- }
- static int DataAvailable(http* p)
- {
- for (;;)
- {
- if (p->Pending)
- {
- if (EventWait(p->Complete,0))
- {
- //DEBUG_MSG(-1,T("avail %d"),p->Avail);
- p->Pending = 0;
- return p->Avail;
- }
- break;
- }
- p->Avail = 0;
- if (InternetQueryDataAvailable(p->Handle,&p->Avail,0,0))
- {
- if (p->Avail==0)
- return -1;
- return p->Avail;
- }
- if (GetLastError()!=ERROR_IO_PENDING)
- return -1;
- //DEBUG_MSG(-1,T("pending"));
- p->Pending = 1;
- }
- return 0;
- }
- static int Read(http* p,void* Data,int Size)
- {
- #ifdef DUMPHTTP
- static bool_t SkipDump = 0;
- #endif
- DWORD Readed;
- DWORD Error;
- if (p->Pending && EventWait(p->Complete,GetTimeFreq()*TIMEOUT_READ))
- p->Pending = 0;
- if (!p->Pending && Pending(p,InternetReadFile(p->Handle,Data,Size,&Readed),TIMEOUT_READ))
- {
- //DEBUG_MSG2(-1,T("readed %d %d"),Size,Readed);
- p->Pos += Readed;
- if (p->Pos == (int)Readed && Readed > 16)
- {
- int Code;
- tchar_t Head[16];
- GetAsciiToken(Head,16,Data,Readed);
- if (stscanf(Head,T("ICY %d"),&Code)==1)
- {
- unsigned int n;
- char* ch = (char*)Data;
- if (Code!=200)
- return -1;
- tcscpy_s(p->ContentType,TSIZEOF(p->ContentType),T("AUDIO/MPEG")); // default for ICY
- for (n=0;n<Readed-4;++n,++ch)
- if (ch[0]==10 && (ch[1]==10 || (ch[1]==13 && ch[2]==10)))
- {
- tchar_t* Head;
- n += 2;
- if (ch[1]==13)
- ++n;
- Head = malloc(sizeof(tchar_t)*(n+1));
- if (Head)
- {
- ch[0] = 0;
- StrToTcs(Head,n+1,(char*)Data);
- ProcessHead(p,Head);
- free(Head);
- }
- Readed -= n;
- memmove(Data,(char*)Data+n,Readed);
- break;
- }
- }
- }
- 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->Pending && EventWait(p->Complete,GetTimeFreq()*TIMEOUT_READ))
- p->Pending = 0;
- if (!p->Pending && Pending(p,InternetReadFile(p->Handle,Meta+Readed,Len-Readed,&Readed),TIMEOUT_READ))
- {
- p->Pos += Readed;
- ProcessMeta(p,Meta,Len);
- }
- else
- goto error;
- 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;
- #ifdef DUMPHTTP
- SkipDump = 1;
- #endif
- Readed = Read(p,b,Size-Len);
- #ifdef DUMPHTTP
- SkipDump = 0;
- #endif
- if (Readed>=0)
- Readed += Len;
- }
- else
- p->MetaLeft -= Readed;
- }
- #ifdef DUMPHTTP
- if (!SkipDump && Dump)
- fwrite(Data,1,Readed,Dump);
- #endif
- return Readed;
- }
- error:
- Error = GetLastError();
- if (p->Pending || Error == ERROR_NOT_CONNECTED || Error == ERROR_INVALID_HANDLE)
- Open(p,p->URL,1,1);
- return -1;
- }
- static int ReadBlock(http* p,block* Block,int Ofs,int Size)
- {
- return Read(p,(char*)(Block->Ptr+Ofs),Size);
- }
- static filepos_t Seek(http* p,filepos_t Pos,int SeekMode)
- {
- filepos_t 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 && !p->ReOpen)
- return p->Pos;
- if (Length > 0 && Length < SEEK_READ && !p->ReOpen)
- {
- int Len = (int)Length;
- void* Buffer = malloc(Len);
- if (Buffer)
- {
- Read(p,Buffer,Len);
- free(Buffer);
- if (p->Pos == Pos)
- return Pos;
- }
- }
- if (p->Ranges || !Pos)
- {
- 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;
- }
- typedef struct htmlchar
- {
- uint8_t ch;
- char sym[6+1];
- } htmlchar;
- static const htmlchar HTMLChar[] =
- {
- {34,"quot"},
- {38,"amp"},
- {60,"lt"},
- {62,"gt"},
- {160,"nbsp"},
- {161,"iexcl"},
- {162,"cent"},
- {163,"pound"},
- {164,"curren"},
- {165,"yen"},
- {166,"brvbar"},
- {167,"sect"},
- {168,"uml"},
- {169,"copy"},
- {170,"ordf"},
- {171,"laquo"},
- {172,"not"},
- {173,"shy"},
- {174,"reg"},
- {175,"hibar"},
- {176,"deg"},
- {177,"plusmn"},
- {185,"sup1"},
- {178,"sup2"},
- {179,"sup3"},
- {180,"acute"},
- {181,"micro"},
- {182,"para"},
- {183,"middot"},
- {184,"cedil"},
- {186,"ordm"},
- {187,"raquo"},
- {188,"frac14"},
- {189,"frac12"},
- {190,"frac34"},
- {191,"iquest"},
- {192,"Agrave"},
- {193,"Aacute"},
- {194,"Acirc"},
- {195,"Atilde"},
- {196,"Auml"},
- {197,"Aring"},
- {198,"AElig"},
- {199,"Ccedil"},
- {200,"Egrave"},
- {201,"Eacute"},
- {202,"Ecirc"},
- {203,"Euml"},
- {204,"Igrave"},
- {205,"Iacute"},
- {206,"Icirc"},
- {207,"Iuml"},
- {208,"ETH"},
- {209,"Ntilde"},
- {210,"Ograve"},
- {211,"Oacute"},
- {212,"Ocirc"},
- {213,"Otilde"},
- {214,"Ouml"},
- {215,"times"},
- {216,"Oslash"},
- {217,"Ugrave"},
- {218,"Uacute"},
- {219,"Ucirc"},
- {220,"Uuml"},
- {221,"Yacute"},
- {222,"THORN"},
- {223,"szlig"},
- {224,"agrave"},
- {225,"aacute"},
- {226,"acirc"},
- {227,"atilde"},
- {228,"auml"},
- {229,"aring"},
- {230,"aelig"},
- {231,"ccedil"},
- {232,"egrave"},
- {233,"eacute"},
- {234,"ecirc"},
- {235,"euml"},
- {236,"igrave"},
- {237,"iacute"},
- {238,"icirc"},
- {239,"iuml"},
- {240,"eth"},
- {241,"ntilde"},
- {242,"ograve"},
- {243,"oacute"},
- {244,"ocirc"},
- {245,"otilde"},
- {246,"ouml"},
- {247,"divide"},
- {248,"oslash"},
- {249,"ugrave"},
- {250,"uacute"},
- {251,"ucirc"},
- {252,"uuml"},
- {253,"yacute"},
- {254,"thorn"},
- {255,"yuml"},
- {0},
- };
- static void HTMLCharParse(char* p)
- {
- char* i;
- for (;*p;++p)
- if (*p=='&' && (i=strchr(p,';'))!=NULL)
- {
- const htmlchar* c;
- int n = i-p-1;
- for (c=HTMLChar;c->ch;++c)
- if (strncmp(c->sym,p+1,n)==0 && c->sym[n]==0)
- {
- *p = c->ch;
- memmove(p+1,i+1,strlen(i));
- break;
- }
- }
- }
- static void HTMLURLParse(char* p)
- {
- for (;*p;++p)
- if (p[0]=='%' && Hex(p[1])>=0 && Hex(p[2])>=0)
- {
- *p = (char)((Hex(p[1])<<4)+Hex(p[2]));
- memmove(p+1,p+3,strlen(p+3)+1);
- }
- }
- // detect Apache directory listing order links
- static bool_t ListingOrder(const tchar_t* Base,const tchar_t* FileName)
- {
- tchar_t Path[MAXPATH];
- int n = tcslen(Base);
- AbsPath(Path,TSIZEOF(Path),FileName,Base);
- return tcsncmp(Path,Base,n)==0 && tcsnicmp(Path+n,T("/?C="),4)==0;
- }
- static int EnumDir(http* p,const tchar_t* URL,const tchar_t* Exts,bool_t ExtFilter,streamdir* Item)
- {
- if (URL)
- {
- tchar_t Head[16];
- 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 = malloc((int)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;
- }
- GetAsciiToken(Head,16,p->EnumBuffer,p->Length);
- if (tcsnicmp(Head,T("<ASX"),4)==0 ||
- tcsnicmp(Head,T("[playlist]"),10)==0 ||
- tcsnicmp(Head,T("[Reference]"),11)==0)
- {
- Open(p,NULL,0,0);
- return ERR_NOT_DIRECTORY;
- }
- p->CodePage = GetCodePage(p->ContentType);
- p->EnumBuffer[Pos] = 0;
- p->EnumPos = p->EnumBuffer;
- p->EnumType =0;
- p->Exts = Exts;
- p->ExtFilter = ExtFilter;
- }
- while (p->EnumType<4)
- {
- const char* Tag1;
- const char* Tag2;
- switch (p->EnumType)
- {
- case 0:
- Tag1 = "<A ";
- Tag2 = "HREF=";
- break;
- case 1:
- Tag1 = "<AREA ";
- Tag2 = "HREF=";
- break;
- case 2:
- Tag1 = "<EMBED ";
- Tag2 = "HREF=";
- break;
- default:
- Tag1 = "<EMBED ";
- Tag2 = "SRC=";
- break;
- }
- while (p->EnumPos && (p->EnumPos = FindUpper(p->EnumPos,Tag1))!=NULL)
- {
- char* End;
- p->EnumPos = FindUpper(p->EnumPos,Tag2);
- 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 Endch = *End;
- *End=0;
- HTMLCharParse(p->EnumPos);
- StrToTcsEx(Item->FileName,TSIZEOF(Item->FileName),p->EnumPos,p->CodePage);
- HTMLURLParse(p->EnumPos);
- StrToTcsEx(Item->DisplayName,TSIZEOF(Item->DisplayName),p->EnumPos,p->CodePage);
- *End = Endch;
- p->EnumPos = End+1;
- Item->Date = -1;
- Item->Size = -1;
- Len = tcslen(Item->FileName);
- if (ListingOrder(p->Base,Item->FileName))
- continue;
- 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;
- }
- }
- p->EnumPos = p->EnumBuffer;
- ++p->EnumType;
- }
- Open(p,NULL,0,0);
- return ERR_END_OF_FILE;
- }
- static int Create(http* p)
- {
- HMODULE Module;
- p->Stream.Get = (nodeget)Get,
- p->Stream.Set = (nodeset)Set,
- p->Stream.Read = Read;
- p->Stream.ReadBlock = ReadBlock;
- p->Stream.Seek = Seek;
- p->Stream.EnumDir = EnumDir;
- p->Stream.DataAvailable = DataAvailable;
- p->Complete = EventCreate(0,0);
- Module = GetModuleHandle(T("wininet.dll"));
- #ifdef UNICODE
- GetProc(&Module,&p->InternetGoOnline,T("InternetGoOnlineW"),1);
- #else
- GetProc(&Module,&p->InternetGoOnline,T("InternetGoOnlineA"),1);
- #endif
- return ERR_NONE;
- }
- static void Delete(http* p)
- {
- Open(p,NULL,0,0);
- EventClose(p->Complete);
- }
- static const nodedef HTTP =
- {
- sizeof(http),
- HTTP_ID,
- STREAM_CLASS,
- PRI_MINIMUM,
- (nodecreate)Create,
- (nodedelete)Delete,
- };
- static const nodedef MMS =
- {
- 0, // parent size
- MMS_ID,
- HTTP_ID,
- PRI_MINIMUM,
- };
- void HTTP_Init()
- {
- NodeRegisterClass(&HTTP);
- NodeRegisterClass(&MMS);
- }
- void HTTP_Done()
- {
- NodeUnRegisterClass(MMS_ID);
- NodeUnRegisterClass(HTTP_ID);
- }
- #endif