giofile.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475
  1. /***************************************************************************\
  2. *
  3. * (C) copyright Fraunhofer - IIS (1998)
  4. * All Rights Reserved
  5. *
  6. * filename: giofile.cpp
  7. * project : MPEG Decoder
  8. * author : Martin Sieler
  9. * date : 1998-02-11
  10. * contents/description: file I/O class for MPEG Decoder
  11. *
  12. *
  13. \***************************************************************************/
  14. /* ------------------------ includes --------------------------------------*/
  15. #include "main.h"
  16. #include "api__in_mp3.h"
  17. #include <time.h>
  18. #include <locale.h>
  19. #include "../Winamp/wa_ipc.h"
  20. #include "LAMEinfo.h"
  21. #include "OFL.h"
  22. #include "../nu/AutoChar.h"
  23. #include "../nu/AutoWide.h"
  24. #include <api/service/waservicefactory.h>
  25. #include <shlwapi.h>
  26. #include "MP3Info.h"
  27. #include "config.h"
  28. #include <math.h>
  29. #include "id3.h"
  30. #include "../apev2/header.h"
  31. #include "uvox_3902.h"
  32. #include <foundation/error.h>
  33. #include <strsafe.h>
  34. #define MAX_REDIRECTS 10
  35. #define SAFE_MALLOC_MATH(orig, x) (((orig)<x)?x:orig)
  36. // seems like a reasonable limit, but we should check with tag first
  37. #define UVOX_MAXMSG_CAP 1048576
  38. static jnl_connection_t CreateConnection(const char *url, jnl_dns_t dns, size_t sendbufsize, size_t recvbufsize)
  39. {
  40. if (!_strnicmp(url, "https:", strlen("https:")))
  41. return jnl_sslconnection_create(dns, sendbufsize, recvbufsize);
  42. else
  43. return jnl_connection_create(dns, sendbufsize, recvbufsize);
  44. }
  45. static int64_t Seek64(HANDLE hf, int64_t distance, DWORD MoveMethod)
  46. {
  47. LARGE_INTEGER li;
  48. li.QuadPart = distance;
  49. li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
  50. if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
  51. {
  52. li.QuadPart = -1;
  53. }
  54. return li.QuadPart;
  55. }
  56. HWND GetDialogBoxParent()
  57. {
  58. HWND parent = (HWND)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
  59. if (!parent || parent == (HWND)1)
  60. return mod.hMainWindow;
  61. return parent;
  62. }
  63. /*-------------------------- defines --------------------------------------*/
  64. /*-------------------------------------------------------------------------*/
  65. //-------------------------------------------------------------------------*
  66. //
  67. // CGioFile
  68. //
  69. //-------------------------------------------------------------------------*
  70. //-------------------------------------------------------------------------*
  71. // constructor
  72. //-------------------------------------------------------------------------*
  73. static char ultravoxUserAgent[128] = "";
  74. char *GetUltravoxUserAgent()
  75. {
  76. if (!ultravoxUserAgent[0])
  77. {
  78. StringCchPrintfA(ultravoxUserAgent, 128, "User-Agent: WinampMPEG/%01x.%02x, Ultravox/2.1\r\n"
  79. "Ultravox-transport-type: TCP\r\n",
  80. WINAMP_VERSION_MAJOR(winampVersion),
  81. WINAMP_VERSION_MINOR(winampVersion));
  82. }
  83. return ultravoxUserAgent;
  84. }
  85. static char userAgent[128] = "";
  86. char *GetUserAgent()
  87. {
  88. if (!userAgent[0])
  89. {
  90. StringCchPrintfA(userAgent, 128, "User-Agent: WinampMPEG/%01x.%02x\r\n",
  91. WINAMP_VERSION_MAJOR(winampVersion),
  92. WINAMP_VERSION_MINOR(winampVersion));
  93. }
  94. return userAgent;
  95. }
  96. extern int lastfn_status_err;
  97. CGioFile::CGioFile()
  98. {
  99. req=0;
  100. proxy_host=0;
  101. host=0;
  102. request=0;
  103. proxy_lp=0;
  104. lpinfo=0;
  105. mpeg_length=0;
  106. file_position=0;
  107. mpeg_position=0;
  108. no_peek_hack=false;
  109. encodingMethod=0;
  110. uvox_3901=0;
  111. uvox_3902=0;
  112. stream_url[0]=0;
  113. stream_genre[0]=0;
  114. stream_current_title[0]=0;
  115. stream_name[0]=0;
  116. ZeroMemory(&last_write_time, sizeof(last_write_time));
  117. ZeroMemory(id3v1_data, sizeof(id3v1_data));
  118. lengthVerified=false;
  119. m_vbr_bytes = 0;
  120. uvox_last_message = 0;
  121. prepad = 0;
  122. postpad = 0;
  123. m_vbr_ms = 0;
  124. m_vbr_hdr = 0;
  125. stream_id3v2_buf = 0;
  126. lyrics3_size=0;
  127. lyrics3_data=0;
  128. apev2_data=0;
  129. m_content_type = 0;
  130. ZeroMemory(uvox_meta, sizeof(uvox_meta));
  131. is_uvox = 0;
  132. uvox_sid = uvox_maxbr = uvox_avgbr = 0;
  133. uvox_message_cnt = uvox_desyncs = 0;
  134. uvox_stream_data = 0;
  135. uvox_stream_data_len = 0;
  136. ZeroMemory(&uvox_artwork, sizeof(uvox_artwork));
  137. uvox_maxmsg = 65535;
  138. force_lpinfo[0] = 0;
  139. is_stream_seek = 0;
  140. last_full_url[0] = 0;
  141. m_is_stream = 0;
  142. m_redircnt = 0;
  143. m_auth_tries = 0;
  144. m_full_buffer = NULL;
  145. fEof = false;
  146. m_connection = NULL;
  147. m_dns = NULL;
  148. hFile = INVALID_HANDLE_VALUE;
  149. m_http_response = 0;
  150. m_seek_reset = false;
  151. m_is_stream_seek = false;
  152. m_is_stream_seekable = false;
  153. initTitleList();
  154. m_vbr_frames = 0;
  155. ZeroMemory(&m_vbr_toc, sizeof(m_vbr_toc));
  156. m_vbr_frame_len = 0;
  157. m_vbr_flag = 0;
  158. m_id3v2_len = 0;
  159. m_id3v1_len = 0;
  160. port = 80;
  161. constate = 0;
  162. ZeroMemory(&save_filename, sizeof(save_filename));
  163. ZeroMemory(&server_name, sizeof(server_name));
  164. recvbuffersize = 32768;
  165. timeout_start = GetTickCount();
  166. meta_interval = 0;
  167. meta_pos = 0;
  168. ZeroMemory(&stream_title_save, sizeof(stream_title_save));
  169. ZeroMemory(&last_title_sent, sizeof(last_title_sent));
  170. ZeroMemory(&dlg_realm, sizeof(dlg_realm));
  171. m_useaproxy = 0;
  172. }
  173. //-------------------------------------------------------------------------*
  174. // destructor
  175. //-------------------------------------------------------------------------*
  176. CGioFile::~CGioFile()
  177. {
  178. int x, y;
  179. for (x = 0; x < 2; x ++)
  180. for (y = 0; y < 32; y ++)
  181. free(uvox_meta[x][y]);
  182. free(m_content_type);
  183. free(uvox_stream_data);
  184. free(stream_id3v2_buf);
  185. free(lyrics3_data);
  186. free(apev2_data);
  187. free(uvox_3901);
  188. free(uvox_3902);
  189. Close();
  190. delete m_vbr_hdr;
  191. m_vbr_hdr = 0;
  192. clearTitleList();
  193. free(lpinfo);
  194. free(proxy_lp);
  195. free(request);
  196. free(host);
  197. free(req);
  198. free(proxy_host);
  199. }
  200. static bool GetRG(const char *key, ID3v2 &info, APEv2::Tag &apev2, wchar_t *val, int len)
  201. {
  202. val[0]=0;
  203. if (info.GetString(key, val, len) == 1 && val[0])
  204. return true;
  205. if (apev2.GetString(key, val, len) == APEv2::APEV2_SUCCESS && val[0])
  206. return true;
  207. return false;
  208. }
  209. float CGioFile::GetGain()
  210. {
  211. if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false))
  212. {
  213. // if (info.HasData())
  214. {
  215. float dB = 0, peak = 1.0f;
  216. wchar_t gain[128] = L"", peakVal[128] = L"";
  217. _locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
  218. switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_source", 0))
  219. {
  220. case 0: // track
  221. if ((GetRG("replaygain_track_gain", info, apev2, gain, 128) == false || !gain[0])
  222. && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
  223. GetRG("replaygain_album_gain", info, apev2, gain, 128);
  224. if ((GetRG("replaygain_track_peak", info, apev2, peakVal, 128) == false || !peakVal[0])
  225. && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
  226. GetRG("replaygain_album_peak", info, apev2, peakVal, 128);
  227. break;
  228. case 1:
  229. if ((GetRG("replaygain_album_gain", info, apev2, gain, 128) == false || !gain[0])
  230. && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
  231. GetRG("replaygain_track_gain", info, apev2, gain, 128);
  232. if ((GetRG("replaygain_album_peak", info, apev2, peakVal, 128) == false || !peakVal[0])
  233. && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
  234. GetRG("replaygain_track_peak", info, apev2, peakVal, 128);
  235. break;
  236. }
  237. if (gain[0])
  238. {
  239. if (gain[0] == L'+')
  240. dB = (float)_wtof_l(&gain[1], C_locale);
  241. else
  242. dB = (float)_wtof_l(gain, C_locale);
  243. }
  244. else
  245. {
  246. dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0);
  247. return (float)pow(10.0f, dB / 20.0f);
  248. }
  249. if (peakVal[0])
  250. {
  251. peak = (float)_wtof_l(peakVal, C_locale);
  252. }
  253. switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_mode", 1))
  254. {
  255. case 0: // apply gain
  256. return (float)pow(10.0f, dB / 20.0f);
  257. case 1: // apply gain, but don't clip
  258. return min((float)pow(10.0f, dB / 20.0f), 1.0f / peak);
  259. case 2: // normalize
  260. return 1.0f / peak;
  261. case 3: // prevent clipping
  262. if (peak > 1.0f)
  263. return 1.0f / peak;
  264. else
  265. return 1.0f;
  266. }
  267. }
  268. /* else
  269. {
  270. float dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0);
  271. return pow(10.0f, dB / 20.0f);
  272. }*/
  273. }
  274. return 1.0f; // no gain
  275. }
  276. //-------------------------------------------------------------------------*
  277. // Open
  278. //-------------------------------------------------------------------------*
  279. static char *jnl_strndup(const char *str, size_t n)
  280. {
  281. char *o = (char *)calloc(n+1, sizeof(char));
  282. if (!o)
  283. return 0;
  284. strncpy(o, str, n);
  285. o[n]=0;
  286. return o;
  287. }
  288. static int parse_url(const char *url, char **prot, char **host, unsigned short *port, char **req, char **lp)
  289. {
  290. free(*prot); *prot=0;
  291. free(*host); *host = 0;
  292. free(*req); *req = 0;
  293. free(*lp); *lp = 0;
  294. *port = 0;
  295. const char *p;
  296. const char *protocol = strstr(url, "://");
  297. if (protocol)
  298. {
  299. *prot = jnl_strndup(url, protocol-url);
  300. p = protocol + 3;
  301. }
  302. else
  303. {
  304. p = url;
  305. }
  306. while (p && *p == '/') p++; // skip extra /
  307. size_t end = strcspn(p, "@/");
  308. // check for username
  309. if (p[end] == '@')
  310. {
  311. *lp = jnl_strndup(p, end);
  312. p = p+end+1;
  313. end = strcspn(p, "[:/");
  314. }
  315. if (p[0] == '[') // IPv6 style address
  316. {
  317. p++;
  318. const char *ipv6_end = strchr(p, ']');
  319. if (!ipv6_end)
  320. return 1;
  321. *host = jnl_strndup(p, ipv6_end-p);
  322. p = ipv6_end+1;
  323. }
  324. else
  325. {
  326. end = strcspn(p, ":/");
  327. *host = jnl_strndup(p, end);
  328. p += end;
  329. }
  330. // is there a port number?
  331. if (p[0] == ':')
  332. {
  333. char *new_end;
  334. *port = (unsigned short)strtoul(p+1, &new_end, 10);
  335. p = new_end;
  336. }
  337. if (p[0])
  338. {
  339. *req = _strdup(p);
  340. }
  341. return 0;
  342. }
  343. static void parseURL(const char *url, char **host, unsigned short *port, char **req, char **lp)
  344. {
  345. char *prot=0;
  346. parse_url(url, &prot, host, port, req, lp);
  347. if (!*port)
  348. {
  349. if (prot)
  350. {
  351. if (!stricmp(prot, "https"))
  352. *port = 443;
  353. else
  354. *port = 80;
  355. }
  356. else
  357. *port=80;
  358. }
  359. free(prot);
  360. if (!*req)
  361. *req = _strdup("/");
  362. }
  363. static void encodeMimeStr(char *in, char *out)
  364. {
  365. char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  366. int shift = 0;
  367. int accum = 0;
  368. while (in && *in)
  369. {
  370. if (*in)
  371. {
  372. accum <<= 8;
  373. shift += 8;
  374. accum |= *in++;
  375. }
  376. while (shift >= 6)
  377. {
  378. shift -= 6;
  379. *out++ = alphabet[(accum >> shift) & 0x3F];
  380. }
  381. }
  382. if (shift == 4)
  383. {
  384. *out++ = alphabet[(accum & 0xF) << 2];
  385. *out++ = '=';
  386. }
  387. else if (shift == 2)
  388. {
  389. *out++ = alphabet[(accum & 0x3) << 4];
  390. *out++ = '=';
  391. *out++ = '=';
  392. }
  393. *out++ = 0;
  394. }
  395. int CGioFile::doConnect(const char *str, int start_offset)
  396. {
  397. char *http_ver_str = " HTTP/1.0\r\n";
  398. unsigned short proxy_port = 80;
  399. char str2[1024]={0};
  400. if (!str)
  401. str = last_full_url;
  402. else
  403. lstrcpynA( last_full_url, str, sizeof( last_full_url ) );
  404. if (start_offset > 0)
  405. {
  406. http_ver_str = " HTTP/1.1\r\n";
  407. }
  408. lstrcpynA(str2, str, 1024);
  409. is_stream_seek = start_offset || !str;
  410. lstrcpynA(g_stream_title, str, 256);
  411. meta_interval = meta_pos = 0;
  412. server_name[0] = 0;
  413. last_title_sent[0] = 0;
  414. stream_bytes_read = start_offset;
  415. stream_metabytes_read = 0;
  416. m_is_stream = 1;
  417. constate = 0;
  418. parseURL(str2, &host, &port, &request, &lpinfo);
  419. if (port == 80 || !GetPrivateProfileIntA("Winamp", "proxyonly80", 0, INI_FILE))
  420. {
  421. const char *p;
  422. const char *winamp_proxy = (const char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_PROXY_STRING);
  423. if (!winamp_proxy || winamp_proxy == (char *)1)
  424. {
  425. char temp[256] = {0};
  426. GetPrivateProfileStringA("Winamp", "proxy", "", temp, sizeof(temp), INI_FILE);
  427. p = temp;
  428. }
  429. else
  430. p = winamp_proxy;
  431. while (p && (*p == ' ' || *p == '\t')) p++;
  432. char config_proxy[512] = "http://";
  433. StringCchCatA(config_proxy, 512, p);
  434. parseURL(config_proxy, &proxy_host, &proxy_port, &req, &proxy_lp);
  435. }
  436. if (!host || !host[0])
  437. return 1;
  438. char *p = request + strlen(request);
  439. while (p >= request && *p != '/') p--;
  440. if (p[1])
  441. lstrcpynA(g_stream_title, ++p, 256);
  442. lstrcpynA(stream_title_save, g_stream_title, 580);
  443. lstrcpynA(stream_name, g_stream_title, 256);
  444. g_stream_title[255] = 0;
  445. fEof = false;
  446. timeout_start = GetTickCount();
  447. EnterCriticalSection(&g_lfnscs);
  448. WASABI_API_LNGSTRING_BUF(IDS_CONNECTING,lastfn_status,256);
  449. LeaveCriticalSection(&g_lfnscs);
  450. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  451. if (force_lpinfo[0])
  452. {
  453. free(lpinfo);
  454. lpinfo = _strdup(force_lpinfo);
  455. }
  456. if (!m_dns) jnl_dns_create(&m_dns);
  457. m_connection = CreateConnection(str, m_dns, 16384, recvbuffersize = max(32768, config_http_buffersize * 1024));
  458. if (!m_connection)
  459. return 1;
  460. if (!proxy_host || !proxy_host[0])
  461. {
  462. jnl_connection_connect(m_connection, host, port);
  463. jnl_connection_send_string(m_connection, "GET ");
  464. jnl_connection_send_string(m_connection, request);
  465. jnl_connection_send_string(m_connection, http_ver_str);
  466. }
  467. else
  468. {
  469. char s[32]={0};
  470. jnl_connection_connect(m_connection, proxy_host, proxy_port);
  471. jnl_connection_send_string(m_connection, "GET http://");
  472. if (lpinfo && lpinfo[0])
  473. {
  474. jnl_connection_send_string(m_connection, lpinfo);
  475. jnl_connection_send_string(m_connection, "@");
  476. }
  477. jnl_connection_send_string(m_connection, host);
  478. StringCchPrintfA(s, 32, ":%d", port);
  479. jnl_connection_send_string(m_connection, s);
  480. jnl_connection_send_string(m_connection, request);
  481. jnl_connection_send_string(m_connection, http_ver_str);
  482. if (proxy_lp && proxy_lp[0])
  483. {
  484. char temp[1024]={0};
  485. jnl_connection_send_string(m_connection, "Proxy-Authorization: Basic ");
  486. encodeMimeStr(proxy_lp, temp);
  487. jnl_connection_send_string(m_connection, temp);
  488. jnl_connection_send_string(m_connection, "\r\n");
  489. }
  490. }
  491. jnl_connection_send_string(m_connection, "Host: ");
  492. jnl_connection_send_string(m_connection, host);
  493. jnl_connection_send_string(m_connection, "\r\n");
  494. if (!start_offset)
  495. {
  496. jnl_connection_send_string(m_connection, GetUltravoxUserAgent());
  497. }
  498. else
  499. jnl_connection_send_string(m_connection, GetUserAgent());
  500. jnl_connection_send_string(m_connection, "Accept: */*\r\n");
  501. if (allow_sctitles && !start_offset) jnl_connection_send_string(m_connection, "Icy-MetaData:1\r\n");
  502. if (lpinfo && lpinfo[0])
  503. {
  504. char str[512] = {0};
  505. encodeMimeStr(lpinfo, str);
  506. jnl_connection_send_string(m_connection, "Authorization: Basic ");
  507. jnl_connection_send_string(m_connection, str);
  508. jnl_connection_send_string(m_connection, "\r\n");
  509. }
  510. if (start_offset > 0)
  511. {
  512. char str[512] = {0};
  513. StringCchPrintfA(str, 512, "Range: bytes=%d-\r\n", start_offset);
  514. jnl_connection_send_string(m_connection, str);
  515. }
  516. jnl_connection_send_string(m_connection, "Connection: close\r\n");
  517. jnl_connection_send_string(m_connection, "\r\n");
  518. return 0;
  519. }
  520. int CGioFile::Open(const wchar_t *pszName, int maxbufsizek)
  521. {
  522. peekBuffer.reserve(16384);
  523. m_vbr_flag = 0;
  524. m_vbr_frames = 0;
  525. m_vbr_samples = 0;
  526. m_vbr_ms = 0;
  527. m_vbr_frame_len = 0;
  528. m_id3v2_len = 0;
  529. m_id3v1_len = 0;
  530. m_apev2_len = 0;
  531. lyrics3_size = 0;
  532. m_is_stream = 0;
  533. mpeg_length = 0;
  534. mpeg_position = 0;
  535. file_position = 0;
  536. if ( !_wcsnicmp( pszName, L"file://", 7 ) )
  537. pszName += 7;
  538. if ( PathIsURL( pszName ) )
  539. {
  540. wchar_t str[ 8192 ] = { 0 };
  541. wchar_t *p;
  542. hFile = INVALID_HANDLE_VALUE;
  543. lstrcpyn( str, pszName, 8192 );
  544. save_filename[ 0 ] = 0;
  545. if ( p = wcsstr( str, L">save.file:" ) )
  546. {
  547. *p = 0;
  548. p += 11;
  549. if ( !wcsstr( p, L".." ) && !wcsstr( p, L"\\" ) && !wcsstr( p, L"/" ) )
  550. {
  551. lstrcpynA( save_filename, AutoChar( p ), 256 );
  552. }
  553. }
  554. if ( doConnect( AutoChar( str ), 0 ) )
  555. return NErr_ConnectionFailed;
  556. }
  557. else
  558. {
  559. hFile = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
  560. if (hFile != INVALID_HANDLE_VALUE)
  561. {
  562. GetFileTime( hFile, 0, 0, &last_write_time );
  563. mpeg_length = Seek64( hFile, 0, FILE_END );
  564. uint64_t startOffset = 0;
  565. unsigned char buf[ 1448 ] = { 0 };
  566. DWORD len = 0;
  567. while ( 1 ) // read all tags (sometimes programs get stupid and make multiple tags)
  568. {
  569. len = 0;
  570. Seek64( hFile, startOffset, FILE_BEGIN );
  571. ReadFile( hFile, buf, 10, &len, NULL );
  572. if ( len >= 10 &&
  573. buf[ 0 ] == 'I' &&
  574. buf[ 1 ] == 'D' &&
  575. buf[ 2 ] == '3' &&
  576. buf[ 3 ] != 255 &&
  577. buf[ 4 ] != 255 &&
  578. buf[ 6 ] < 0x80 &&
  579. buf[ 7 ] < 0x80 &&
  580. buf[ 8 ] < 0x80 &&
  581. buf[ 9 ] < 0x80 )
  582. {
  583. DWORD thisLen = 10;
  584. if ( buf[ 5 ] & 0x10 ) // check for footer flag
  585. thisLen += 10;
  586. thisLen += ( (int)buf[ 6 ] ) << 21;
  587. thisLen += ( (int)buf[ 7 ] ) << 14;
  588. thisLen += ( (int)buf[ 8 ] ) << 7;
  589. thisLen += ( (int)buf[ 9 ] );
  590. SetFilePointer( hFile, -10, NULL, FILE_CURRENT );
  591. if ( stream_id3v2_buf ) // already read a tag?
  592. {
  593. startOffset += thisLen;
  594. m_id3v2_len += thisLen;
  595. mpeg_length -= thisLen;
  596. mpeg_position += thisLen;
  597. SetFilePointer( hFile, thisLen, NULL, FILE_CURRENT );
  598. continue;
  599. }
  600. stream_id3v2_buf = (char *)malloc( thisLen );
  601. if ( stream_id3v2_buf )
  602. {
  603. memcpy( stream_id3v2_buf, buf, 10 );
  604. DWORD dummy = 0;
  605. if ( !ReadFile( hFile, stream_id3v2_buf, thisLen, &dummy, 0 ) || dummy < thisLen )
  606. {
  607. free( stream_id3v2_buf );
  608. stream_id3v2_buf = NULL;
  609. thisLen = 0;
  610. SetFilePointer( hFile, 0, NULL, FILE_END );
  611. break;
  612. }
  613. else
  614. {
  615. mpeg_position += thisLen;
  616. stream_id3v2_read = thisLen;
  617. mpeg_length -= thisLen;
  618. startOffset += thisLen;
  619. info.Decode( stream_id3v2_buf, thisLen );
  620. }
  621. }
  622. else
  623. {
  624. /* memory allocation failed, let's assume the ID3v2 tag was valid ... */
  625. mpeg_position += thisLen;
  626. stream_id3v2_read = thisLen;
  627. mpeg_length -= thisLen;
  628. startOffset += thisLen;
  629. }
  630. m_id3v2_len += thisLen;
  631. }
  632. else
  633. {
  634. // benski> unnecessary because we call SetFilePointer immediately after the loop:
  635. // CUT: SetFilePointer(hFile, -10, NULL, FILE_CURRENT);
  636. break;
  637. }
  638. }
  639. /* Read ID3v1 Tag */
  640. if ( mpeg_length >= 128 )
  641. {
  642. SetFilePointer( hFile, -128, NULL, FILE_END );
  643. len = 0;
  644. if ( ReadFile( hFile, id3v1_data, 128, &len, NULL ) && len == 128 )
  645. {
  646. if ( id3v1_data[ 0 ] == 'T' && id3v1_data[ 1 ] == 'A' && id3v1_data[ 2 ] == 'G' )
  647. {
  648. m_id3v1_len = 128;
  649. mpeg_length -= m_id3v1_len;
  650. }
  651. }
  652. }
  653. /* read appended ID3v2.4 tag */
  654. if ( mpeg_length >= 10 && Seek64( hFile, mpeg_position + mpeg_length - 10, FILE_BEGIN ) != -1 )
  655. {
  656. len = 0;
  657. ReadFile( hFile, buf, 10, &len, NULL );
  658. if ( len >= 10 &&
  659. buf[ 0 ] == '3' &&
  660. buf[ 1 ] == 'D' &&
  661. buf[ 2 ] == 'I' &&
  662. buf[ 3 ] != 255 &&
  663. buf[ 4 ] != 255 &&
  664. buf[ 6 ] < 0x80 &&
  665. buf[ 7 ] < 0x80 &&
  666. buf[ 8 ] < 0x80 &&
  667. buf[ 9 ] < 0x80 )
  668. {
  669. DWORD thisLen = 10;
  670. if ( buf[ 5 ] & 0x10 ) // check for header flag
  671. thisLen += 10;
  672. thisLen += ( (int)buf[ 6 ] ) << 21;
  673. thisLen += ( (int)buf[ 7 ] ) << 14;
  674. thisLen += ( (int)buf[ 8 ] ) << 7;
  675. thisLen += ( (int)buf[ 9 ] );
  676. mpeg_length -= thisLen;
  677. }
  678. }
  679. /* Read Lyrics3 Tag */
  680. if ( mpeg_length >= 15 )
  681. {
  682. free( lyrics3_data );
  683. lyrics3_data = NULL;
  684. lyrics3_size = 0;
  685. char lyrics3_end_signature[ 15 ] = { 0 };
  686. Seek64( hFile, ( mpeg_position + mpeg_length - 15 ), FILE_BEGIN );
  687. len = 0;
  688. if ( ReadFile( hFile, lyrics3_end_signature, 15, &len, NULL ) && len == 15 )
  689. {
  690. if ( !memcmp( lyrics3_end_signature + 6, "LYRICS200", 9 ) )
  691. {
  692. lyrics3_size = strtoul( lyrics3_end_signature, 0, 10 );
  693. if ( lyrics3_size )
  694. {
  695. lyrics3_data = (char *)malloc( lyrics3_size );
  696. if ( lyrics3_data )
  697. {
  698. SetFilePointer( hFile, -(LONG)( 15 + lyrics3_size ), NULL, FILE_CURRENT );
  699. len = 0;
  700. ReadFile( hFile, lyrics3_data, lyrics3_size, &len, 0 );
  701. if ( len != lyrics3_size || memcmp( lyrics3_data, "LYRICSBEGIN", 11 ) )
  702. {
  703. free( lyrics3_data );
  704. lyrics3_data = NULL;
  705. lyrics3_size = 0;
  706. }
  707. else
  708. {
  709. mpeg_length -= lyrics3_size + 15;
  710. }
  711. }
  712. }
  713. }
  714. }
  715. }
  716. if ( mpeg_length >= 32 )
  717. {
  718. /* Read APEv2 Tag */
  719. free( apev2_data );
  720. apev2_data = NULL;
  721. char ape[ 32 ] = { 0 };
  722. Seek64( hFile, ( mpeg_position + mpeg_length - 32 ), FILE_BEGIN );
  723. len = 0;
  724. if ( ReadFile( hFile, ape, 32, &len, NULL ) && len == 32 )
  725. {
  726. APEv2::Header footer( ape );
  727. if ( footer.Valid() )
  728. {
  729. m_apev2_len = footer.TagSize();
  730. if ( mpeg_length >= m_apev2_len )
  731. {
  732. Seek64( hFile, -(int64_t)( m_apev2_len ), FILE_CURRENT );
  733. apev2_data = (char *)malloc( m_apev2_len );
  734. if ( apev2_data )
  735. {
  736. len = 0;
  737. ReadFile( hFile, apev2_data, m_apev2_len, &len, NULL );
  738. if ( len != m_apev2_len || apev2.Parse( apev2_data, m_apev2_len ) != APEv2::APEV2_SUCCESS )
  739. {
  740. free( apev2_data );
  741. apev2_data = NULL;
  742. m_apev2_len = 0;
  743. }
  744. }
  745. mpeg_length -= m_apev2_len;
  746. }
  747. }
  748. }
  749. }
  750. {
  751. Seek64( hFile, mpeg_position, FILE_BEGIN );
  752. len = 0;
  753. ReadFile( hFile, buf, sizeof( buf ), &len, NULL );
  754. delete m_vbr_hdr;
  755. m_vbr_hdr = NULL;
  756. LAMEinfo lame;
  757. lame.toc = m_vbr_toc;
  758. m_vbr_frame_len = ReadLAMEinfo( buf, &lame );
  759. if ( m_vbr_frame_len )
  760. {
  761. lengthVerified = false;
  762. prepad = lame.encoderDelay;
  763. postpad = lame.padding;
  764. encodingMethod = lame.encodingMethod;
  765. if ( !encodingMethod && lame.cbr )
  766. encodingMethod = ENCODING_METHOD_CBR;
  767. if ( lame.flags & TOC_FLAG )
  768. {
  769. int x;
  770. for ( x = 0; x < 100; x++ )
  771. if ( m_vbr_toc[ x ] ) break;
  772. if ( x != 100 )
  773. m_vbr_flag = 1;
  774. }
  775. if ( lame.flags & BYTES_FLAG )
  776. {
  777. // some programs are stupid and count the id3v2 length in the lame header
  778. if ( mpeg_length + m_id3v2_len == lame.bytes || mpeg_length + m_id3v2_len + m_id3v1_len == lame.bytes )
  779. {
  780. m_vbr_bytes = mpeg_length;
  781. lengthVerified = true;
  782. }
  783. else if ( abs( (int)mpeg_length - lame.bytes ) < MAX_ACCEPTABLE_DEVIANCE )
  784. {
  785. m_vbr_bytes = lame.bytes;
  786. lengthVerified = true;
  787. }
  788. }
  789. if ( lame.flags & FRAMES_FLAG
  790. && m_vbr_bytes && lengthVerified ) // only use the length if we're sure it's unmodified
  791. {
  792. m_vbr_frames = lame.frames;
  793. m_vbr_samples = Int32x32To64( lame.frames, lame.h_id ? 1152 : 576 );
  794. m_vbr_samples -= ( prepad + postpad );
  795. m_vbr_ms = MulDiv( (int)m_vbr_samples, 1000, lame.samprate );
  796. }
  797. if ( !m_vbr_frames || encodingMethod == ENCODING_METHOD_CBR )
  798. m_vbr_flag = 0;
  799. mpeg_length -= m_vbr_frame_len;
  800. mpeg_position += m_vbr_frame_len;
  801. }
  802. else
  803. {
  804. m_vbr_hdr = new CVbriHeader;
  805. m_vbr_frame_len = m_vbr_hdr->readVbriHeader(buf);
  806. if (m_vbr_frame_len)
  807. {
  808. m_vbr_bytes = m_vbr_hdr->getBytes();
  809. m_vbr_frames = m_vbr_hdr->getNumFrames();
  810. m_vbr_ms = m_vbr_hdr->getNumMS();
  811. lengthVerified = true;
  812. mpeg_length -= m_vbr_frame_len;
  813. mpeg_position += m_vbr_frame_len;
  814. }
  815. else
  816. {
  817. delete m_vbr_hdr;
  818. m_vbr_hdr = NULL;
  819. }
  820. }
  821. }
  822. // read OFL
  823. {
  824. Seek64( hFile, mpeg_position, FILE_BEGIN );
  825. len = 0;
  826. ReadFile( hFile, buf, sizeof( buf ), &len, NULL );
  827. MPEGFrame frame;
  828. frame.ReadBuffer( buf );
  829. OFL ofl;
  830. if ( ofl.Read( frame, &buf[ 4 ], len - 4 ) == NErr_Success )
  831. {
  832. m_vbr_ms = (int)ofl.GetLengthSeconds() * 1000;
  833. m_vbr_samples = ofl.GetSamples();
  834. m_vbr_frames = ofl.GetFrames();
  835. size_t pre, post;
  836. if ( ofl.GetGaps( &pre, &post ) == NErr_Success )
  837. {
  838. prepad = (int)pre - 529;
  839. postpad = (int)post + 529;
  840. }
  841. }
  842. }
  843. ReadiTunesGaps();
  844. Seek64( hFile, mpeg_position, FILE_BEGIN );
  845. if ( maxbufsizek * 1024 >= mpeg_length )
  846. {
  847. DWORD m_full_buffer_len = 0;
  848. m_full_buffer = new unsigned char[ (unsigned int)mpeg_length ];
  849. if ( !ReadFile( hFile, m_full_buffer, (DWORD)mpeg_length, &m_full_buffer_len, NULL ) )
  850. {
  851. CloseHandle( hFile );
  852. hFile = INVALID_HANDLE_VALUE;
  853. delete[] m_full_buffer;
  854. m_full_buffer = NULL;
  855. return NErr_Error;
  856. }
  857. CloseHandle( hFile );
  858. hFile = INVALID_HANDLE_VALUE;
  859. m_full_buffer_pos = 0;
  860. }
  861. else
  862. {
  863. m_full_buffer = NULL;
  864. }
  865. fEof = false;
  866. return NErr_Success;
  867. }
  868. else
  869. {
  870. //DWORD dwError = GetLastError();
  871. return NErr_Error;
  872. }
  873. }
  874. return NErr_Success;
  875. }
  876. //-------------------------------------------------------------------------*
  877. // Close
  878. //-------------------------------------------------------------------------*
  879. int CGioFile::Close()
  880. {
  881. int dwReturn = NErr_Success;
  882. if (m_is_stream)
  883. {
  884. jnl_connection_release(m_connection);
  885. if (m_dns) jnl_dns_release(m_dns);
  886. m_dns = 0;
  887. if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
  888. hFile = INVALID_HANDLE_VALUE;
  889. m_is_stream = 0;
  890. }
  891. else
  892. {
  893. delete [] m_full_buffer;
  894. m_full_buffer = NULL;
  895. if (hFile != INVALID_HANDLE_VALUE)
  896. {
  897. dwReturn = CloseHandle(hFile) ? NErr_Success : NErr_Error;
  898. hFile = INVALID_HANDLE_VALUE;
  899. }
  900. }
  901. return dwReturn;
  902. }
  903. void CGioFile::processMetaData(char *data, int len, int msgId)
  904. {
  905. if (len && *data)
  906. {
  907. char *ld = NULL;
  908. int x;
  909. if (len > 4096) return ;
  910. for (x = 0; x < len; x ++)
  911. if (!data[x]) break;
  912. if (x == len) return ;
  913. while ((ld = strstr(data, "='")))
  914. {
  915. char * n = data;
  916. ld[0] = 0;
  917. ld += 2;
  918. data = strstr(ld, "';");
  919. if (data)
  920. {
  921. data[0] = 0;
  922. data += 2;
  923. if (!_stricmp(n, "StreamTitle"))
  924. {
  925. lstrcpynA(g_stream_title, ld, sizeof(g_stream_title));
  926. lstrcpynA(last_title_sent, g_stream_title, sizeof(last_title_sent));
  927. lstrcpynA(stream_current_title, g_stream_title, sizeof(stream_current_title));
  928. if (sctitle_format)
  929. {
  930. StringCchCatA(g_stream_title, 256, *stream_title_save ? *g_stream_title ? " (" : "(" : "");
  931. StringCchCatA(g_stream_title, 256, stream_title_save);
  932. StringCchCatA(g_stream_title, 256, *stream_title_save ? ")" : "");
  933. }
  934. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  935. }
  936. else if (!_stricmp(n, "StreamUrl"))
  937. {
  938. lstrcpynA(stream_url, ld, sizeof(stream_url));
  939. DWORD_PTR dw;
  940. if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, IPC_MBOPEN, SMTO_NORMAL, 500, &dw);
  941. }
  942. }
  943. else break;
  944. }
  945. }
  946. }
  947. INT_PTR CALLBACK CGioFile::httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  948. {
  949. CGioFile *_this;
  950. switch (uMsg)
  951. {
  952. case WM_INITDIALOG:
  953. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
  954. _this = (CGioFile *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  955. if (_this->force_lpinfo[0])
  956. SetDlgItemTextA(hwndDlg, IDC_EDIT1, _this->force_lpinfo);
  957. else SetDlgItemTextA(hwndDlg, IDC_EDIT1, _this->lpinfo?_this->lpinfo:"");
  958. SetDlgItemTextA(hwndDlg, IDC_REALM, _this->dlg_realm);
  959. return 1;
  960. case WM_COMMAND:
  961. _this = (CGioFile *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  962. if (LOWORD(wParam) == IDOK)
  963. {
  964. GetDlgItemTextA(hwndDlg, IDC_EDIT1, _this->force_lpinfo, sizeof(_this->force_lpinfo));
  965. EndDialog(hwndDlg, 1);
  966. }
  967. else if (LOWORD(wParam) == IDCANCEL)
  968. {
  969. EndDialog(hwndDlg, 0);
  970. }
  971. break;
  972. }
  973. return 0;
  974. }
  975. class GioFileFiller : public Filler
  976. {
  977. public:
  978. GioFileFiller(CGioFile *_file)
  979. {
  980. ret=NErr_Success;
  981. file=_file;
  982. }
  983. size_t Read(void *dest, size_t len)
  984. {
  985. int bytesRead=0;
  986. ret = file->Read(dest, (int)len, &bytesRead);
  987. return bytesRead;
  988. }
  989. CGioFile *file;
  990. int ret;
  991. };
  992. int CGioFile::Peek(void *pBuffer, int cbToRead, int *pcbRead)
  993. {
  994. GioFileFiller filler(this);
  995. // do we need to fill up?
  996. if (cbToRead > (int)peekBuffer.size())
  997. {
  998. no_peek_hack = true;// benski> HACK ALERT! we have to set this or else Read() will try to use the peek buffer
  999. peekBuffer.fill(&filler, cbToRead - peekBuffer.size());
  1000. no_peek_hack=false;
  1001. }
  1002. *pcbRead = (int)peekBuffer.peek(pBuffer, cbToRead);
  1003. return filler.ret;
  1004. }
  1005. //-------------------------------------------------------------------------*
  1006. // Read
  1007. //-------------------------------------------------------------------------*
  1008. int CGioFile::Read(void *pBuffer, int cbToRead, int *pcbRead)
  1009. {
  1010. TITLELISTTYPE *mylist = TitleLinkedList;
  1011. // these are used for SHOUTCAST2 metadata and artwork since it can provide
  1012. // multi-packet metadata chunks which are out of order or are received in
  1013. // a way which would otherwise cause these to be cleared incorrectly
  1014. static int title_parts = 0, stream_art_parts = 0, stream_art_parts_total_len = 0,
  1015. playing_art_parts = 0, playing_art_parts_total_len = 0;
  1016. static char **title_blocks = 0, **stream_art_blocks = 0, **playing_art_blocks = 0;
  1017. if (mylist != &TitleListTerminator && mod.outMod)
  1018. {
  1019. while (mylist->Next && mylist != &TitleListTerminator)
  1020. {
  1021. TITLELISTTYPE *next = (TITLELISTTYPE *)mylist->Next;
  1022. long now = mod.outMod->GetOutputTime();
  1023. if (mylist->title[0] || mylist->part_len)
  1024. {
  1025. if (!mylist->timer || now >= mylist->timer)
  1026. {
  1027. switch(mylist->style)
  1028. {
  1029. case UVOX_METADATA_STYLE_AOLRADIO:
  1030. {
  1031. EnterCriticalSection(&streamInfoLock);
  1032. free(uvox_3901);
  1033. uvox_3901 = _strdup(mylist->title);
  1034. LeaveCriticalSection(&streamInfoLock);
  1035. if (g_playing_file)
  1036. {
  1037. PostMessage(mod.hMainWindow, WM_USER, (WPARAM) "0x3901", IPC_METADATA_CHANGED);
  1038. PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
  1039. }
  1040. }
  1041. break;
  1042. case UVOX_METADATA_STYLE_SHOUTCAST:
  1043. {
  1044. processMetaData(mylist->title, (int)strlen(mylist->title) + 1);
  1045. }
  1046. break;
  1047. case UVOX_METADATA_STYLE_SHOUTCAST2:
  1048. {
  1049. EnterCriticalSection(&streamInfoLock);
  1050. // so we can recombine multi-packets we'll store things and
  1051. // when all of the packets have been read then we form them
  1052. if(!title_blocks)
  1053. title_blocks = (char **)malloc(sizeof(char*)*(mylist->total_parts));
  1054. title_blocks[mylist->part-1] = _strdup(mylist->title);
  1055. title_parts++;
  1056. // sanity check so we only try to get the metadata if all parts were processed
  1057. if (title_parts == mylist->total_parts)
  1058. {
  1059. free(uvox_3902);
  1060. uvox_3902 = (char *)malloc(16377 * mylist->total_parts);
  1061. uvox_3902[0] = 0;
  1062. title_parts = 0;
  1063. for(int i = 0; i < mylist->total_parts; i++)
  1064. {
  1065. StringCchCatA(uvox_3902, mylist->total_parts * 16384, title_blocks[i]);
  1066. free(title_blocks[i]);
  1067. }
  1068. free(title_blocks);
  1069. title_blocks = 0;
  1070. // attempt to form a title as 'artist - album - title' as sc_serv2 feeds
  1071. // changed for 5.61 to be just 'artist - title' to match v1 and v2 tools
  1072. Ultravox3902 uvox_metadata;
  1073. if (uvox_metadata.Parse(uvox_3902) != API_XML_FAILURE)
  1074. {
  1075. wchar_t stream_title[256] = {0};
  1076. char* fields[] = {"artist", "title"};
  1077. for(int i = 0; i < sizeof(fields)/sizeof(fields[0]); i++)
  1078. {
  1079. wchar_t temp[256] = {0};
  1080. int ret = uvox_metadata.GetExtendedData(fields[i], temp, 256);
  1081. if(ret && temp[0])
  1082. {
  1083. if(stream_title[0]) StringCchCatW(stream_title, 256, L" - ");
  1084. StringCchCatW(stream_title, 256, temp);
  1085. }
  1086. }
  1087. lstrcpynA(g_stream_title, AutoChar(stream_title, CP_UTF8), sizeof(g_stream_title));
  1088. lstrcpynA(last_title_sent, g_stream_title, sizeof(last_title_sent));
  1089. lstrcpynA(stream_current_title, g_stream_title, sizeof(stream_current_title));
  1090. }
  1091. }
  1092. else
  1093. {
  1094. g_stream_title[0] = 0;
  1095. last_title_sent[0] = 0;
  1096. }
  1097. if (sctitle_format)
  1098. {
  1099. StringCchCatA(g_stream_title, 256, *stream_title_save ? *g_stream_title ? " (" : "(" : "");
  1100. StringCchCatA(g_stream_title, 256, stream_title_save);
  1101. StringCchCatA(g_stream_title, 256, *stream_title_save ? ")" : "");
  1102. }
  1103. LeaveCriticalSection(&streamInfoLock);
  1104. if (g_playing_file)
  1105. {
  1106. PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
  1107. }
  1108. }
  1109. break;
  1110. case UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK:
  1111. {
  1112. EnterCriticalSection(&streamInfoLock);
  1113. // so we can recombine multi-packets we'll store things and
  1114. // when all of the packets have been read then we form them
  1115. if(!stream_art_blocks)
  1116. {
  1117. stream_art_parts_total_len = 0;
  1118. stream_art_blocks = (char **)malloc(sizeof(char*)*(mylist->total_parts));
  1119. }
  1120. stream_art_blocks[mylist->part-1] = (char *)malloc(mylist->part_len+1);
  1121. memcpy(stream_art_blocks[mylist->part-1], mylist->title, mylist->part_len);
  1122. stream_art_parts++;
  1123. stream_art_parts_total_len += mylist->part_len;
  1124. // sanity check so we only try to get the metadata if all parts were processed
  1125. if (stream_art_parts == mylist->total_parts)
  1126. {
  1127. free(uvox_artwork.uvox_stream_artwork);
  1128. if (stream_art_parts_total_len <= 0) break;
  1129. uvox_artwork.uvox_stream_artwork = (char *)malloc(stream_art_parts_total_len);
  1130. uvox_artwork.uvox_stream_artwork[0] = 0;
  1131. uvox_artwork.uvox_stream_artwork_len = stream_art_parts_total_len;
  1132. uvox_artwork.uvox_stream_artwork_type = mylist->type;
  1133. stream_art_parts = 0;
  1134. char *art = uvox_artwork.uvox_stream_artwork;
  1135. for(int i = 0; i < mylist->total_parts; i++)
  1136. {
  1137. int size = min(stream_art_parts_total_len, 16371);
  1138. if (size > 0 && size <= 16371)
  1139. {
  1140. memcpy(art, stream_art_blocks[i], size);
  1141. stream_art_parts_total_len -= size;
  1142. art += size;
  1143. }
  1144. free(stream_art_blocks[i]);
  1145. }
  1146. free(stream_art_blocks);
  1147. stream_art_blocks = 0;
  1148. }
  1149. LeaveCriticalSection(&streamInfoLock);
  1150. if (g_playing_file)
  1151. {
  1152. PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
  1153. }
  1154. }
  1155. break;
  1156. case UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK_PLAYING:
  1157. {
  1158. EnterCriticalSection(&streamInfoLock);
  1159. // so we can recombine multi-packets we'll store things and
  1160. // when all of the packets have been read then we form them
  1161. if(!playing_art_blocks)
  1162. {
  1163. playing_art_parts_total_len = 0;
  1164. playing_art_blocks = (char **)malloc(sizeof(char*)*(mylist->total_parts));
  1165. }
  1166. playing_art_blocks[mylist->part-1] = (char *)malloc(mylist->part_len+1);
  1167. memcpy(playing_art_blocks[mylist->part-1], mylist->title, mylist->part_len);
  1168. playing_art_parts++;
  1169. playing_art_parts_total_len += mylist->part_len;
  1170. // sanity check so we only try to get the metadata if all parts were processed
  1171. if (playing_art_parts == mylist->total_parts)
  1172. {
  1173. free(uvox_artwork.uvox_playing_artwork);
  1174. if (playing_art_parts_total_len <= 0) break;
  1175. uvox_artwork.uvox_playing_artwork = (char *)malloc(playing_art_parts_total_len);
  1176. uvox_artwork.uvox_playing_artwork[0] = 0;
  1177. uvox_artwork.uvox_playing_artwork_len = playing_art_parts_total_len;
  1178. uvox_artwork.uvox_playing_artwork_type = mylist->type;
  1179. playing_art_parts = 0;
  1180. char *art = uvox_artwork.uvox_playing_artwork;
  1181. for(int i = 0; i < mylist->total_parts; i++)
  1182. {
  1183. int size = min(playing_art_parts_total_len, 16371);
  1184. if (size > 0 && size <= 16371)
  1185. {
  1186. memcpy(art, playing_art_blocks[i], size);
  1187. playing_art_parts_total_len -= size;
  1188. art += size;
  1189. }
  1190. free(playing_art_blocks[i]);
  1191. }
  1192. free(playing_art_blocks);
  1193. playing_art_blocks = 0;
  1194. }
  1195. LeaveCriticalSection(&streamInfoLock);
  1196. if (g_playing_file)
  1197. {
  1198. PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
  1199. }
  1200. }
  1201. break;
  1202. }
  1203. removeTitleListEntry(mylist);
  1204. }
  1205. }
  1206. mylist = next;
  1207. }
  1208. }
  1209. if (!no_peek_hack && peekBuffer.size())
  1210. {
  1211. *pcbRead = (int)peekBuffer.read(pBuffer, cbToRead);
  1212. return NErr_Success;
  1213. }
  1214. BOOL bSuccess;
  1215. if (m_is_stream)
  1216. {
  1217. if (m_connection)
  1218. {
  1219. char str[4096]={0};
  1220. if (pcbRead) *pcbRead = 0;
  1221. jnl_connection_run(m_connection, -1, -1, 0, 0);
  1222. if (constate == 0)
  1223. {
  1224. if ( jnl_connection_receive_lines_available( m_connection ) > 0 )
  1225. {
  1226. char *p = str;
  1227. jnl_connection_receive_line( m_connection, str, 4096 );
  1228. // check http version and type of data, partial or full
  1229. if ( strlen( str ) >= 13 && !_strnicmp( str, "HTTP/1.1", 8 ) )
  1230. {
  1231. char *p = str + 8; while ( p && *p == ' ' ) p++;
  1232. m_http_response = ( p ? atoi( p ) : 0 );
  1233. if ( m_http_response == 200 )
  1234. m_seek_reset = true;
  1235. }
  1236. EnterCriticalSection( &g_lfnscs );
  1237. lstrcpynA( lastfn_status, str, 256 );
  1238. LeaveCriticalSection( &g_lfnscs );
  1239. PostMessage( mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE );
  1240. while ( p && *p && *p != ' ' ) p++;
  1241. if ( p && *p ) p++;
  1242. if ( p[ 0 ] == '2' ) constate = 1;
  1243. else if ( strstr( p, "301" ) == p || strstr( p, "302" ) == p ||
  1244. strstr( p, "303" ) == p || strstr( p, "307" ) == p )
  1245. {
  1246. constate = 69;
  1247. }
  1248. else if ( strstr( p, "401" ) == p && m_auth_tries++ < 3 )
  1249. {
  1250. constate = 75;
  1251. }
  1252. else if ( strstr( p, "403" ) == p )
  1253. {
  1254. EnterCriticalSection( &g_lfnscs );
  1255. lstrcpynA( lastfn_status, "access denied", 256 );
  1256. lastfn_status_err = 1;
  1257. LeaveCriticalSection( &g_lfnscs );
  1258. jnl_connection_close( m_connection, 1 );
  1259. }
  1260. else if ( strstr( p, "503" ) == p )
  1261. {
  1262. EnterCriticalSection( &g_lfnscs );
  1263. lstrcpynA( lastfn_status, "server full", 256 );
  1264. lastfn_status_err = 1;
  1265. LeaveCriticalSection( &g_lfnscs );
  1266. jnl_connection_close( m_connection, 1 );
  1267. }
  1268. else
  1269. {
  1270. lastfn_status_err = 1;
  1271. jnl_connection_close( m_connection, 1 );
  1272. }
  1273. }
  1274. else if ( jnl_connection_get_state( m_connection ) == JNL_CONNECTION_STATE_CLOSED || jnl_connection_get_state( m_connection ) == JNL_CONNECTION_STATE_ERROR || jnl_connection_get_state( m_connection ) == JNL_CONNECTION_STATE_NOCONNECTION )
  1275. {
  1276. const char *t = jnl_connection_get_error( m_connection );
  1277. if ( t && *t )
  1278. {
  1279. EnterCriticalSection( &g_lfnscs );
  1280. lstrcpynA( lastfn_status, t, 256 );
  1281. lastfn_status_err = 1;
  1282. LeaveCriticalSection( &g_lfnscs );
  1283. }
  1284. PostMessage( mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE );
  1285. }
  1286. }
  1287. if (constate == 75) // authorization required
  1288. {
  1289. while (jnl_connection_receive_lines_available(m_connection) > 0)
  1290. {
  1291. char *wwwa = "WWW-Authenticate:";
  1292. jnl_connection_receive_line(m_connection, str, 4096);
  1293. if (!str[0])
  1294. {
  1295. lastfn_status_err = 1; jnl_connection_close(m_connection, 1); break;
  1296. }
  1297. if (!_strnicmp(str, wwwa, strlen(wwwa)))
  1298. {
  1299. int has = 0;
  1300. char *s2 = "Basic realm=\"";
  1301. char *p = str + strlen(wwwa); while (p && *p == ' ') p++;
  1302. if (!_strnicmp(p, s2, strlen(s2)))
  1303. {
  1304. p += strlen(s2);
  1305. if (strstr(p, "\""))
  1306. {
  1307. if (p && *p)
  1308. {
  1309. strstr(p, "\"")[0] = 0;
  1310. extern char *get_inifile();
  1311. if (!force_lpinfo[0]) GetPrivateProfileStringA("HTTP-AUTH", p, "", force_lpinfo, sizeof(force_lpinfo), get_inifile());
  1312. if (!force_lpinfo[0] || (lpinfo && lpinfo[0]))
  1313. {
  1314. lstrcpynA(dlg_realm, p, sizeof(dlg_realm));
  1315. if (!WASABI_API_DIALOGBOXPARAM(IDD_HTTPAUTH, GetDialogBoxParent(), httpDlgProc, (LPARAM)this))
  1316. {
  1317. force_lpinfo[0] = 0;
  1318. }
  1319. else
  1320. {
  1321. WritePrivateProfileStringA("HTTP-AUTH", p, force_lpinfo, get_inifile());
  1322. }
  1323. }
  1324. if (force_lpinfo[0])
  1325. {
  1326. jnl_connection_release(m_connection);
  1327. m_connection = NULL;
  1328. doConnect(NULL, 0);
  1329. has = 1;
  1330. }
  1331. }
  1332. }
  1333. }
  1334. if (!has)
  1335. {
  1336. lastfn_status_err = 1;
  1337. jnl_connection_close(m_connection, 1);
  1338. }
  1339. break;
  1340. }
  1341. }
  1342. }
  1343. if (constate == 69) // redirect city
  1344. {
  1345. while (jnl_connection_receive_lines_available(m_connection) > 0)
  1346. {
  1347. jnl_connection_receive_line(m_connection, str, 4096);
  1348. if (!str[0])
  1349. {
  1350. jnl_connection_close(m_connection, 1); break;
  1351. }
  1352. if (!_strnicmp(str, "Location:", 9))
  1353. {
  1354. char *p = str + 9; while (p && *p == ' ') p++;
  1355. if (p && *p)
  1356. {
  1357. if (m_redircnt++ < MAX_REDIRECTS)
  1358. {
  1359. jnl_connection_release(m_connection);
  1360. m_connection = NULL;
  1361. doConnect(p, 0);
  1362. }
  1363. else
  1364. {
  1365. EnterCriticalSection(&g_lfnscs);
  1366. WASABI_API_LNGSTRING_BUF(IDS_REDIRECT_LIMIT_EXCEEDED,lastfn_status,256);
  1367. lastfn_status_err = 1;
  1368. LeaveCriticalSection(&g_lfnscs);
  1369. jnl_connection_close(m_connection, 1);
  1370. }
  1371. break;
  1372. }
  1373. }
  1374. }
  1375. }
  1376. if (constate == 1)
  1377. {
  1378. while (jnl_connection_receive_lines_available(m_connection) > 0)
  1379. {
  1380. jnl_connection_receive_line(m_connection, str, 4096);
  1381. if (!str[0])
  1382. {
  1383. if (config_http_save_dir[0] && (config_miscopts&16))
  1384. {
  1385. if (!save_filename[0] && m_is_stream == 1 &&
  1386. strlen(stream_title_save) > 4 &&
  1387. !strstr(stream_title_save, "..") &&
  1388. !strstr(stream_title_save, "\\") &&
  1389. !strstr(stream_title_save, "/"))
  1390. {
  1391. lstrcpynA(save_filename, stream_title_save, 251);
  1392. char *p = strstr(save_filename, ".mp");
  1393. if (!p) p = strstr(save_filename, ".MP");
  1394. if (!p) p = strstr(save_filename, ".mP");
  1395. if (!p) p = strstr(save_filename, ".Mp");
  1396. if (!p)
  1397. {
  1398. StringCchCatA(save_filename, 256, ".mp3");
  1399. }
  1400. else
  1401. {
  1402. while (p && *p && *p != ' ') p++;
  1403. if (p) *p = 0;
  1404. }
  1405. }
  1406. if (save_filename[0])
  1407. {
  1408. char buf[4096] = {0};
  1409. StringCchPrintfA(buf, 4096, "%s%s%s", config_http_save_dir, config_http_save_dir[strlen(config_http_save_dir) - 1] == '\\' ? "" : "\\", save_filename);
  1410. hFile = CreateFileA(buf, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1411. }
  1412. }
  1413. else save_filename[0] = 0;
  1414. constate = meta_interval ? 4 : 2;
  1415. break;
  1416. }
  1417. // check if stream is seekable
  1418. if (strlen(str) >= 14 && !_strnicmp(str, "Accept-Ranges:", 14))
  1419. {
  1420. m_is_stream_seekable = true;
  1421. }
  1422. if (!_strnicmp(str, "Content-Length:", 15))
  1423. {
  1424. char *p = str + 15; while (p && *p == ' ') p++;
  1425. if (!is_stream_seek)
  1426. mpeg_length = atoi(p);
  1427. m_is_stream_seekable = true;
  1428. }
  1429. if (!_strnicmp(str, "content-type:", 13))
  1430. {
  1431. char *p = str + 13; while (p && *p == ' ') p++;
  1432. free(m_content_type);
  1433. m_content_type = _strdup(p);
  1434. if (!_strnicmp(m_content_type, "misc/ultravox",13))
  1435. {
  1436. stream_title_save[0] = 0;
  1437. stream_name[0]=0;
  1438. g_stream_title[0] = 0;
  1439. is_uvox = 1;
  1440. // TODO get this to id as SC2 stream if possible...
  1441. m_is_stream = 3;
  1442. }
  1443. }
  1444. if (!_strnicmp(str, "Server:", 7))
  1445. {
  1446. char *p = str + 7; while (p && *p == ' ') p++;
  1447. lstrcpynA(server_name, p, sizeof(server_name));
  1448. }
  1449. if (!_strnicmp(str, "ultravox-max-msg:", 17))
  1450. {
  1451. char *p = str + 17; while (p && *p == ' ') p++;
  1452. uvox_maxmsg = (p ? atoi(p) : 0);
  1453. if (uvox_maxmsg > UVOX_MAXMSG_CAP) // benski> security vulnerability fix, too high of value was causing an integer overflow (because we malloc uvox_maxmsg*2
  1454. uvox_maxmsg = UVOX_MAXMSG_CAP;
  1455. m_is_stream = 3;
  1456. }
  1457. else if (!_strnicmp(str, "Ultravox-SID:", 13))
  1458. {
  1459. char *p = str + 13; while (p && *p == ' ') p++;
  1460. uvox_sid = (p ? atoi(p) : 0);
  1461. m_is_stream = 3;
  1462. }
  1463. if (!_strnicmp(str, "Ultravox-Avg-Bitrate:", 21))
  1464. {
  1465. char *p = str + 21; while (p && *p == ' ') p++;
  1466. uvox_avgbr = (p ? atoi(p) : 0);
  1467. m_is_stream = 3;
  1468. }
  1469. if (!_strnicmp(str, "Ultravox-Max-Bitrate:", 21))
  1470. {
  1471. char *p = str + 21; while (p && *p == ' ') p++;
  1472. uvox_maxbr = (p ? atoi(p) : 0);
  1473. m_is_stream = 3;
  1474. }
  1475. if (!_strnicmp(str, "Ultravox-Bitrate:", 17))
  1476. {
  1477. char *p = str + 17; while (p && *p == ' ') p++;
  1478. uvox_avgbr = uvox_maxbr = (p ? atoi(p) : 0);
  1479. m_is_stream = 3;
  1480. }
  1481. if (!_strnicmp(str, "Ultravox-Title:", 15))
  1482. {
  1483. char *p = str + 15; while (p && *p == ' ') p++;
  1484. lstrcpynA(stream_title_save, p, 580);
  1485. m_is_stream = 3;
  1486. }
  1487. if (!_strnicmp(str, "Ultravox-Genre:", 15))
  1488. {
  1489. char *p = str + 15; while (p && *p == ' ') p++;
  1490. lstrcpynA(stream_genre, p, sizeof(stream_genre));
  1491. m_is_stream = 3;
  1492. }
  1493. if (!_strnicmp(str, "Ultravox-URL:", 13)/* && !strstr(str, "shoutcast.com")*/)
  1494. {
  1495. char *p = str + 13; while (p && *p == ' ') p++;
  1496. lstrcpynA(stream_url, p, sizeof(stream_url));
  1497. DWORD_PTR dw = 0;
  1498. if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, IPC_MBOPEN, SMTO_NORMAL, 500, &dw);
  1499. m_is_stream = 3;
  1500. }
  1501. if (!_strnicmp(str, "Ultravox-Class-Type:", 19))
  1502. {
  1503. // id our stream for 'streamtype'
  1504. // added for 5.63 as is a better way to check for
  1505. // a SC2/UVOX2.1 stream when no metadata is sent
  1506. m_is_stream = 5;
  1507. }
  1508. if (!_strnicmp(str, "icy-notice2:", 12))
  1509. {
  1510. char *p = str + 12; while (p && *p == ' ') p++;
  1511. char *p2 = (p ? strstr(p, "<BR>") : 0);
  1512. if (p2)
  1513. {
  1514. *p2 = 0;
  1515. lstrcpynA(server_name, p, sizeof(server_name));
  1516. }
  1517. m_is_stream=2;
  1518. }
  1519. if (!_strnicmp(str, "content-disposition:", 20))
  1520. {
  1521. if (strstr(str, "filename="))
  1522. lstrcpynA(g_stream_title, strstr(str, "filename=") + 9, sizeof(g_stream_title));
  1523. lstrcpynA(stream_title_save, g_stream_title, 580);
  1524. }
  1525. if (!_strnicmp(str, "icy-name:", 9))
  1526. {
  1527. char *p = str + 9; while (p && *p == ' ') p++;
  1528. lstrcpynA(g_stream_title, p, sizeof(g_stream_title));
  1529. lstrcpynA(stream_title_save, g_stream_title, 580);
  1530. lstrcpynA(stream_name, g_stream_title, 256);
  1531. // m_is_stream = 2; // benski> cut: some things use icy-name as a hack to show a title - not a reliable indicator of a SHOUTcast stream
  1532. }
  1533. if (!_strnicmp(str, "icy-metaint:", 12))
  1534. {
  1535. char *p = str + 12; while (p && *p == ' ') p++;
  1536. meta_interval = (p ? atoi(p) : 0);
  1537. m_is_stream = 2;
  1538. }
  1539. if (!_strnicmp(str, "icy-genre:", 10))
  1540. {
  1541. char *p = str + 10; while (p && *p == ' ') p++;
  1542. lstrcpynA(stream_genre, p, sizeof(stream_genre));
  1543. m_is_stream = 2;
  1544. }
  1545. if (!_strnicmp(str, "icy-url:", 8) && !strstr(str, "shoutcast.com"))
  1546. {
  1547. char *p = str + 8; while (p && *p == ' ') p++;
  1548. lstrcpynA(stream_url, p, sizeof(stream_url));
  1549. //if (!strncmp(stream_url,"hTtP",4))
  1550. //{
  1551. // DWORD dw;
  1552. // SendMessageTimeout(mod.hMainWindow,WM_USER,(WPARAM)0,241,SMTO_NORMAL,500,&dw);
  1553. //} // Removed by Tag, Annoying.
  1554. DWORD_PTR dw = 0;
  1555. if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, IPC_MBOPEN, SMTO_NORMAL, 500, &dw);
  1556. m_is_stream = 2;
  1557. }
  1558. }
  1559. }
  1560. if (constate == 2) // check for id3v2
  1561. {
  1562. if (jnl_connection_receive_bytes_available(m_connection) >= 10)
  1563. {
  1564. char buf[10]={0};
  1565. constate = 4;
  1566. jnl_connection_peek(m_connection, buf, 10);
  1567. if (buf[0] == 'I'
  1568. && buf[1] == 'D'
  1569. && buf[2] == '3'
  1570. && buf[3] != 255
  1571. && buf[4] != 255
  1572. && buf[6] < 0x80
  1573. && buf[7] < 0x80
  1574. && buf[8] < 0x80
  1575. && buf[9] < 0x80)
  1576. {
  1577. jnl_connection_receive(m_connection, buf, 10);
  1578. m_id3v2_len = 10;
  1579. if (buf[5] & 0x10) // check for footer flag
  1580. m_id3v2_len += 10;
  1581. m_id3v2_len += ((int)buf[6]) << 21;
  1582. m_id3v2_len += ((int)buf[7]) << 14;
  1583. m_id3v2_len += ((int)buf[8]) << 7;
  1584. m_id3v2_len += ((int)buf[9]);
  1585. if (m_id3v2_len < 0) m_id3v2_len = 0;
  1586. if (mpeg_length && m_id3v2_len > mpeg_length)
  1587. {
  1588. m_id3v2_len = 0;
  1589. }
  1590. if (m_id3v2_len)
  1591. {
  1592. constate = 3;
  1593. stream_id3v2_read = 0;
  1594. if (m_id3v2_len < 16*1024*1024)
  1595. {
  1596. stream_id3v2_buf = (char*)malloc(10 + m_id3v2_len);
  1597. stream_id3v2_read = 10;
  1598. memcpy(stream_id3v2_buf, buf, 10);
  1599. }
  1600. EnterCriticalSection(&g_lfnscs);
  1601. WASABI_API_LNGSTRING_BUF(IDS_READING_ID3,lastfn_status,256);
  1602. LeaveCriticalSection(&g_lfnscs);
  1603. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  1604. }
  1605. }
  1606. }
  1607. }
  1608. if (constate == 3) // id3v2 found
  1609. {
  1610. while ((int)stream_id3v2_read < m_id3v2_len)
  1611. {
  1612. char buf[1024]={0};
  1613. int btoread = m_id3v2_len - stream_id3v2_read;
  1614. if (btoread > sizeof(buf)) btoread = sizeof(buf);
  1615. int avail = (int)jnl_connection_receive_bytes_available(m_connection);
  1616. if (btoread > avail) btoread = avail;
  1617. if (!btoread) break;
  1618. if (stream_id3v2_buf)
  1619. stream_id3v2_read += (uint32_t)jnl_connection_receive(m_connection, stream_id3v2_buf + stream_id3v2_read, btoread);
  1620. else
  1621. stream_id3v2_read += (uint32_t)jnl_connection_receive(m_connection, buf, btoread);
  1622. //stream_id3v2_read+=m_connection->ReceiveBytes(0,btoread);
  1623. }
  1624. if ((int)stream_id3v2_read >= m_id3v2_len)
  1625. {
  1626. if (stream_id3v2_buf)
  1627. {
  1628. if (m_is_stream_seekable /*m_is_stream != 2*/) /* don't want to do id3v2 on an internet stream */
  1629. {
  1630. EnterCriticalSection(&streamInfoLock);
  1631. info.Decode(stream_id3v2_buf, stream_id3v2_read);
  1632. // TODO: streamInfo = info;
  1633. LeaveCriticalSection(&streamInfoLock);
  1634. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  1635. }
  1636. }
  1637. constate = 4;
  1638. }
  1639. }
  1640. if (constate == 4) // check for xing header
  1641. {
  1642. if (GetContentLength() < 1 || is_stream_seek) constate = 5;
  1643. else
  1644. {
  1645. int avail = (int)jnl_connection_receive_bytes_available(m_connection);
  1646. if (avail > 4096 || jnl_connection_get_state(m_connection) == JNL_CONNECTION_STATE_CLOSED)
  1647. {
  1648. char buf[4096]={0};
  1649. jnl_connection_peek(m_connection, buf, sizeof(buf));
  1650. constate++;
  1651. {
  1652. delete m_vbr_hdr;
  1653. m_vbr_hdr = 0;
  1654. LAMEinfo lame;
  1655. lame.toc = m_vbr_toc;
  1656. m_vbr_frame_len = ReadLAMEinfo((unsigned char *)buf, &lame);
  1657. if (m_vbr_frame_len)
  1658. {
  1659. prepad = lame.encoderDelay;
  1660. postpad = lame.padding;
  1661. if (lame.flags&TOC_FLAG)
  1662. {
  1663. int x;
  1664. for (x = 0; x < 100; x++)
  1665. if (m_vbr_toc[x]) break;
  1666. if (x != 100)
  1667. m_vbr_flag = 1;
  1668. }
  1669. if (lame.flags&FRAMES_FLAG)
  1670. {
  1671. m_vbr_frames = lame.frames;
  1672. m_vbr_samples = Int32x32To64(lame.frames, lame.h_id ? 1152 : 576);
  1673. m_vbr_samples -= (prepad + postpad);
  1674. m_vbr_ms = MulDiv((int)m_vbr_samples, 1000, lame.samprate);
  1675. }
  1676. if (!m_vbr_frames) m_vbr_flag = 0;
  1677. jnl_connection_receive(m_connection, buf, m_vbr_frame_len);
  1678. }
  1679. else
  1680. {
  1681. m_vbr_hdr = new CVbriHeader;
  1682. m_vbr_frame_len = m_vbr_hdr->readVbriHeader((unsigned char *)buf);
  1683. if (m_vbr_frame_len)
  1684. {
  1685. m_vbr_bytes = m_vbr_hdr->getBytes();
  1686. m_vbr_frames = m_vbr_hdr->getNumFrames();
  1687. m_vbr_ms = m_vbr_hdr->getNumMS();
  1688. }
  1689. else
  1690. {
  1691. delete m_vbr_hdr;
  1692. m_vbr_hdr = 0;
  1693. }
  1694. }
  1695. }
  1696. // TODO OFL
  1697. }
  1698. }
  1699. }
  1700. if (constate == 5) // time to stream
  1701. {
  1702. while (1)
  1703. {
  1704. // Process any timed titles
  1705. int len = (int)jnl_connection_receive_bytes_available(m_connection);
  1706. if (meta_interval && meta_pos >= meta_interval)
  1707. {
  1708. unsigned char b;
  1709. if (len > 0 && jnl_connection_peek(m_connection, (char*)&b, 1) && len > (b << 4))
  1710. {
  1711. char metabuf[4096]={0};
  1712. jnl_connection_receive(m_connection, metabuf, 1);
  1713. jnl_connection_receive(m_connection, metabuf, b << 4);
  1714. processMetaData(metabuf, b << 4);
  1715. stream_metabytes_read += (b << 4) + 1;
  1716. meta_pos = 0;
  1717. }
  1718. else break;
  1719. }
  1720. else if (is_uvox)
  1721. {
  1722. if (!uvox_stream_data)
  1723. {
  1724. /* benski> this was a security vulnerability.
  1725. don't blindly multiply by 2 and pass to malloc
  1726. if uvox_maxmsg happens to be 2^31, multiplying by 2 turns it into 0!
  1727. CUT!!! uvox_stream_data = (unsigned char*)malloc(uvox_maxmsg * 2 + 4096);
  1728. */
  1729. uvox_stream_data = (unsigned char*)malloc(SAFE_MALLOC_MATH(uvox_maxmsg * 2 + 4096, uvox_maxmsg));
  1730. }
  1731. if (uvox_stream_data_len < 1)
  1732. {
  1733. again:
  1734. if (len < 6) break;
  1735. jnl_connection_peek(m_connection, (char*)uvox_stream_data, 6);
  1736. int uvox_qos = uvox_stream_data[1];
  1737. int classtype = (uvox_stream_data[2] << 8) | uvox_stream_data[3];
  1738. int uvox_len = (uvox_stream_data[4] << 8) | uvox_stream_data[5];
  1739. int uvox_class = (classtype >> 12) & 0xF;
  1740. int uvox_type = classtype & 0xFFF;
  1741. if (uvox_stream_data[0] != 0x5A || uvox_len > uvox_maxmsg)
  1742. {
  1743. jnl_connection_receive(m_connection, NULL, 1);
  1744. len--;
  1745. uvox_desyncs++;
  1746. goto again;
  1747. }
  1748. if (uvox_len + 7 > len) break;
  1749. // process uvox chunk
  1750. jnl_connection_peek(m_connection, (char*)uvox_stream_data, 6 + uvox_len + 1);
  1751. if (uvox_stream_data[6 + uvox_len])
  1752. {
  1753. jnl_connection_receive(m_connection, NULL, 1);
  1754. uvox_desyncs++;
  1755. len--;
  1756. goto again;
  1757. }
  1758. else if (uvox_class == 0x2 && uvox_type == 0x003)
  1759. {
  1760. // failover gayness
  1761. }
  1762. else if (uvox_class == 0x2 && uvox_type == 0x002)
  1763. {
  1764. EnterCriticalSection(&g_lfnscs);
  1765. WASABI_API_LNGSTRING_BUF(IDS_STREAM_TERMINATED,lastfn_status,256);
  1766. LeaveCriticalSection(&g_lfnscs);
  1767. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  1768. jnl_connection_close(m_connection, 0);
  1769. }
  1770. else if (uvox_class == 0x2 && uvox_type == 0x001)
  1771. {
  1772. EnterCriticalSection(&g_lfnscs);
  1773. WASABI_API_LNGSTRING_BUF(IDS_STREAM_TEMPORARILY_INTERRUPTED,lastfn_status,256);
  1774. LeaveCriticalSection(&g_lfnscs);
  1775. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  1776. }
  1777. else if (uvox_class == 0x3 && (uvox_type == 0x902 || uvox_type == 0x901)) // SHOUTcast 2 metadata
  1778. {
  1779. // id our stream for 'streamtype'
  1780. m_is_stream = 5;
  1781. // this will allow us to cope with multi-packet metadata messages
  1782. // (used to be needed when the old SC2 spec used an APIC tag to
  1783. // to send the artwork in the metadata message - now it's sent in
  1784. // in the uvox_class == 0x4 messages for stream and playing cases)
  1785. if (!uvox_stream_data[8])
  1786. {
  1787. char *mbuf = (char*)uvox_stream_data + 12;
  1788. if (mbuf)
  1789. {
  1790. unsigned long delay = 0;
  1791. if (uvox_avgbr)
  1792. {
  1793. long byterate = (uvox_avgbr / 8);
  1794. long bytes = 1024 * 11;
  1795. float localdelay = (float)bytes / (float)byterate;
  1796. delay = (long)localdelay * 1000;
  1797. }
  1798. // make sure that we've got a packet which is within the specs
  1799. // as id can only be 1-32, total parts can only be 1-32,
  1800. // id cannot be more than total parts and if not then skip it.
  1801. if(uvox_stream_data[11] < 1 || uvox_stream_data[11] > 32 ||
  1802. uvox_stream_data[11] > uvox_stream_data[9] ||
  1803. uvox_stream_data[9] < 1 || uvox_stream_data[9] > 32)
  1804. {
  1805. break;
  1806. }
  1807. TITLELISTTYPE *newtitle = newTitleListEntry();
  1808. newtitle->style = (uvox_type == 0x902 ? UVOX_METADATA_STYLE_SHOUTCAST2 : UVOX_METADATA_STYLE_AOLRADIO);
  1809. // we make sure to only copy up to the maximum metadata payload size
  1810. newtitle->part_len = min((uvox_len - 6), 16371);
  1811. memcpy(newtitle->title, mbuf, newtitle->part_len);
  1812. newtitle->part = uvox_stream_data[11];
  1813. newtitle->total_parts = uvox_stream_data[9];
  1814. newtitle->timer = (stream_bytes_read && mod.outMod ? delay + mod.outMod->GetOutputTime() : 0);
  1815. }
  1816. }
  1817. }
  1818. else if (uvox_class == 0x4) // SHOUTcast 2 albumart
  1819. {
  1820. if (allow_scartwork && !uvox_stream_data[8])
  1821. {
  1822. char *mbuf = (char*)uvox_stream_data + 12;
  1823. if (mbuf)
  1824. {
  1825. // [0x4] [0|1] [00|01|02|03]
  1826. unsigned long delay = 0;
  1827. if (uvox_avgbr)
  1828. {
  1829. long byterate = (uvox_avgbr / 8);
  1830. long bytes = 1024 * 11;
  1831. float localdelay = (float)bytes / (float)byterate;
  1832. delay = (long)localdelay * 1000;
  1833. }
  1834. // make sure that we've got a packet which is within the specs
  1835. // as id can only be 1-32, total parts can only be 1-32,
  1836. // id cannot be more than total parts and if not then skip it.
  1837. if(uvox_stream_data[11] < 1 || uvox_stream_data[11] > 32 ||
  1838. uvox_stream_data[11] > uvox_stream_data[9] ||
  1839. uvox_stream_data[9] < 1 || uvox_stream_data[9] > 32)
  1840. {
  1841. break;
  1842. }
  1843. TITLELISTTYPE *newtitle = newTitleListEntry();
  1844. newtitle->style = (uvox_type & 0x100 ? UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK_PLAYING : UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK);
  1845. // we make sure to only copy up to the maximum metadata payload size
  1846. newtitle->part_len = min((uvox_len - 6), 16371);
  1847. memcpy(newtitle->title, mbuf, newtitle->part_len);
  1848. newtitle->part = uvox_stream_data[11];
  1849. newtitle->total_parts = uvox_stream_data[9];
  1850. newtitle->type = (uvox_type & 0x00FF);
  1851. newtitle->timer = (stream_bytes_read && mod.outMod ? delay + mod.outMod->GetOutputTime() : 0);
  1852. }
  1853. }
  1854. }
  1855. else if (uvox_class == 0x3 && (uvox_type == 0x001 || uvox_type == 0x002))
  1856. {
  1857. int w = uvox_type - 1; // should be ID?
  1858. int n = (uvox_stream_data[8] << 8) | uvox_stream_data[9];
  1859. if (n && n < 33)
  1860. {
  1861. int t = (uvox_stream_data[10] << 8) | uvox_stream_data[11];
  1862. if (t && t <= n)
  1863. {
  1864. int l = 0;
  1865. int a;
  1866. char *p = (char*)uvox_stream_data + 12; // this almost works
  1867. free(uvox_meta[w][t - 1]);
  1868. uvox_meta[w][t - 1] = _strdup(p);
  1869. for (a = 0;a < n;a++)
  1870. {
  1871. if (!uvox_meta[w][a]) break;
  1872. l += (int)strlen(uvox_meta[w][a]);
  1873. }
  1874. if (a == n)
  1875. {
  1876. char *outtext = (char*)malloc(l + 1);
  1877. p = outtext;
  1878. for (a = 0;a < n;a++)
  1879. {
  1880. lstrcpynA(p, uvox_meta[w][a], l + 1);
  1881. free(uvox_meta[w][a]);
  1882. uvox_meta[w][a] = 0;
  1883. p += strlen(p);
  1884. }
  1885. processMetaData(outtext, l + 1);
  1886. free(outtext);
  1887. }
  1888. }
  1889. }
  1890. }
  1891. else if ((uvox_class == 0x7 && (uvox_type == 0x0 || uvox_type == 0x1))
  1892. || (uvox_class == 0x8 && (uvox_type == 0x0 || uvox_type == 0x1 || uvox_type == 0x3)))
  1893. {
  1894. memcpy(uvox_stream_data, uvox_stream_data + 6, uvox_len);
  1895. uvox_stream_data_len = uvox_len;
  1896. uvox_last_message = uvox_class << 12 | uvox_type;
  1897. }
  1898. jnl_connection_receive(m_connection, NULL, 6 + uvox_len + 1);
  1899. uvox_message_cnt++;
  1900. }
  1901. if (uvox_stream_data_len > 0)
  1902. {
  1903. len = min(cbToRead, uvox_stream_data_len);
  1904. memcpy(pBuffer, uvox_stream_data, len);
  1905. if (pcbRead) *pcbRead = len;
  1906. stream_bytes_read += len;
  1907. if (len < uvox_stream_data_len)
  1908. {
  1909. memcpy(uvox_stream_data, uvox_stream_data + len, uvox_stream_data_len - len);
  1910. }
  1911. uvox_stream_data_len -= len;
  1912. break;
  1913. }
  1914. }
  1915. else
  1916. {
  1917. len = min(cbToRead, len);
  1918. if (meta_interval) len = min(meta_interval - meta_pos, len);
  1919. if (len > 0)
  1920. {
  1921. DWORD dw = 0;
  1922. len = (int)jnl_connection_receive(m_connection, (char*)pBuffer, len);
  1923. if (hFile != INVALID_HANDLE_VALUE) WriteFile(hFile, pBuffer, len, &dw, NULL);
  1924. if (pcbRead) *pcbRead = len;
  1925. meta_pos += len;
  1926. stream_bytes_read += len;
  1927. }
  1928. else if (pcbRead) *pcbRead = 0;
  1929. break;
  1930. }
  1931. }
  1932. }
  1933. int state = m_connection ? jnl_connection_get_state(m_connection) : JNL_CONNECTION_STATE_CLOSED;
  1934. if (state == JNL_CONNECTION_STATE_ERROR || state == JNL_CONNECTION_STATE_CLOSED)
  1935. {
  1936. if ((!pcbRead || !*pcbRead) && (!m_connection || jnl_connection_receive_bytes_available(m_connection) < 1))
  1937. {
  1938. fEof = 1;
  1939. return NErr_Error;
  1940. }
  1941. }
  1942. else if (constate != 5 && constate != 4 && constate != 3 && timeout_start + 15000 < GetTickCount()) // 15 second net connect timeout
  1943. {
  1944. EnterCriticalSection(&g_lfnscs);
  1945. WASABI_API_LNGSTRING_BUF(IDS_TIMED_OUT,lastfn_status,256);
  1946. lastfn_status_err = 1;
  1947. LeaveCriticalSection(&g_lfnscs);
  1948. PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
  1949. fEof = 1;
  1950. return NErr_Error;
  1951. }
  1952. return NErr_Success;
  1953. }
  1954. return NErr_Error;
  1955. }
  1956. else if (m_full_buffer)
  1957. {
  1958. int len = cbToRead;
  1959. if ((uint64_t)len > (mpeg_length - m_full_buffer_pos))
  1960. {
  1961. len = (int)(mpeg_length - m_full_buffer_pos);
  1962. }
  1963. if (pcbRead) *pcbRead = len;
  1964. if (len)
  1965. {
  1966. memcpy(pBuffer, m_full_buffer + m_full_buffer_pos, len);
  1967. m_full_buffer_pos += len;
  1968. }
  1969. else
  1970. {
  1971. fEof = true;
  1972. return NErr_EndOfFile;
  1973. }
  1974. return NErr_Success;
  1975. }
  1976. else
  1977. {
  1978. if (hFile != INVALID_HANDLE_VALUE)
  1979. {
  1980. if ((uint64_t)cbToRead >= (mpeg_length - file_position))
  1981. {
  1982. cbToRead = (int)(mpeg_length - file_position);
  1983. fEof = true;
  1984. }
  1985. if (cbToRead == 0)
  1986. {
  1987. if (pcbRead)
  1988. *pcbRead = 0;
  1989. return NErr_Success;
  1990. }
  1991. DWORD dwRead = 0;
  1992. bSuccess = ReadFile(hFile, pBuffer, cbToRead, &dwRead, NULL);
  1993. if (bSuccess)
  1994. {
  1995. file_position += dwRead;
  1996. // update pcbRead
  1997. if (pcbRead)
  1998. *pcbRead = dwRead;
  1999. // check for EOF
  2000. if (dwRead == 0)
  2001. fEof = true;
  2002. return NErr_Success;
  2003. }
  2004. else
  2005. {
  2006. // error reading from file
  2007. return NErr_Error;
  2008. }
  2009. }
  2010. else
  2011. {
  2012. // no valid file handle
  2013. return NErr_Error;
  2014. }
  2015. }
  2016. }
  2017. //-------------------------------------------------------------------------*
  2018. // IsEof
  2019. //-------------------------------------------------------------------------*
  2020. bool CGioFile::IsEof() const
  2021. {
  2022. return fEof;
  2023. }
  2024. //-------------------------------------------------------------------------*
  2025. // GetContentLength
  2026. //-------------------------------------------------------------------------*
  2027. DWORD CGioFile::GetContentLength(void) const
  2028. {
  2029. DWORD dwSize = 0 ;
  2030. dwSize = (DWORD)mpeg_length;
  2031. return dwSize ;
  2032. }
  2033. //-------------------------------------------------------------------------*
  2034. // GetCurrentPosition
  2035. //-------------------------------------------------------------------------*
  2036. DWORD CGioFile::GetCurrentPosition(void) const
  2037. {
  2038. DWORD dwPos = 0;
  2039. if (m_is_stream)
  2040. {
  2041. dwPos = (DWORD)stream_bytes_read;
  2042. }
  2043. else if (m_full_buffer)
  2044. {
  2045. dwPos = (DWORD)m_full_buffer_pos;
  2046. }
  2047. else if (hFile != INVALID_HANDLE_VALUE)
  2048. {
  2049. dwPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  2050. dwPos -= (DWORD)(mpeg_position + peekBuffer.size());
  2051. }
  2052. return dwPos ;
  2053. }
  2054. //-------------------------------------------------------------------------*
  2055. // SetCurrentPosition
  2056. //-------------------------------------------------------------------------*
  2057. void CGioFile::SetCurrentPosition(long dwPos, int How) // GIO_FILE_BEGIN only
  2058. {
  2059. fEof = false;
  2060. if (m_full_buffer)
  2061. {
  2062. m_full_buffer_pos = dwPos;
  2063. if (m_full_buffer_pos < 0) m_full_buffer_pos = 0;
  2064. if (m_full_buffer_pos > mpeg_length) m_full_buffer_pos = mpeg_length;
  2065. }
  2066. else if (hFile != INVALID_HANDLE_VALUE)
  2067. {
  2068. Seek64(hFile, mpeg_position + dwPos, FILE_BEGIN);
  2069. file_position = dwPos;
  2070. peekBuffer.clear();
  2071. }
  2072. }
  2073. int CGioFile::GetHeaderOffset()
  2074. {
  2075. return (int)mpeg_position;
  2076. }
  2077. /*-------------------------------------------------------------------------*/
  2078. void CGioFile::Seek(int posms, int br)
  2079. {
  2080. int offs = 0;
  2081. if (m_vbr_hdr)
  2082. {
  2083. offs = m_vbr_hdr->seekPointByTime((float)posms);
  2084. }
  2085. else if (!m_vbr_flag)
  2086. offs = MulDiv(posms, br, 8);
  2087. else
  2088. {
  2089. int ms = 0;
  2090. int fl = GetContentLength();
  2091. if (!m_vbr_frames)
  2092. {
  2093. ms = MulDiv(fl, 8 * 1000, br);
  2094. }
  2095. else ms = m_vbr_ms;
  2096. offs = SeekPoint(m_vbr_toc, fl, (float)posms / ((float)ms / 100.0f));
  2097. }
  2098. if (m_is_stream)
  2099. {
  2100. if (GetContentLength() > 0)
  2101. {
  2102. if (m_connection && m_is_stream_seekable)
  2103. {
  2104. jnl_connection_release(m_connection);
  2105. m_connection = NULL;
  2106. m_is_stream_seek = true;
  2107. m_seek_reset = false;
  2108. doConnect(NULL, offs);
  2109. }
  2110. }
  2111. }
  2112. else
  2113. {
  2114. SetCurrentPosition(offs, GIO_FILE_BEGIN);
  2115. }
  2116. }
  2117. bool CGioFile::IsSeekable()
  2118. {
  2119. return !m_is_stream || GetContentLength() > 0;
  2120. }
  2121. void CGioFile::GetStreamInfo(wchar_t *obuf, size_t len)
  2122. {
  2123. if (m_is_stream)
  2124. {
  2125. wchar_t langbuf[2048]={0};
  2126. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_NETWORK_RECEIVED_X_BYTES, langbuf, 2048), stream_bytes_read + stream_metabytes_read);
  2127. if (server_name[0])
  2128. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_SERVER, langbuf, 2048), AutoWide(server_name,CP_UTF8));
  2129. if (m_content_type && m_content_type[0])
  2130. {
  2131. if(is_uvox)
  2132. {
  2133. // report the actual content type instead of just misc/ultravox to make it easier to see what the stream type is (helps debugging)
  2134. static const int MP3_DATA = 0x7000;
  2135. static const int VLB_DATA = 0x8000;
  2136. static const int AAC_LC_DATA = 0x8001;
  2137. static const int AACP_DATA = 0x8003;
  2138. static const int OGG_DATA = 0x8004;
  2139. switch(uvox_last_message)
  2140. {
  2141. case MP3_DATA:
  2142. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/mpeg");
  2143. break;
  2144. case VLB_DATA:
  2145. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/vlb");
  2146. break;
  2147. case AAC_LC_DATA:
  2148. case AACP_DATA:
  2149. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/aacp");
  2150. break;
  2151. case OGG_DATA:
  2152. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/ogg");
  2153. break;
  2154. default:
  2155. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), AutoWide(m_content_type,CP_UTF8));
  2156. break;
  2157. }
  2158. }
  2159. else
  2160. {
  2161. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), AutoWide(m_content_type,CP_UTF8));
  2162. }
  2163. }
  2164. if (is_uvox)
  2165. {
  2166. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ULTRAVOX_SYNC, langbuf, 2048), uvox_message_cnt, uvox_desyncs);
  2167. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ULTRAVOX_DATA_MESSAGE, langbuf, 2048), uvox_last_message);
  2168. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ULTRAVOX_SID_AVGBR_MAXBR, langbuf, 2048), uvox_sid, uvox_avgbr, uvox_maxbr);
  2169. }
  2170. if (stream_metabytes_read)
  2171. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_METADATA_RECEIVED, langbuf, 2048), stream_metabytes_read);
  2172. if (meta_interval)
  2173. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_METADATA_INTERVAL, langbuf, 2048), meta_interval);
  2174. if (m_id3v2_len)
  2175. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ID3v2_TAG, langbuf, 2048), m_id3v2_len);
  2176. if (m_vbr_frame_len)
  2177. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_VBR_LEADING_FRAME, langbuf, 2048), m_vbr_frame_len);
  2178. if (stream_title_save[0])
  2179. {
  2180. wchar_t name[580]={0};
  2181. ConvertTryUTF8(stream_title_save, name, 580);
  2182. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_STREAM_NAME, langbuf, 2048), name/*AutoWide(stream_title_save,CP_UTF8)*/);
  2183. }
  2184. if (last_title_sent[0])
  2185. {
  2186. wchar_t title[256]={0};
  2187. ConvertTryUTF8(last_title_sent, title, 256);
  2188. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CURRENT_TITLE, langbuf, 2048), title);
  2189. }
  2190. if (mpeg_length)
  2191. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_LENGTH, langbuf, 2048), mpeg_length);
  2192. if (save_filename[0] && hFile != INVALID_HANDLE_VALUE)
  2193. StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_SAVING_TO, langbuf, 2048), AutoWide(save_filename,CP_UTF8));
  2194. }
  2195. }
  2196. static inline const wchar_t *IncSafe(const wchar_t *val, int x)
  2197. {
  2198. while (x--)
  2199. {
  2200. if (val && *val)
  2201. val++;
  2202. }
  2203. return val;
  2204. }
  2205. void CGioFile::ReadiTunesGaps()
  2206. {
  2207. if (info.HasData() && !prepad && !postpad)
  2208. {
  2209. wchar_t str[128] = {0};
  2210. if (info.GetString("pregap", str, 128) == 1)
  2211. prepad = _wtoi(str);
  2212. str[0]=0;
  2213. if (info.GetString("postgap", str, 128) == 1)
  2214. postpad = _wtoi(str);
  2215. }
  2216. }
  2217. #define CBCLASS CGioFile
  2218. START_DISPATCH;
  2219. CB( MPEGSTREAM_PEEK, Peek )
  2220. CB( MPEGSTREAM_READ, Read )
  2221. CB( MPEGSTREAM_EOF, EndOf )
  2222. CB( MPEGSTREAM_GAIN, GetGain )
  2223. END_DISPATCH;
  2224. #undef CBCLASS