http_win32.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:22k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*****************************************************************************
  2.  *
  3.  * This program is free software ; you can redistribute it and/or modify
  4.  * it under the terms of the GNU General Public License as published by
  5.  * the Free Software Foundation; either version 2 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  16.  *
  17.  * $Id: http_win32.c 615 2006-01-26 16:57:51Z picard $
  18.  *
  19.  * The Core Pocket Media Player
  20.  * Copyright (c) 2004-2005 Gabor Kovacs
  21.  *
  22.  ****************************************************************************/
  23. #include "../common/common.h"
  24. #include "http.h"
  25. //#define DUMPHTTP
  26. #define TIMEOUT_CONNECT 30
  27. #define TIMEOUT_READ 180
  28. #if defined(TARGET_WIN32) || defined(TARGET_WINCE)
  29. #ifndef STRICT
  30. #define STRICT
  31. #endif
  32. #define WIN32_LEAN_AND_MEAN
  33. #include <windows.h>
  34. #if _MSC_VER > 1000
  35. #pragma warning(disable : 4201)
  36. #endif
  37. #include <wininet.h>
  38. #define MAXPRAGMA 512
  39. #define SEEK_READ 65536
  40. typedef HANDLE HINTERNET;
  41. #define HTTP_QUERY_CONTENT_TYPE 1
  42. #define HTTP_QUERY_CONTENT_LENGTH 5
  43. #define HTTP_QUERY_STATUS_CODE 19
  44. #define HTTP_QUERY_STATUS_TEXT 20
  45. #define HTTP_QUERY_RAW_HEADERS          21
  46. #define HTTP_QUERY_RAW_HEADERS_CRLF     22
  47. #define HTTP_QUERY_ACCEPT_RANGES        42
  48. #define HTTP_QUERY_PRAGMA               17
  49. #define HTTP_QUERY_CUSTOM               65535
  50. #define INTERNET_OPEN_TYPE_DIRECT 1
  51. #define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000
  52. #define INTERNET_OPTION_CONNECT_TIMEOUT 2
  53. typedef struct http
  54. {
  55. stream Stream;
  56. HINTERNET Internet;
  57. HINTERNET Handle;
  58. filepos_t Length;
  59. filepos_t Pos;
  60. bool_t Silent;
  61. bool_t Ranges;
  62. bool_t ReOpen;
  63. pin Comments;
  64. bool_t Pending;
  65. void* Complete;
  66. DWORD CompleteResult;
  67. DWORD Avail;
  68. uint32_t MetaInt;
  69. uint32_t MetaLeft;
  70. char* EnumBuffer;
  71. char* EnumPos;
  72. int EnumType;
  73. const tchar_t* Exts;
  74. bool_t ExtFilter;
  75. int AccessType;
  76. int CodePage;
  77. tchar_t URL[MAXPATH];
  78. tchar_t Base[MAXPATH];
  79. tchar_t ContentType[MAXPATH];
  80. tchar_t PragmaSend[MAXPRAGMA];
  81. tchar_t PragmaGet[MAXPRAGMA];
  82. BOOL (WINAPI* InternetGoOnline)(LPCTSTR, HWND, DWORD);
  83. } http;
  84. static int Get(http* p, int No, void* Data, int Size)
  85. {
  86. int Result = ERR_INVALID_PARAM;
  87. switch (No)
  88. {
  89. case STREAM_URL: GETSTRING(p->URL); break;
  90. case STREAM_BASE: GETSTRING(p->Base); break;
  91. case STREAM_SILENT: GETVALUE(p->Silent,bool_t); break;
  92. case STREAM_LENGTH: GETVALUECOND(p->Length,int,p->Length>=0); break;
  93. case STREAM_CONTENTTYPE: GETSTRING(p->ContentType); break;
  94. case STREAM_COMMENT: GETVALUE(p->Comments,pin); break;
  95. case STREAM_PRAGMA_SEND: GETSTRING(p->PragmaSend); break;
  96. case STREAM_PRAGMA_GET: GETSTRING(p->PragmaGet); break;
  97. }
  98. return Result;
  99. }
  100. static NOINLINE void GetLine(const tchar_t* In,tchar_t* Out,int OutLen)
  101. {
  102. while (IsSpace(*In)) ++In;
  103. for (;*In && *In!=10 && *In!=13 && OutLen>1;++In,++Out,--OutLen)
  104. *Out = *In;
  105. *Out=0;
  106. }
  107. static void ProcessHead(http* p,const tchar_t* Head)
  108. {
  109. tchar_t s[128];
  110. #ifdef DUMPHTTP
  111. FILE* Dump;
  112. Dump = fopen("\dumphttp.head","wb+");
  113. if (Dump)
  114. {
  115. fwrite(Head,1,tcslen(Head)*sizeof(tchar_t),Dump);
  116. fclose(Dump);
  117. }
  118. #endif
  119. while (*Head)
  120. {
  121. if (tcsncmp(Head,T("Content-Type:"),13)==0 || tcsncmp(Head,T("content-type:"),13)==0)
  122. {
  123. GetLine(Head+13,p->ContentType,MAXPATH);
  124. tcsupr(p->ContentType);
  125. }
  126. if (tcsncmp(Head,T("icy-genre:"),10)==0)
  127. {
  128. tcscpy_s(s,TSIZEOF(s),T("GENRE="));
  129. GetLine(Head+10,s+6,128-6);
  130. if (p->Comments.Node)
  131. p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
  132. }
  133. else
  134. if (tcsncmp(Head,T("icy-name:"),9)==0)
  135. {
  136. tcscpy_s(s,TSIZEOF(s),T("TITLE="));
  137. GetLine(Head+9,s+6,128-6);
  138. if (p->Comments.Node)
  139. p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
  140. }
  141. else
  142. if (tcsncmp(Head,T("icy-metaint:"),12)==0)
  143. {
  144. GetLine(Head+12,s,128);
  145. p->MetaLeft = p->MetaInt = StringToInt(s,0);
  146. }
  147. while (*Head && *Head != 10)
  148. ++Head;
  149. if (*Head == 10) 
  150. ++Head;
  151. }
  152. }
  153. #ifdef DUMPHTTP
  154. static FILE* Dump = NULL;
  155. #endif
  156. static void CALLBACK InternetCallback(HINTERNET hInternet,
  157.                                DWORD dwContext,
  158.                                DWORD dwInternetStatus,
  159.                                LPVOID lpvStatusInformation,
  160.                                DWORD dwStatusInformationLength)
  161. {
  162. if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
  163. {
  164. INTERNET_ASYNC_RESULT *Result = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
  165. http *p = (http*)dwContext;
  166. p->CompleteResult = Result->dwResult;
  167. EventSet(p->Complete);
  168. }
  169. }
  170. static DWORD Pending(http* p,DWORD v,int Timeout)
  171. {
  172. if (v || GetLastError()!=ERROR_IO_PENDING)
  173. return v;
  174. p->Pending = 1;
  175. if (EventWait(p->Complete,GetTimeFreq()*Timeout))
  176. {
  177. int Result = p->CompleteResult;
  178. p->Pending = 0;
  179. return Result;
  180. }
  181. return 0;
  182. }
  183. static int Open(http* p, const tchar_t* URL, bool_t ReOpen, bool_t UsePragma)
  184. {
  185. int Again = 0;
  186. again:
  187. if (p->Handle)
  188. {
  189. InternetCloseHandle(p->Handle);
  190. p->Handle = 0;
  191. }
  192. if (p->Internet)
  193. {
  194. InternetCloseHandle(p->Internet);
  195. p->Internet = 0;
  196. }
  197. //DEBUG_MSG(-1,T("closed %d"),p->Pending);
  198. if (p->Pending)
  199. {
  200. EventWait(p->Complete,GetTimeFreq());
  201. p->Pending = 0;
  202. }
  203. p->ContentType[0] = 0;
  204. p->Length = -1;
  205. if (!ReOpen)
  206. {
  207. p->AccessType = INTERNET_OPEN_TYPE_DIRECT;
  208. p->URL[0] = 0;
  209. }
  210. else
  211. Sleep(200);
  212. free(p->EnumBuffer);
  213. p->EnumBuffer = NULL;
  214. p->EnumPos = NULL;
  215. p->EnumType =0;
  216. p->MetaInt = 0;
  217. p->MetaLeft = 0;
  218. p->ReOpen = 0;
  219. #ifdef DUMPHTTP
  220. if (Dump)
  221. {
  222. fclose(Dump);
  223. Dump = NULL;
  224. }
  225. #endif
  226. if (URL && URL[0])
  227. {
  228. tchar_t URL2[MAXPATH];
  229. tchar_t s[MAXPRAGMA+32];
  230. DWORD n;
  231. int Secure = 0;
  232. #ifdef DUMPHTTP
  233. Dump = fopen("\dumphttp.asf","wb+");
  234. #endif
  235. if (tcsnicmp(URL,T("https"),5)==0)
  236. Secure = INTERNET_FLAG_SECURE|INTERNET_FLAG_KEEP_CONNECTION;
  237. if (tcsnicmp(URL,T("mms://"),6)==0)
  238. {
  239. tcscpy_s(URL2,TSIZEOF(URL2),T("http://"));
  240. tcscat_s(URL2,TSIZEOF(URL2),URL+6);
  241. URL = URL2;
  242. }
  243. if (!ReOpen && p->InternetGoOnline)
  244. p->InternetGoOnline(URL,Context()->Wnd,0);
  245. retry:
  246. //WMP9 p->Internet = InternetOpen(T("NSPlayer/4.1.0.3928"),p->AccessType,NULL,NULL,INTERNET_FLAG_ASYNC); 
  247. p->Internet = InternetOpen(T("NSPlayer/10.0.0.3802"),p->AccessType,NULL,NULL,INTERNET_FLAG_ASYNC); 
  248. InternetSetStatusCallback(p->Internet,InternetCallback);
  249. s[0] = 0;
  250. if (ReOpen && p->Ranges && p->Pos>0)
  251. stprintf_s(s,TSIZEOF(s),T("Range: bytes=%d-n"),p->Pos);
  252. else
  253. p->Pos = 0;
  254. if (UsePragma)
  255. tcscat_s(s,TSIZEOF(s),p->PragmaSend);
  256. //DEBUG_MSG1(-1,T("open %d"),p->Pending);
  257. p->Handle = (HANDLE)Pending(p,(DWORD)InternetOpenUrl(p->Internet, URL, s, (DWORD)-1, INTERNET_FLAG_NO_CACHE_WRITE|Secure, (DWORD)p),TIMEOUT_CONNECT);
  258. if (!p->Handle)
  259. {
  260. if (!ReOpen && p->AccessType == INTERNET_OPEN_TYPE_DIRECT)
  261. {
  262. p->AccessType = INTERNET_OPEN_TYPE_PRECONFIG;
  263. InternetCloseHandle(p->Internet);
  264. goto retry;
  265. }
  266. if (!ReOpen && !p->Silent)
  267. {
  268. if (URL2==URL)
  269. ShowError(0,ERR_ID,ERR_MIME_NOT_FOUND,T("MMS"));
  270. else
  271. ShowError(0,ERR_ID,ERR_CONNECT_FAILED,URL);
  272. }
  273. return ERR_FILE_NOT_FOUND;
  274. }
  275. n = sizeof(p->URL);
  276. if (!InternetQueryOption(p->Handle, INTERNET_OPTION_URL, p->URL, &n))
  277. tcscpy_s(p->URL,TSIZEOF(p->URL),URL);
  278. SplitURL(p->URL,p->Base,TSIZEOF(p->Base),p->Base,TSIZEOF(p->Base),NULL,0,NULL,0);
  279. n = sizeof(p->ContentType);
  280. if (!HttpQueryInfo(p->Handle, HTTP_QUERY_CONTENT_TYPE , p->ContentType, &n, NULL))
  281. p->ContentType[0] = 0;
  282. tcsupr(p->ContentType);
  283. n = sizeof(s);
  284. if (HttpQueryInfo(p->Handle, HTTP_QUERY_STATUS_CODE , &s, &n, NULL) && n>0)
  285. {
  286. n = StringToInt(s,0);
  287. //DEBUG_MSG1(-1,T("HTTP status %d"),n);
  288. if (n>=400 && n<500) // client error
  289. {
  290. if (Again<5 && n!=404 && n!=410)
  291. {
  292. ++Again;
  293. if (!ReOpen)
  294. Sleep(200);
  295. goto again;
  296. }
  297. if (!ReOpen && !p->Silent)
  298. switch (n)
  299. {
  300. case 401:
  301. ShowError(0,ERR_ID,ERR_UNAUTHORIZED);
  302. break;
  303. case 404:
  304. case 410:
  305. ShowError(0,ERR_ID,ERR_FILE_NOT_FOUND,URL);
  306. break;
  307. default:
  308. ShowError(0,ERR_ID,ERR_CONNECT_FAILED);
  309. break;
  310. }
  311. return ERR_FILE_NOT_FOUND;
  312. }
  313. }
  314. n = sizeof(s);
  315. if (HttpQueryInfo(p->Handle, HTTP_QUERY_CONTENT_LENGTH , &s, &n, NULL) && n>0)
  316. {
  317. n = StringToInt(s,0);
  318. if (n>0)
  319. p->Length = n + p->Pos;
  320. }
  321. if (UsePragma)
  322. {
  323. DWORD No = 0;
  324. p->PragmaGet[0] = 0;
  325. for (;;)
  326. {
  327. n = (TSIZEOF(p->PragmaGet) - tcslen(p->PragmaGet) - 2)*sizeof(tchar_t);
  328. if (!HttpQueryInfo(p->Handle, HTTP_QUERY_PRAGMA, p->PragmaGet+tcslen(p->PragmaGet), &n, &No) || n<=0)
  329. break;
  330. tcscat_s(p->PragmaGet,TSIZEOF(p->PragmaGet),T(","));
  331. ++No;
  332. }
  333. {
  334. tchar_t* Head;
  335. n = 0;
  336. HttpQueryInfo(p->Handle, HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &n, NULL);
  337. if (n>0 && (Head = (tchar_t*)malloc(n))!=NULL)
  338. {
  339. if (HttpQueryInfo(p->Handle, HTTP_QUERY_RAW_HEADERS_CRLF, Head, &n, NULL))
  340. ProcessHead(p,Head);
  341. free(Head);
  342. }
  343. }
  344. }
  345. if (!ReOpen)
  346. {
  347. n = sizeof(s);
  348. if (HttpQueryInfo(p->Handle, HTTP_QUERY_ACCEPT_RANGES, s, &n, NULL) && n>0)
  349. {
  350. tcsupr(s);
  351. p->Ranges = tcsstr(s,T("BYTES")) != NULL;
  352. }
  353. else 
  354. p->Ranges = p->Length>0; // assume range support for fixed length files
  355. }
  356. }
  357. else
  358. p->Length = -1;
  359. return ERR_NONE;
  360. }
  361. static int Set(http* p, int No, const void* Data, int Size)
  362. {
  363. int Result = ERR_INVALID_PARAM;
  364. switch (No)
  365. {
  366. case STREAM_COMMENT: SETVALUE(p->Comments,pin,ERR_NONE); break;
  367. case STREAM_SILENT: SETVALUE(p->Silent,bool_t,ERR_NONE); break;
  368. case STREAM_PRAGMA_SEND: SETSTRING(p->PragmaSend); p->ReOpen = 1; break;
  369. case STREAM_PRAGMA_GET: SETSTRING(p->PragmaGet); break;
  370. case STREAM_URL:
  371. tcscpy_s(p->PragmaSend,TSIZEOF(p->PragmaSend),
  372. T("Icy-MetaData:1n")
  373. T("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=1,max-duration=2147492981n"));
  374. Result = Open(p,(const tchar_t*)Data,0,1);
  375. break;
  376. }
  377. return Result;
  378. }
  379. static void ProcessMeta(http* p,char* Meta,int Size)
  380. {
  381. tchar_t s[128];
  382. char *i,*j;
  383. for (i=Meta;i<Meta+Size;i++)
  384. if (memcmp(i,"StreamTitle='",13)==0 && i[13]!=''')
  385. {
  386. for (j=i+13;j<Meta+Size;++j)
  387. if (*j==''')
  388. break;
  389. *j=0;
  390. tcscpy_s(s,TSIZEOF(s),T("TITLE="));
  391. StrToTcs(s+6,TSIZEOF(s)-6,i+13);
  392. if (p->Comments.Node)
  393. p->Comments.Node->Set(p->Comments.Node,p->Comments.No,s,sizeof(s));
  394. break;
  395. }
  396. }
  397. static int DataAvailable(http* p)
  398. {
  399. for (;;)
  400. {
  401. if (p->Pending)
  402. {
  403. if (EventWait(p->Complete,0))
  404. {
  405. //DEBUG_MSG(-1,T("avail %d"),p->Avail);
  406. p->Pending = 0;
  407. return p->Avail;
  408. }
  409. break;
  410. }
  411. p->Avail = 0;
  412. if (InternetQueryDataAvailable(p->Handle,&p->Avail,0,0))
  413. {
  414. if (p->Avail==0)
  415. return -1;
  416. return p->Avail;
  417. }
  418. if (GetLastError()!=ERROR_IO_PENDING)
  419. return -1;
  420. //DEBUG_MSG(-1,T("pending"));
  421. p->Pending = 1;
  422. }
  423. return 0;
  424. }
  425. static int Read(http* p,void* Data,int Size)
  426. {
  427. #ifdef DUMPHTTP
  428. static bool_t SkipDump = 0;
  429. #endif
  430. DWORD Readed;
  431. DWORD Error;
  432. if (p->Pending && EventWait(p->Complete,GetTimeFreq()*TIMEOUT_READ))
  433. p->Pending = 0;
  434. if (!p->Pending && Pending(p,InternetReadFile(p->Handle,Data,Size,&Readed),TIMEOUT_READ))
  435. {
  436. //DEBUG_MSG2(-1,T("readed %d %d"),Size,Readed);
  437. p->Pos += Readed;
  438. if (p->Pos == (int)Readed && Readed > 16)
  439. {
  440. int Code;
  441. tchar_t Head[16];
  442. GetAsciiToken(Head,16,Data,Readed);
  443. if (stscanf(Head,T("ICY %d"),&Code)==1)
  444. {
  445. unsigned int n;
  446. char* ch = (char*)Data;
  447. if (Code!=200)
  448. return -1;
  449. tcscpy_s(p->ContentType,TSIZEOF(p->ContentType),T("AUDIO/MPEG")); // default for ICY
  450. for (n=0;n<Readed-4;++n,++ch)
  451. if (ch[0]==10 && (ch[1]==10 || (ch[1]==13 && ch[2]==10)))
  452. {
  453. tchar_t* Head;
  454. n += 2;
  455. if (ch[1]==13)
  456. ++n;
  457. Head = malloc(sizeof(tchar_t)*(n+1));
  458. if (Head)
  459. {
  460. ch[0] = 0;
  461. StrToTcs(Head,n+1,(char*)Data);
  462. ProcessHead(p,Head);
  463. free(Head);
  464. }
  465. Readed -= n;
  466. memmove(Data,(char*)Data+n,Readed);
  467. break;
  468. }
  469. }
  470. }
  471. if (p->MetaInt>0)
  472. {
  473. if (p->MetaLeft < Readed)
  474. {
  475. uint32_t Len;
  476. uint8_t* b = (uint8_t*)Data;
  477. while (p->MetaLeft < Readed)
  478. {
  479. // skip data bytes
  480. b += p->MetaLeft;
  481. Readed -= p->MetaLeft;
  482. Len = *b * 16;
  483. if (--Readed < Len)
  484. {
  485. // need more meta data 
  486. char Meta[16*255+1];
  487. memcpy(Meta,b+1,Readed);
  488. if (p->Pending && EventWait(p->Complete,GetTimeFreq()*TIMEOUT_READ))
  489. p->Pending = 0;
  490. if (!p->Pending && Pending(p,InternetReadFile(p->Handle,Meta+Readed,Len-Readed,&Readed),TIMEOUT_READ))
  491. {
  492. p->Pos += Readed;
  493. ProcessMeta(p,Meta,Len);
  494. }
  495. else
  496. goto error;
  497. Readed = 0;
  498. }
  499. else
  500. {
  501. Readed -= Len;
  502. if (Len)
  503. ProcessMeta(p,(char*)(b+1),Len);
  504. memmove(b,b+1+Len,Readed);
  505. }
  506. p->MetaLeft = p->MetaInt;
  507. }
  508. p->MetaLeft -= Readed;
  509. b += Readed;
  510. Len = b-(uint8_t*)Data;
  511. #ifdef DUMPHTTP
  512. SkipDump = 1;
  513. #endif
  514. Readed = Read(p,b,Size-Len);
  515. #ifdef DUMPHTTP
  516. SkipDump = 0;
  517. #endif
  518. if (Readed>=0)
  519. Readed += Len;
  520. }
  521. else
  522. p->MetaLeft -= Readed;
  523. }
  524. #ifdef DUMPHTTP
  525. if (!SkipDump && Dump)
  526. fwrite(Data,1,Readed,Dump);
  527. #endif
  528. return Readed;
  529. }
  530. error:
  531. Error = GetLastError();
  532. if (p->Pending || Error == ERROR_NOT_CONNECTED || Error == ERROR_INVALID_HANDLE)
  533. Open(p,p->URL,1,1);
  534. return -1;
  535. }
  536. static int ReadBlock(http* p,block* Block,int Ofs,int Size)
  537. {
  538. return Read(p,(char*)(Block->Ptr+Ofs),Size);
  539. }
  540. static filepos_t Seek(http* p,filepos_t Pos,int SeekMode)
  541. {
  542. filepos_t Length;
  543. switch (SeekMode)
  544. {
  545. case SEEK_CUR: 
  546. Pos += p->Pos; 
  547. break;
  548. case SEEK_END: 
  549. if (p->Length<0) 
  550. return -1;
  551. Pos += p->Length;
  552. break;
  553. }
  554. Length = Pos - p->Pos;
  555. if (Length<0 && Pos < SEEK_READ)
  556. {
  557. p->Pos = 0;
  558. Open(p,p->URL,1,1);
  559. Length = Pos - p->Pos;
  560. }
  561. if (Length == 0 && !p->ReOpen)
  562. return p->Pos;
  563. if (Length > 0 && Length < SEEK_READ && !p->ReOpen)
  564. {
  565. int Len = (int)Length;
  566. void* Buffer = malloc(Len);
  567. if (Buffer)
  568. {
  569. Read(p,Buffer,Len);
  570. free(Buffer);
  571. if (p->Pos == Pos)
  572. return Pos;
  573. }
  574. }
  575. if (p->Ranges || !Pos)
  576. {
  577. p->Pos = Pos;
  578. if (Open(p,p->URL,1,1) == ERR_NONE)
  579. return p->Pos;
  580. }
  581. return -1;
  582. }
  583. static char* FindUpper(char* p,const char* s)
  584. {
  585. int i;
  586. for (i=0;*p && s[i];++p)
  587. if (toupper(p[0]) == s[i])
  588. ++i;
  589. else
  590. i=0;
  591. return s[i] ? NULL:p;
  592. }
  593. typedef struct htmlchar
  594. {
  595. uint8_t ch;
  596. char sym[6+1];
  597. } htmlchar;
  598. static const htmlchar HTMLChar[] =
  599. {
  600. {34,"quot"},
  601. {38,"amp"},
  602. {60,"lt"},
  603. {62,"gt"},
  604. {160,"nbsp"},
  605. {161,"iexcl"},
  606. {162,"cent"},
  607. {163,"pound"},
  608. {164,"curren"},
  609. {165,"yen"},
  610. {166,"brvbar"},
  611. {167,"sect"},
  612. {168,"uml"},
  613. {169,"copy"},
  614. {170,"ordf"},
  615. {171,"laquo"},
  616. {172,"not"},
  617. {173,"shy"},
  618. {174,"reg"},
  619. {175,"hibar"},
  620. {176,"deg"},
  621. {177,"plusmn"},
  622. {185,"sup1"},
  623. {178,"sup2"},
  624. {179,"sup3"},
  625. {180,"acute"},
  626. {181,"micro"},
  627. {182,"para"},
  628. {183,"middot"},
  629. {184,"cedil"},
  630. {186,"ordm"},
  631. {187,"raquo"},
  632. {188,"frac14"},
  633. {189,"frac12"},
  634. {190,"frac34"},
  635. {191,"iquest"},
  636. {192,"Agrave"},
  637. {193,"Aacute"},
  638. {194,"Acirc"},
  639. {195,"Atilde"},
  640. {196,"Auml"},
  641. {197,"Aring"},
  642. {198,"AElig"},
  643. {199,"Ccedil"},
  644. {200,"Egrave"},
  645. {201,"Eacute"},
  646. {202,"Ecirc"},
  647. {203,"Euml"},
  648. {204,"Igrave"},
  649. {205,"Iacute"},
  650. {206,"Icirc"},
  651. {207,"Iuml"},
  652. {208,"ETH"},
  653. {209,"Ntilde"},
  654. {210,"Ograve"},
  655. {211,"Oacute"},
  656. {212,"Ocirc"},
  657. {213,"Otilde"},
  658. {214,"Ouml"},
  659. {215,"times"},
  660. {216,"Oslash"},
  661. {217,"Ugrave"},
  662. {218,"Uacute"},
  663. {219,"Ucirc"},
  664. {220,"Uuml"},
  665. {221,"Yacute"},
  666. {222,"THORN"},
  667. {223,"szlig"},
  668. {224,"agrave"},
  669. {225,"aacute"},
  670. {226,"acirc"},
  671. {227,"atilde"},
  672. {228,"auml"},
  673. {229,"aring"},
  674. {230,"aelig"},
  675. {231,"ccedil"},
  676. {232,"egrave"},
  677. {233,"eacute"},
  678. {234,"ecirc"},
  679. {235,"euml"},
  680. {236,"igrave"},
  681. {237,"iacute"},
  682. {238,"icirc"},
  683. {239,"iuml"},
  684. {240,"eth"},
  685. {241,"ntilde"},
  686. {242,"ograve"},
  687. {243,"oacute"},
  688. {244,"ocirc"},
  689. {245,"otilde"},
  690. {246,"ouml"},
  691. {247,"divide"},
  692. {248,"oslash"},
  693. {249,"ugrave"},
  694. {250,"uacute"},
  695. {251,"ucirc"},
  696. {252,"uuml"},
  697. {253,"yacute"},
  698. {254,"thorn"},
  699. {255,"yuml"},
  700. {0},
  701. };
  702. static void HTMLCharParse(char* p)
  703. {
  704. char* i;
  705. for (;*p;++p)
  706. if (*p=='&' && (i=strchr(p,';'))!=NULL)
  707. {
  708. const htmlchar* c;
  709. int n = i-p-1;
  710. for (c=HTMLChar;c->ch;++c)
  711. if (strncmp(c->sym,p+1,n)==0 && c->sym[n]==0)
  712. {
  713. *p = c->ch;
  714. memmove(p+1,i+1,strlen(i));
  715. break;
  716. }
  717. }
  718. }
  719. static void HTMLURLParse(char* p)
  720. {
  721. for (;*p;++p)
  722. if (p[0]=='%' && Hex(p[1])>=0 && Hex(p[2])>=0)
  723. {
  724. *p = (char)((Hex(p[1])<<4)+Hex(p[2]));
  725. memmove(p+1,p+3,strlen(p+3)+1);
  726. }
  727. }
  728. // detect Apache directory listing order links
  729. static bool_t ListingOrder(const tchar_t* Base,const tchar_t* FileName)
  730. {
  731. tchar_t Path[MAXPATH];
  732. int n = tcslen(Base);
  733. AbsPath(Path,TSIZEOF(Path),FileName,Base);
  734. return tcsncmp(Path,Base,n)==0 && tcsnicmp(Path+n,T("/?C="),4)==0;
  735. }
  736. static int EnumDir(http* p,const tchar_t* URL,const tchar_t* Exts,bool_t ExtFilter,streamdir* Item)
  737. {
  738. if (URL)
  739. {
  740. tchar_t Head[16];
  741. int Pos;
  742. int Result = Open(p,URL,0,0);
  743. if (Result != ERR_NONE)
  744. return Result;
  745. if (!tcsstr(p->ContentType,T("TEXT/HTML")))
  746. {
  747. Open(p,NULL,0,0);
  748. return ERR_NOT_DIRECTORY;
  749. }
  750. if (p->Length<=0)
  751. p->Length = 256*1024-1;
  752. if (p->Length >= 512*1024)
  753. p->Length = 512*1024-1;
  754. p->EnumBuffer = malloc((int)p->Length+1);
  755. if (!p->EnumBuffer)
  756. return ERR_OUT_OF_MEMORY;
  757. Pos = 0;
  758. while (Pos<p->Length)
  759. {
  760. int Size = Read(p,p->EnumBuffer+Pos,p->Length-Pos);
  761. if (Size <= 0)
  762. break;
  763. Pos += Size;
  764. }
  765. GetAsciiToken(Head,16,p->EnumBuffer,p->Length);
  766. if (tcsnicmp(Head,T("<ASX"),4)==0 || 
  767. tcsnicmp(Head,T("[playlist]"),10)==0 || 
  768. tcsnicmp(Head,T("[Reference]"),11)==0)
  769. {
  770. Open(p,NULL,0,0);
  771. return ERR_NOT_DIRECTORY;
  772. }
  773. p->CodePage = GetCodePage(p->ContentType);
  774. p->EnumBuffer[Pos] = 0;
  775. p->EnumPos = p->EnumBuffer;
  776. p->EnumType =0;
  777. p->Exts = Exts;
  778. p->ExtFilter = ExtFilter;
  779. }
  780. while (p->EnumType<4)
  781. {
  782. const char* Tag1;
  783. const char* Tag2;
  784. switch (p->EnumType)
  785. {
  786. case 0:
  787. Tag1 = "<A ";
  788. Tag2 = "HREF=";
  789. break;
  790. case 1:
  791. Tag1 = "<AREA ";
  792. Tag2 = "HREF=";
  793. break;
  794. case 2:
  795. Tag1 = "<EMBED ";
  796. Tag2 = "HREF=";
  797. break;
  798. default:
  799. Tag1 = "<EMBED ";
  800. Tag2 = "SRC=";
  801. break;
  802. }
  803. while (p->EnumPos && (p->EnumPos = FindUpper(p->EnumPos,Tag1))!=NULL)
  804. {
  805. char* End;
  806. p->EnumPos = FindUpper(p->EnumPos,Tag2);
  807. if (!p->EnumPos)
  808. break;
  809. if (*p->EnumPos=='"' || *p->EnumPos==''')
  810. {
  811. ++p->EnumPos;
  812. End = strchr(p->EnumPos,p->EnumPos[-1]);
  813. }
  814. else
  815. End = strchr(p->EnumPos,'>');
  816. if (End)
  817. {
  818. int Len;
  819. char Endch = *End;
  820. *End=0;
  821. HTMLCharParse(p->EnumPos);
  822. StrToTcsEx(Item->FileName,TSIZEOF(Item->FileName),p->EnumPos,p->CodePage);
  823. HTMLURLParse(p->EnumPos);
  824. StrToTcsEx(Item->DisplayName,TSIZEOF(Item->DisplayName),p->EnumPos,p->CodePage);
  825. *End = Endch;
  826. p->EnumPos = End+1;
  827. Item->Date = -1;
  828. Item->Size = -1;
  829. Len = tcslen(Item->FileName);
  830. if (ListingOrder(p->Base,Item->FileName))
  831. continue;
  832. if (Len && Item->FileName[Len-1]=='/')
  833. {
  834. Item->FileName[Len-1]=0;
  835. return ERR_NONE;
  836. }
  837. if (CheckExts(Item->FileName,T("html:H;htm:H;asp:H;php:H")))
  838. return ERR_NONE;
  839. Item->Type = CheckExts(Item->FileName,p->Exts);
  840. Item->Size = 0;
  841. if (Item->Type || !p->ExtFilter)
  842. return ERR_NONE;
  843. }
  844. }
  845. p->EnumPos = p->EnumBuffer;
  846. ++p->EnumType;
  847. }
  848. Open(p,NULL,0,0);
  849. return ERR_END_OF_FILE;
  850. }
  851. static int Create(http* p)
  852. {
  853. HMODULE Module;
  854. p->Stream.Get = (nodeget)Get,
  855. p->Stream.Set = (nodeset)Set,
  856. p->Stream.Read = Read;
  857. p->Stream.ReadBlock = ReadBlock;
  858. p->Stream.Seek = Seek;
  859. p->Stream.EnumDir = EnumDir;
  860. p->Stream.DataAvailable = DataAvailable;
  861. p->Complete = EventCreate(0,0);
  862. Module = GetModuleHandle(T("wininet.dll"));
  863. #ifdef UNICODE
  864. GetProc(&Module,&p->InternetGoOnline,T("InternetGoOnlineW"),1);
  865. #else
  866. GetProc(&Module,&p->InternetGoOnline,T("InternetGoOnlineA"),1);
  867. #endif
  868. return ERR_NONE;
  869. }
  870. static void Delete(http* p)
  871. {
  872. Open(p,NULL,0,0);
  873. EventClose(p->Complete);
  874. }
  875. static const nodedef HTTP =
  876. {
  877. sizeof(http),
  878. HTTP_ID,
  879. STREAM_CLASS,
  880. PRI_MINIMUM,
  881. (nodecreate)Create,
  882. (nodedelete)Delete,
  883. };
  884. static const nodedef MMS =
  885. {
  886. 0, // parent size
  887. MMS_ID,
  888. HTTP_ID,
  889. PRI_MINIMUM,
  890. };
  891. void HTTP_Init()
  892. {
  893. NodeRegisterClass(&HTTP);
  894. NodeRegisterClass(&MMS);
  895. }
  896. void HTTP_Done()
  897. {
  898. NodeUnRegisterClass(MMS_ID);
  899. NodeUnRegisterClass(HTTP_ID);
  900. }
  901. #endif