1
0

readers.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. #include <windows.h>
  2. #include "main.h"
  3. #include <sys/stat.h>
  4. #ifdef NO_WASABI
  5. #include "../../jnetlib/httpget.h"
  6. api_httpreceiver *CreateGet()
  7. {
  8. return new JNL_HTTPGet;
  9. }
  10. void ReleaseGet(api_httpreceiver *&get)
  11. {
  12. delete (JNL_HTTPGet *)get;
  13. get=0;
  14. }
  15. #else
  16. #include "../..\Components\wac_network\wac_network_http_receiver_api.h"
  17. #include <api.h>
  18. #include <api/service/waservicefactory.h>
  19. #include "../../Winamp/in2.h"
  20. extern In_Module mod;
  21. waServiceFactory *httpFactory = 0;
  22. api_httpreceiver *CreateGet()
  23. {
  24. api_httpreceiver *get = 0;
  25. if (!httpFactory && mod.service)
  26. httpFactory = mod.service->service_getServiceByGuid(httpreceiverGUID);
  27. if (httpFactory)
  28. get = (api_httpreceiver *)httpFactory->getInterface();
  29. return get;
  30. }
  31. void ReleaseGet(api_httpreceiver *&get)
  32. {
  33. if (!get)
  34. return ;
  35. if (!httpFactory && mod.service)
  36. waServiceFactory *sf = mod.service->service_getServiceByGuid(httpreceiverGUID);
  37. if (httpFactory)
  38. httpFactory->releaseInterface(get);
  39. get = 0;
  40. }
  41. #endif
  42. #define MAX_MULTICONNECTS 8
  43. class HTTPReader : public IDataReader
  44. {
  45. public:
  46. HTTPReader(const char *url);
  47. ~HTTPReader();
  48. size_t read(char *buf, size_t len);
  49. bool iseof() { return !!m_eof; }
  50. char *gettitle() { return m_title; }
  51. char *geterror() { return m_err; }
  52. bool canseek() { return m_content_length != 0xFFFFFFFF && m_accept_ranges && !m_meta_interval; }
  53. int seek(unsigned __int64 newpos)
  54. {
  55. if (!canseek()) return 1;
  56. doConnect((int)newpos);
  57. return 0;
  58. }
  59. unsigned __int64 getsize() { return m_content_length; }
  60. char *getheader(char *header_name)
  61. {
  62. return m_get ? (char *)m_get->getheader(header_name) : NULL;
  63. }
  64. private:
  65. int serialconnect( int seekto , int timeout);
  66. void doConnect(int seekto);
  67. int getProxyInfo(const char *url, char *out);
  68. char *m_url;
  69. char *m_err;
  70. char *m_title;
  71. int m_eof;
  72. int m_meta_init, m_meta_interval, m_meta_pos, m_meta_size, m_meta_buf_pos;
  73. char m_meta_buf[4096];
  74. int m_read_headers;
  75. unsigned int m_content_length;
  76. int m_accept_ranges;
  77. int m_is_uvox;
  78. int m_uvox_readpos;
  79. int m_uvox_enough_bytes;
  80. char proxybuf[8400], *proxy;
  81. api_httpreceiver *m_get;
  82. // this structure is allocated once, and freed once
  83. struct
  84. {
  85. char *url; //pointers into m_url
  86. // these two are only active temporarily.
  87. api_httpreceiver *get;
  88. char *error;
  89. }
  90. m_cons[MAX_MULTICONNECTS];
  91. int m_numcons;
  92. int m_newcons;
  93. int m_serialized;
  94. int m_mstimeout;
  95. int m_contryptr;
  96. int m_serialfailed;
  97. int m_useaproxy;
  98. };
  99. HTTPReader::HTTPReader(const char *url)
  100. {
  101. m_title = 0;
  102. m_is_uvox = m_uvox_readpos = 0;
  103. m_meta_init = m_meta_interval = m_meta_pos = m_meta_size = m_meta_buf_pos = 0;
  104. m_meta_buf[0] = 0;
  105. m_err = NULL;
  106. m_eof = 0;
  107. m_read_headers = 0;
  108. m_content_length = 0xFFFFFFFF;
  109. m_accept_ranges = 0;
  110. m_get = NULL;
  111. m_serialized = 0;
  112. m_mstimeout = 0;
  113. m_contryptr = 0;
  114. m_newcons = 0;
  115. m_serialfailed = 0;
  116. m_useaproxy = 0;
  117. // TCP multiconnect
  118. // JF> using ; as a delimiter is vomit inducing and breaks a lot of other
  119. // code. I petition we use <> to delimit, and I'm making it do that.
  120. m_numcons = 0;
  121. m_url = _strdup(url);
  122. int allowproxy = 1;
  123. char *tmpurl = m_url;
  124. while (m_numcons < MAX_MULTICONNECTS)
  125. {
  126. char *next = strstr( tmpurl, "<>" );
  127. if ( next ) *next = '\0';
  128. if (tmpurl[0])
  129. {
  130. m_cons[m_numcons].error = NULL;
  131. m_cons[m_numcons].get = NULL;
  132. m_cons[m_numcons++].url = tmpurl;
  133. if (!_strnicmp(tmpurl, "uvox:", 5)) allowproxy = 0;
  134. if (!_strnicmp(tmpurl, "order://", 8))
  135. {
  136. char *p = tmpurl + 8;
  137. // serialized mctp
  138. m_serialized = 1;
  139. m_numcons--;
  140. m_mstimeout = atoi(p);
  141. if ( m_mstimeout < 1 )
  142. {
  143. m_serialized = 0;
  144. m_mstimeout = 0;
  145. }
  146. }
  147. }
  148. if (!next) break;
  149. tmpurl = next + 2;
  150. }
  151. memset(proxybuf, 0, sizeof(proxybuf));
  152. proxy = NULL;
  153. if (allowproxy && getProxyInfo(url, proxybuf))
  154. {
  155. proxy = strstr(proxybuf, "http=");
  156. if (!proxy) proxy = proxybuf;
  157. else
  158. {
  159. proxy += 5;
  160. char *tp = strstr(proxy, ";");
  161. if (tp) *tp = 0;
  162. }
  163. }
  164. m_is_uvox = 0;
  165. if ( m_serialized && m_numcons > 1 ) // sanity check
  166. {
  167. int rval = 0, i;
  168. m_newcons = 1;
  169. // walk the list, set the url such that m_cons[0].url points to each item. try to connect
  170. // serialconnect returns error codes -1 on error, 0 on timeout, 1 on successfull connect
  171. for ( i = 0; i < m_numcons; i++ )
  172. {
  173. if ( i )
  174. {
  175. m_cons[0].url = m_cons[i].url;
  176. }
  177. rval = serialconnect(0, m_mstimeout);
  178. if ( rval == 1 ) break;
  179. }
  180. if ( rval < 1 )
  181. {
  182. // we didnt get a connection so...
  183. m_serialfailed = 1;
  184. }
  185. }
  186. else
  187. doConnect(0);
  188. }
  189. void HTTPReader::doConnect(int seekto)
  190. {
  191. ReleaseGet(m_get);
  192. m_uvox_readpos = 0;
  193. m_eof = 0;
  194. int i;
  195. for (i = 0; i < m_numcons; i++ )
  196. {
  197. free(m_cons[i].error);
  198. m_cons[i].error = NULL;
  199. ReleaseGet(m_cons[i].get);
  200. m_cons[i].get = CreateGet();
  201. if (!m_cons[i].get)
  202. break;
  203. m_cons[i].get->open(API_DNS_AUTODNS, 65536, (proxy && proxy[0]) ? proxy : NULL);
  204. #ifdef WINAMP_PLUGIN
  205. m_cons[i].get->addheader("User-Agent:Winamp NSV Player/5.12 (ultravox/2.0)");
  206. #else
  207. # ifdef WINAMPX
  208. m_cons[i].get->addheader("User-Agent:" UNAGI_USER_AGENT " (ultravox/2.0)");
  209. # else
  210. m_cons[i].get->addheader("User-Agent:NSV Player/0.0 (ultravox/2.0)");
  211. # endif
  212. #endif
  213. m_cons[i].get->addheader("Accept:*/*");
  214. m_cons[i].get->addheader("Connection:close");
  215. m_cons[i].get->addheader("Ultravox-transport-type: TCP");
  216. if (seekto)
  217. {
  218. char buf[64] = {0};
  219. wsprintfA(buf, "Range:bytes=%d-", seekto);
  220. m_cons[i].get->addheader(buf);
  221. }
  222. else
  223. m_cons[i].get->addheader("icy-metadata:1");
  224. m_cons[i].get->connect(m_cons[i].url, !!seekto);
  225. }
  226. m_uvox_enough_bytes = 1;
  227. }
  228. HTTPReader::~HTTPReader()
  229. {
  230. ReleaseGet(m_get);
  231. free(m_title);
  232. free(m_err);
  233. free(m_url);
  234. int i;
  235. for (i = 0; i < m_numcons; i++)
  236. {
  237. ReleaseGet(m_cons[i].get);
  238. free(m_cons[i].error);
  239. }
  240. }
  241. int HTTPReader::serialconnect(int seekto , int timeout)
  242. {
  243. ReleaseGet(m_get);
  244. m_uvox_readpos = 0;
  245. m_eof = 0;
  246. int64_t mythen, mynow , myref;
  247. LARGE_INTEGER then, now, ref;
  248. QueryPerformanceFrequency( &ref);
  249. myref = ref.QuadPart;
  250. QueryPerformanceCounter( &then );
  251. mythen = then.QuadPart;
  252. int timer = 0;
  253. int i = 0;
  254. {
  255. ReleaseGet(m_cons[i].get);
  256. m_cons[i].get = CreateGet();
  257. if (m_cons[i].get == NULL)
  258. return 0;
  259. m_cons[i].get->open(API_DNS_AUTODNS, 65536, (proxy && proxy[0]) ? proxy : NULL);
  260. #ifdef WINAMP_PLUGIN
  261. m_cons[i].get->addheader("User-Agent:Winamp NSV Player/5.12 (ultravox/2.0)");
  262. #else
  263. # ifdef WINAMPX
  264. m_cons[i].get->addheader("User-Agent:" UNAGI_USER_AGENT " (ultravox/2.0)");
  265. # else
  266. m_cons[i].get->addheader("User-Agent:NSV Player/0.0 (ultravox/2.0)");
  267. # endif
  268. #endif
  269. m_cons[i].get->addheader("Accept:*/*");
  270. m_cons[i].get->addheader("Connection:close");
  271. m_cons[i].get->addheader("Ultravox-transport-type: TCP");
  272. if (seekto)
  273. {
  274. char buf[64] = {0};
  275. wsprintfA(buf, "Range:bytes=%d-", seekto);
  276. m_cons[i].get->addheader(buf);
  277. }
  278. else m_cons[i].get->addheader("icy-metadata:1");
  279. m_cons[i].get->connect(m_cons[i].url, !!seekto);
  280. }
  281. m_uvox_enough_bytes = 1;
  282. int ret, status;
  283. if (!m_get)
  284. {
  285. if (m_err) return 0;
  286. int i;
  287. int found = 0;
  288. i = 0;
  289. while ( timer < timeout )
  290. {
  291. if (!m_cons[i].get) return 0;
  292. found = 1;
  293. QueryPerformanceCounter( &now );
  294. mynow = now.QuadPart;
  295. float profiletime = (float)(mynow - mythen);
  296. profiletime /= myref;
  297. profiletime *= 1000.0;
  298. timer = (int) profiletime;
  299. ret = m_cons[i].get->run();
  300. status = m_cons[i].get->get_status();
  301. if (ret < 0 || status < 0)
  302. {
  303. const char *t = m_cons[i].get->geterrorstr();
  304. if (t)
  305. {}
  306. ReleaseGet(m_cons[i].get);
  307. break;
  308. }
  309. if ( status > 0 )
  310. {
  311. int code = m_cons[i].get->getreplycode();
  312. if ( code < 200 || code > 299 )
  313. {
  314. ReleaseGet(m_cons[i].get);
  315. //wsprintf( m_cons[i].error, "Error: Server returned %d", code );
  316. break;
  317. }
  318. else
  319. {
  320. // we're in good shape, make our getter current, and delete all the gay ones
  321. ReleaseGet(m_get); // just in case, probably zero anyway
  322. m_get = m_cons[i].get;
  323. m_cons[i].get = NULL;
  324. // trash i here, but we are breaking anyway :)
  325. /* for (i = 0; i < m_numcons; i++)
  326. {
  327. delete m_cons[i].get;
  328. m_cons[i].get = NULL;
  329. free( m_cons[i].error );
  330. m_cons[i].error = NULL;
  331. }*/
  332. break;
  333. }
  334. }
  335. #ifdef _WIN32
  336. Sleep(1);
  337. #else
  338. usleep(1000);
  339. #endif
  340. } // while
  341. if ( timer > timeout )
  342. {
  343. ReleaseGet(m_cons[i].get);
  344. ReleaseGet(m_get);
  345. return 0;
  346. }
  347. if (!m_get)
  348. {
  349. return 0;
  350. }
  351. }
  352. if ( m_get ) return 1;
  353. else return 0;
  354. }
  355. size_t HTTPReader::read(char *buffer, size_t len)
  356. {
  357. int ret, status;
  358. if (!m_get)
  359. {
  360. if (m_err) return 0;
  361. int i;
  362. int found = 0;
  363. for (i = 0; !m_get && i < m_numcons; i++)
  364. {
  365. if (!m_cons[i].get) continue;
  366. found = 1;
  367. ret = m_cons[i].get->run();
  368. status = m_cons[i].get->get_status();
  369. if (ret < 0 || status < 0)
  370. {
  371. const char *t = m_cons[i].get->geterrorstr();
  372. if (t)
  373. {
  374. free(m_cons[i].error);
  375. m_cons[i].error = _strdup( t );
  376. }
  377. ReleaseGet(m_cons[i].get);
  378. }
  379. if ( status > 0 )
  380. {
  381. int code = m_cons[i].get->getreplycode();
  382. if ( code < 200 || code > 299 )
  383. {
  384. ReleaseGet(m_cons[i].get);
  385. m_cons[i].get = NULL;
  386. free(m_cons[i].error);
  387. m_cons[i].error = (char *)malloc( 100 );
  388. wsprintfA( m_cons[i].error, "Error: Server returned %d", code );
  389. }
  390. else
  391. {
  392. // we're in good shape, make our getter current, and delete all the gay ones
  393. ReleaseGet(m_get); // just in case, probably zero anyway
  394. m_get = m_cons[i].get;
  395. m_cons[i].get = NULL;
  396. // trash i here, but we are breaking anyway :)
  397. for (i = 0; i < m_numcons; i++)
  398. {
  399. ReleaseGet(m_cons[i].get);
  400. free( m_cons[i].error );
  401. m_cons[i].error = NULL;
  402. }
  403. break; // exit loop of connections
  404. }
  405. }
  406. } // loop of connections
  407. if (!found) // out of attempted connections heh
  408. {
  409. free( m_err );
  410. if (m_numcons > 1)
  411. {
  412. size_t size = 0;
  413. for (i = 0; i < m_numcons; i++)
  414. if ( m_cons[i].error ) size += strlen( m_cons[i].error ) + 1;
  415. m_err = (char *)malloc(size + 100);
  416. wsprintfA( m_err, "No Valid Multiconnect URLs (%d);", m_numcons );
  417. for (i = 0; i < m_numcons; i++)
  418. {
  419. strcat( m_err, m_cons[i].error );
  420. strcat( m_err, ";" );
  421. free(m_cons[i].error);
  422. m_cons[i].error = NULL;
  423. }
  424. }
  425. else
  426. {
  427. m_err = m_cons[0].error;
  428. m_cons[0].error = NULL;
  429. if (!m_err) m_err = _strdup("Connection error (Invalid URL?)");
  430. }
  431. }
  432. if (!m_get) return 0;
  433. }
  434. ret = m_get->run();
  435. status = m_get->get_status();
  436. if (ret > 0 && (!m_get->bytes_available() || !m_uvox_enough_bytes) && status > 1)
  437. {
  438. m_eof = 1;
  439. }
  440. if (ret < 0 || status < 0)
  441. {
  442. const char *t = m_get->geterrorstr();
  443. if (t)
  444. {
  445. free( m_err );
  446. m_err = (char *)malloc( strlen( t) + 16 );
  447. wsprintfA( m_err, "Error: %s", t );
  448. return 0;
  449. }
  450. }
  451. if (status > 0)
  452. {
  453. if (!m_read_headers)
  454. {
  455. if (status > 1)
  456. {
  457. const char *v = m_get->getheader("Content-Length");
  458. if (v) m_content_length = atoi(v);
  459. v = m_get->getheader("Accept-Ranges");
  460. if (v) while (v && *v)
  461. {
  462. if (!_strnicmp(v, "bytes", 5))
  463. {
  464. m_accept_ranges = 1;
  465. break;
  466. }
  467. v++;
  468. }
  469. v = m_get->getheader("icy-metaint");
  470. if (v)
  471. {
  472. m_meta_interval = atoi(v);
  473. }
  474. if (!m_title)
  475. {
  476. v = m_get->getheader("icy-name");
  477. if (v)
  478. m_title = _strdup(v);
  479. }
  480. #ifdef WINAMP_PLUGIN
  481. extern void process_url(char *url);
  482. v = m_get->getheader("icy-url");
  483. if (v && !strstr(v, "shoutcast.com"))
  484. {
  485. char *p = (char *)v; while (p && *p && *p == ' ') p++;
  486. process_url(p);
  487. }
  488. #endif
  489. v = m_get->getheader("content-type");
  490. if (v && !_stricmp(v, "misc/ultravox"))
  491. {
  492. v = m_get->getheader("ultravox-max-msg");
  493. if (v) m_is_uvox = atoi(v);
  494. if (!m_is_uvox) m_is_uvox = 16000;
  495. }
  496. if (!m_title)
  497. {
  498. v = m_get->getheader("content-disposition");
  499. if (v) v = strstr(v, "filename=");
  500. if (v)
  501. {
  502. m_title = _strdup(v + 9);
  503. }
  504. }
  505. m_read_headers = 1;
  506. }
  507. }
  508. size_t l = m_get->bytes_available();
  509. if (m_is_uvox)
  510. {
  511. again:
  512. if (l >= 6)
  513. {
  514. unsigned char buf[32768*2] = {0};
  515. m_get->peek_bytes((char *)buf, 6);
  516. if (buf[0] != 0x5A)
  517. {
  518. l--;
  519. m_get->get_bytes((char *)buf, 1);
  520. goto again;
  521. }
  522. int resqos = buf[1];
  523. int classtype = (buf[2] << 8) | buf[3];
  524. int msglen = (buf[4] << 8) | buf[5];
  525. if (msglen > m_is_uvox) // length is too long
  526. {
  527. m_get->get_bytes((char *)buf, 1);
  528. l--;
  529. goto again;
  530. }
  531. if (msglen + 7 <= (int)l)
  532. {
  533. m_uvox_enough_bytes = 1;
  534. m_get->peek_bytes((char *)buf, msglen + 7);
  535. if (buf[msglen + 6])
  536. {
  537. m_get->get_bytes((char *)buf, 1);
  538. l--;
  539. goto again;
  540. }
  541. if (classtype == 0x7777) // take any data for now, ignore all other frames
  542. {
  543. l = msglen - m_uvox_readpos;
  544. if (l > len) l = len;
  545. memcpy(buffer, buf + 6 + m_uvox_readpos, l);
  546. m_uvox_readpos += (int)l;
  547. if (m_uvox_readpos >= msglen)
  548. {
  549. m_uvox_readpos = 0;
  550. m_get->get_bytes((char *)buf, msglen + 7);
  551. }
  552. return l;
  553. #ifdef WINAMP_PLUGIN
  554. }
  555. else if ( classtype == 0x3001 )
  556. {
  557. extern void process_metadata(char *buf, int size);
  558. m_get->get_bytes((char *)buf, msglen + 7);
  559. process_metadata((char*)buf + 6, msglen + 1);
  560. #endif
  561. }
  562. else
  563. {
  564. m_get->get_bytes((char *)buf, msglen + 7);
  565. }
  566. }
  567. else
  568. {
  569. m_uvox_enough_bytes = 0;
  570. }
  571. }
  572. return 0;
  573. }
  574. else
  575. {
  576. if (l > len) l = len;
  577. m_get->get_bytes(buffer, (int)l);
  578. if (m_meta_interval)
  579. {
  580. int x = (int)l;
  581. unsigned char *buf = (unsigned char *)buffer;
  582. if (m_meta_size) // already in meta block
  583. {
  584. int len = min(x, m_meta_size - m_meta_buf_pos);
  585. memcpy(m_meta_buf + m_meta_buf_pos, buf, len);
  586. m_meta_buf_pos += len;
  587. if (m_meta_buf_pos == m_meta_size)
  588. {
  589. // if(metacb) metacb->metaDataReader_onData(m_meta_buf,m_meta_size);
  590. m_meta_buf_pos = 0;
  591. m_meta_size = 0;
  592. m_meta_pos = 0;
  593. }
  594. x -= len;
  595. if (x) memcpy(buf, buf + len, x);
  596. }
  597. else if (m_meta_pos + x > m_meta_interval) // block contains meta data somewhere in it, and we're not alreayd reading a block
  598. {
  599. int start_offs = m_meta_interval - m_meta_pos;
  600. int len;
  601. m_meta_size = ((unsigned char *)buf)[start_offs] * 16;
  602. len = min(x - start_offs - 1, m_meta_size);
  603. if (len) memcpy(m_meta_buf, buf + start_offs + 1, len);
  604. m_meta_buf_pos = len;
  605. if (m_meta_buf_pos == m_meta_size) // full read of metadata successful
  606. {
  607. x -= m_meta_size + 1;
  608. if (x > start_offs) memcpy(buf + start_offs, buf + start_offs + 1 + m_meta_size, x - start_offs);
  609. #ifdef WINAMP_PLUGIN
  610. extern void process_metadata(char *buf, int size);
  611. process_metadata(m_meta_buf, m_meta_size);
  612. #endif
  613. //if(metacb) metacb->metaDataReader_onData(m_meta_buf,m_meta_size);
  614. m_meta_buf_pos = 0;
  615. m_meta_pos = -start_offs;
  616. m_meta_size = 0;
  617. }
  618. else
  619. {
  620. x = start_offs; // otherwise, there's only the first block of data
  621. }
  622. }
  623. if (x > 0)
  624. {
  625. m_meta_pos += x;
  626. }
  627. l = x;
  628. } // end of poopie metadata
  629. } // !uvox
  630. #if 0
  631. {
  632. FILE *fh = fopen("c:\\dump.nsv", "ab");
  633. fwrite(buffer, 1, l, fh);
  634. fclose(fh);
  635. }
  636. #endif
  637. return l;
  638. }
  639. return 0;
  640. }
  641. static void parseURL(char *url, char *lp, char *host, int *port, char *req)
  642. {
  643. char *p, *np;
  644. /* if (_strnicmp(url,"http://",4) &&
  645. _strnicmp(url,"icy://",6) &&
  646. _strnicmp(url,"sc://",6) &&
  647. _strnicmp(url,"shoutcast://",12)) return;
  648. */
  649. np = p = strstr(url, "://");
  650. if (!np) np = (char*)url;
  651. else np += 3;
  652. if (!p) p = (char*)url;
  653. else p += 3;
  654. while (np && *np != '/' && *np) *np++;
  655. if (np && *np)
  656. {
  657. lstrcpynA(req, np, 2048);
  658. *np++ = 0;
  659. }
  660. else strcpy(req, "/");
  661. np = p;
  662. while (np && *np != '@' && *np) np++;
  663. if (np && *np)
  664. {
  665. *np++ = 0;
  666. lstrcpynA(lp, p, 256);
  667. p = np;
  668. }
  669. else lp[0] = 0;
  670. np = p;
  671. while (np && *np != ':' && *np) np++;
  672. if (*np)
  673. {
  674. *np++ = 0;
  675. *port = atoi(np);
  676. }
  677. else *port = 80;
  678. lstrcpynA(host, p, 256);
  679. }
  680. int HTTPReader::getProxyInfo(const char *url, char *out)
  681. {
  682. #ifndef WINAMPX
  683. char INI_FILE[MAX_PATH] = {0};
  684. char *p;
  685. GetModuleFileNameA(NULL, INI_FILE, sizeof(INI_FILE));
  686. p = INI_FILE + strlen(INI_FILE);
  687. while (p >= INI_FILE && *p != '.') p--;
  688. strcpy(++p, "ini");
  689. GetPrivateProfileStringA("Winamp", "proxy", "", out, 8192, INI_FILE);
  690. return !!out[0];
  691. #else
  692. DWORD v = 0;
  693. HKEY hKey;
  694. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\AOL\\Unagi", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  695. {
  696. DWORD l = 4;
  697. DWORD t;
  698. if (RegQueryValueEx(hKey, "ProxyEnable", NULL, &t, (unsigned char *)&v, &l) == ERROR_SUCCESS && t == REG_DWORD)
  699. {
  700. if ( v != 2 )
  701. {
  702. l = 8192;
  703. if (RegQueryValueEx(hKey, "ProxyServer", NULL, &t, (unsigned char *)out, &l ) != ERROR_SUCCESS || t != REG_SZ)
  704. {
  705. v = 0;
  706. *out = 0;
  707. }
  708. }
  709. else return 0;
  710. }
  711. else v = 0;
  712. out[512 - 1] = 0;
  713. RegCloseKey(hKey);
  714. }
  715. if ( !v && m_useaproxy )
  716. {
  717. char blah[8192] = "";
  718. lstrcpyn(blah, url, 8192);
  719. char plp[512] = {0};
  720. char phost[512] = {0};
  721. int pport = 80;
  722. char pthereq[1024] = {0};
  723. parseURL(blah, plp, phost, &pport, pthereq);
  724. v = ResolvProxyFromURL(url, phost, out);
  725. if ( v < 0 ) v = 0; // error getting proxy
  726. }
  727. if ( v > 0)
  728. {
  729. char prox[1024] = {0};
  730. wsprintf(prox, "PROXY: %s", out);
  731. SendMetadata(prox, 1);
  732. }
  733. return v;
  734. #endif
  735. }
  736. class Win32FileReader : public IDataReader
  737. {
  738. public:
  739. Win32FileReader(HANDLE file) { m_hFile = file; m_eof = 0; m_err = NULL; }
  740. ~Win32FileReader() { CloseHandle(m_hFile); }
  741. size_t read(char *buf, size_t len)
  742. {
  743. DWORD ob = 0;
  744. if (!len) return 0;
  745. if (!ReadFile(m_hFile, buf, (DWORD)len, &ob, NULL))
  746. {
  747. m_err = "Error calling ReadFile()!";
  748. return 0;
  749. }
  750. else if (!ob) m_eof = true;
  751. return ob;
  752. }
  753. bool iseof() { return m_eof; }
  754. bool canseek() { return 1; }
  755. int seek(uint64_t newpos)
  756. {
  757. LARGE_INTEGER li;
  758. li.QuadPart = newpos;
  759. li.LowPart = SetFilePointer (m_hFile, li.LowPart, &li.HighPart, SEEK_SET);
  760. if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
  761. {
  762. li.QuadPart = -1;
  763. }
  764. return li.QuadPart== ~0;
  765. }
  766. uint64_t getsize()
  767. {
  768. LARGE_INTEGER position;
  769. position.QuadPart=0;
  770. position.LowPart = GetFileSize(m_hFile, (LPDWORD)&position.HighPart);
  771. if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
  772. return INVALID_FILE_SIZE;
  773. else
  774. return position.QuadPart;
  775. }
  776. char *geterror() { return m_err; }
  777. private:
  778. HANDLE m_hFile;
  779. bool m_eof;
  780. char *m_err;
  781. };
  782. #define VAR_TO_FPOS(fpos, var) (fpos) = (var)
  783. #define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)(fpos)
  784. class FileReader : public IDataReader
  785. {
  786. public:
  787. FileReader(FILE *file) { fp = file; m_err = NULL; }
  788. ~FileReader() { fclose(fp); }
  789. size_t read(char *buf, size_t len)
  790. {
  791. size_t ob;
  792. if (!len) return 0;
  793. ob = fread(buf, 1, len, fp);
  794. if (!ob && ferror(fp))
  795. {
  796. m_err = "Error calling fread()!";
  797. return 0;
  798. }
  799. return ob;
  800. }
  801. bool iseof() { return !!feof(fp); }
  802. bool canseek() { return 1; }
  803. int seek(uint64_t newpos)
  804. {
  805. fpos_t pos= newpos;
  806. VAR_TO_FPOS(pos, newpos);
  807. return fsetpos(fp, &pos);
  808. }
  809. unsigned __int64 getsize()
  810. {
  811. struct stat s;
  812. if (fstat(fileno(fp), &s) < 0)
  813. {
  814. m_err = "Error calling fread()!";
  815. return 0;
  816. }
  817. return s.st_size;
  818. }
  819. char *geterror() { return m_err; }
  820. private:
  821. FILE *fp;
  822. char *m_err;
  823. };
  824. IDataReader *CreateReader(const char *url)
  825. {
  826. if (strstr(url, "://")) return new HTTPReader(url);
  827. #ifdef _WIN32
  828. HANDLE hFile = CreateFileA(url, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  829. OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  830. if (hFile != INVALID_HANDLE_VALUE)
  831. return new Win32FileReader(hFile);
  832. #else
  833. FILE *fp = fopen(url, "r");
  834. if (fp)
  835. return new FileReader(fp);
  836. #endif
  837. return NULL;
  838. }