123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475 |
- /***************************************************************************\
- *
- * (C) copyright Fraunhofer - IIS (1998)
- * All Rights Reserved
- *
- * filename: giofile.cpp
- * project : MPEG Decoder
- * author : Martin Sieler
- * date : 1998-02-11
- * contents/description: file I/O class for MPEG Decoder
- *
- *
- \***************************************************************************/
- /* ------------------------ includes --------------------------------------*/
- #include "main.h"
- #include "api__in_mp3.h"
- #include <time.h>
- #include <locale.h>
- #include "../Winamp/wa_ipc.h"
- #include "LAMEinfo.h"
- #include "OFL.h"
- #include "../nu/AutoChar.h"
- #include "../nu/AutoWide.h"
- #include <api/service/waservicefactory.h>
- #include <shlwapi.h>
- #include "MP3Info.h"
- #include "config.h"
- #include <math.h>
- #include "id3.h"
- #include "../apev2/header.h"
- #include "uvox_3902.h"
- #include <foundation/error.h>
- #include <strsafe.h>
- #define MAX_REDIRECTS 10
- #define SAFE_MALLOC_MATH(orig, x) (((orig)<x)?x:orig)
- // seems like a reasonable limit, but we should check with tag first
- #define UVOX_MAXMSG_CAP 1048576
- static jnl_connection_t CreateConnection(const char *url, jnl_dns_t dns, size_t sendbufsize, size_t recvbufsize)
- {
- if (!_strnicmp(url, "https:", strlen("https:")))
- return jnl_sslconnection_create(dns, sendbufsize, recvbufsize);
- else
- return jnl_connection_create(dns, sendbufsize, recvbufsize);
- }
- static int64_t Seek64(HANDLE hf, int64_t distance, DWORD MoveMethod)
- {
- LARGE_INTEGER li;
- li.QuadPart = distance;
- li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
- if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
- {
- li.QuadPart = -1;
- }
- return li.QuadPart;
- }
- HWND GetDialogBoxParent()
- {
- HWND parent = (HWND)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
- if (!parent || parent == (HWND)1)
- return mod.hMainWindow;
- return parent;
- }
- /*-------------------------- defines --------------------------------------*/
- /*-------------------------------------------------------------------------*/
- //-------------------------------------------------------------------------*
- //
- // CGioFile
- //
- //-------------------------------------------------------------------------*
- //-------------------------------------------------------------------------*
- // constructor
- //-------------------------------------------------------------------------*
- static char ultravoxUserAgent[128] = "";
- char *GetUltravoxUserAgent()
- {
- if (!ultravoxUserAgent[0])
- {
- StringCchPrintfA(ultravoxUserAgent, 128, "User-Agent: WinampMPEG/%01x.%02x, Ultravox/2.1\r\n"
- "Ultravox-transport-type: TCP\r\n",
- WINAMP_VERSION_MAJOR(winampVersion),
- WINAMP_VERSION_MINOR(winampVersion));
- }
- return ultravoxUserAgent;
- }
- static char userAgent[128] = "";
- char *GetUserAgent()
- {
- if (!userAgent[0])
- {
- StringCchPrintfA(userAgent, 128, "User-Agent: WinampMPEG/%01x.%02x\r\n",
- WINAMP_VERSION_MAJOR(winampVersion),
- WINAMP_VERSION_MINOR(winampVersion));
- }
- return userAgent;
- }
- extern int lastfn_status_err;
- CGioFile::CGioFile()
- {
- req=0;
- proxy_host=0;
- host=0;
- request=0;
- proxy_lp=0;
- lpinfo=0;
- mpeg_length=0;
- file_position=0;
- mpeg_position=0;
- no_peek_hack=false;
- encodingMethod=0;
- uvox_3901=0;
- uvox_3902=0;
- stream_url[0]=0;
- stream_genre[0]=0;
- stream_current_title[0]=0;
- stream_name[0]=0;
- ZeroMemory(&last_write_time, sizeof(last_write_time));
- ZeroMemory(id3v1_data, sizeof(id3v1_data));
- lengthVerified=false;
- m_vbr_bytes = 0;
- uvox_last_message = 0;
- prepad = 0;
- postpad = 0;
- m_vbr_ms = 0;
- m_vbr_hdr = 0;
- stream_id3v2_buf = 0;
- lyrics3_size=0;
- lyrics3_data=0;
- apev2_data=0;
- m_content_type = 0;
- ZeroMemory(uvox_meta, sizeof(uvox_meta));
- is_uvox = 0;
- uvox_sid = uvox_maxbr = uvox_avgbr = 0;
- uvox_message_cnt = uvox_desyncs = 0;
- uvox_stream_data = 0;
- uvox_stream_data_len = 0;
- ZeroMemory(&uvox_artwork, sizeof(uvox_artwork));
- uvox_maxmsg = 65535;
- force_lpinfo[0] = 0;
- is_stream_seek = 0;
- last_full_url[0] = 0;
- m_is_stream = 0;
- m_redircnt = 0;
- m_auth_tries = 0;
- m_full_buffer = NULL;
- fEof = false;
- m_connection = NULL;
- m_dns = NULL;
- hFile = INVALID_HANDLE_VALUE;
- m_http_response = 0;
- m_seek_reset = false;
- m_is_stream_seek = false;
- m_is_stream_seekable = false;
- initTitleList();
- m_vbr_frames = 0;
- ZeroMemory(&m_vbr_toc, sizeof(m_vbr_toc));
- m_vbr_frame_len = 0;
- m_vbr_flag = 0;
- m_id3v2_len = 0;
- m_id3v1_len = 0;
- port = 80;
- constate = 0;
- ZeroMemory(&save_filename, sizeof(save_filename));
- ZeroMemory(&server_name, sizeof(server_name));
- recvbuffersize = 32768;
- timeout_start = GetTickCount();
- meta_interval = 0;
- meta_pos = 0;
- ZeroMemory(&stream_title_save, sizeof(stream_title_save));
- ZeroMemory(&last_title_sent, sizeof(last_title_sent));
- ZeroMemory(&dlg_realm, sizeof(dlg_realm));
- m_useaproxy = 0;
- }
- //-------------------------------------------------------------------------*
- // destructor
- //-------------------------------------------------------------------------*
- CGioFile::~CGioFile()
- {
- int x, y;
- for (x = 0; x < 2; x ++)
- for (y = 0; y < 32; y ++)
- free(uvox_meta[x][y]);
- free(m_content_type);
- free(uvox_stream_data);
- free(stream_id3v2_buf);
- free(lyrics3_data);
- free(apev2_data);
- free(uvox_3901);
- free(uvox_3902);
- Close();
- delete m_vbr_hdr;
- m_vbr_hdr = 0;
- clearTitleList();
- free(lpinfo);
- free(proxy_lp);
- free(request);
- free(host);
- free(req);
- free(proxy_host);
- }
- static bool GetRG(const char *key, ID3v2 &info, APEv2::Tag &apev2, wchar_t *val, int len)
- {
- val[0]=0;
- if (info.GetString(key, val, len) == 1 && val[0])
- return true;
- if (apev2.GetString(key, val, len) == APEv2::APEV2_SUCCESS && val[0])
- return true;
- return false;
- }
- float CGioFile::GetGain()
- {
- if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false))
- {
- // if (info.HasData())
- {
- float dB = 0, peak = 1.0f;
- wchar_t gain[128] = L"", peakVal[128] = L"";
- _locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
- switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_source", 0))
- {
- case 0: // track
- if ((GetRG("replaygain_track_gain", info, apev2, gain, 128) == false || !gain[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- GetRG("replaygain_album_gain", info, apev2, gain, 128);
- if ((GetRG("replaygain_track_peak", info, apev2, peakVal, 128) == false || !peakVal[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- GetRG("replaygain_album_peak", info, apev2, peakVal, 128);
- break;
- case 1:
- if ((GetRG("replaygain_album_gain", info, apev2, gain, 128) == false || !gain[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- GetRG("replaygain_track_gain", info, apev2, gain, 128);
- if ((GetRG("replaygain_album_peak", info, apev2, peakVal, 128) == false || !peakVal[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- GetRG("replaygain_track_peak", info, apev2, peakVal, 128);
- break;
- }
- if (gain[0])
- {
- if (gain[0] == L'+')
- dB = (float)_wtof_l(&gain[1], C_locale);
- else
- dB = (float)_wtof_l(gain, C_locale);
- }
- else
- {
- dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0);
- return (float)pow(10.0f, dB / 20.0f);
- }
- if (peakVal[0])
- {
- peak = (float)_wtof_l(peakVal, C_locale);
- }
- switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_mode", 1))
- {
- case 0: // apply gain
- return (float)pow(10.0f, dB / 20.0f);
- case 1: // apply gain, but don't clip
- return min((float)pow(10.0f, dB / 20.0f), 1.0f / peak);
- case 2: // normalize
- return 1.0f / peak;
- case 3: // prevent clipping
- if (peak > 1.0f)
- return 1.0f / peak;
- else
- return 1.0f;
- }
- }
- /* else
- {
- float dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0);
- return pow(10.0f, dB / 20.0f);
- }*/
- }
- return 1.0f; // no gain
- }
- //-------------------------------------------------------------------------*
- // Open
- //-------------------------------------------------------------------------*
- static char *jnl_strndup(const char *str, size_t n)
- {
- char *o = (char *)calloc(n+1, sizeof(char));
- if (!o)
- return 0;
-
- strncpy(o, str, n);
- o[n]=0;
- return o;
- }
- static int parse_url(const char *url, char **prot, char **host, unsigned short *port, char **req, char **lp)
- {
- free(*prot); *prot=0;
- free(*host); *host = 0;
- free(*req); *req = 0;
- free(*lp); *lp = 0;
- *port = 0;
- const char *p;
- const char *protocol = strstr(url, "://");
- if (protocol)
- {
- *prot = jnl_strndup(url, protocol-url);
- p = protocol + 3;
-
- }
- else
- {
- p = url;
- }
- while (p && *p == '/') p++; // skip extra /
- size_t end = strcspn(p, "@/");
- // check for username
- if (p[end] == '@')
- {
- *lp = jnl_strndup(p, end);
- p = p+end+1;
- end = strcspn(p, "[:/");
- }
- if (p[0] == '[') // IPv6 style address
- {
- p++;
- const char *ipv6_end = strchr(p, ']');
- if (!ipv6_end)
- return 1;
- *host = jnl_strndup(p, ipv6_end-p);
- p = ipv6_end+1;
- }
- else
- {
- end = strcspn(p, ":/");
- *host = jnl_strndup(p, end);
- p += end;
- }
- // is there a port number?
- if (p[0] == ':')
- {
- char *new_end;
- *port = (unsigned short)strtoul(p+1, &new_end, 10);
- p = new_end;
- }
- if (p[0])
- {
- *req = _strdup(p);
- }
-
- return 0;
- }
- static void parseURL(const char *url, char **host, unsigned short *port, char **req, char **lp)
- {
- char *prot=0;
-
- parse_url(url, &prot, host, port, req, lp);
- if (!*port)
- {
- if (prot)
- {
- if (!stricmp(prot, "https"))
- *port = 443;
- else
- *port = 80;
- }
- else
- *port=80;
- }
-
- free(prot);
- if (!*req)
- *req = _strdup("/");
- }
- static void encodeMimeStr(char *in, char *out)
- {
- char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- int shift = 0;
- int accum = 0;
- while (in && *in)
- {
- if (*in)
- {
- accum <<= 8;
- shift += 8;
- accum |= *in++;
- }
- while (shift >= 6)
- {
- shift -= 6;
- *out++ = alphabet[(accum >> shift) & 0x3F];
- }
- }
- if (shift == 4)
- {
- *out++ = alphabet[(accum & 0xF) << 2];
- *out++ = '=';
- }
- else if (shift == 2)
- {
- *out++ = alphabet[(accum & 0x3) << 4];
- *out++ = '=';
- *out++ = '=';
- }
- *out++ = 0;
- }
- int CGioFile::doConnect(const char *str, int start_offset)
- {
- char *http_ver_str = " HTTP/1.0\r\n";
- unsigned short proxy_port = 80;
- char str2[1024]={0};
- if (!str)
- str = last_full_url;
- else
- lstrcpynA( last_full_url, str, sizeof( last_full_url ) );
- if (start_offset > 0)
- {
- http_ver_str = " HTTP/1.1\r\n";
- }
- lstrcpynA(str2, str, 1024);
-
- is_stream_seek = start_offset || !str;
-
- lstrcpynA(g_stream_title, str, 256);
-
- meta_interval = meta_pos = 0;
- server_name[0] = 0;
- last_title_sent[0] = 0;
- stream_bytes_read = start_offset;
- stream_metabytes_read = 0;
- m_is_stream = 1;
- constate = 0;
- parseURL(str2, &host, &port, &request, &lpinfo);
- if (port == 80 || !GetPrivateProfileIntA("Winamp", "proxyonly80", 0, INI_FILE))
- {
- const char *p;
- const char *winamp_proxy = (const char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_PROXY_STRING);
- if (!winamp_proxy || winamp_proxy == (char *)1)
- {
- char temp[256] = {0};
- GetPrivateProfileStringA("Winamp", "proxy", "", temp, sizeof(temp), INI_FILE);
- p = temp;
- }
- else
- p = winamp_proxy;
- while (p && (*p == ' ' || *p == '\t')) p++;
- char config_proxy[512] = "http://";
- StringCchCatA(config_proxy, 512, p);
- parseURL(config_proxy, &proxy_host, &proxy_port, &req, &proxy_lp);
- }
- if (!host || !host[0])
- return 1;
- char *p = request + strlen(request);
- while (p >= request && *p != '/') p--;
- if (p[1])
- lstrcpynA(g_stream_title, ++p, 256);
- lstrcpynA(stream_title_save, g_stream_title, 580);
- lstrcpynA(stream_name, g_stream_title, 256);
- g_stream_title[255] = 0;
- fEof = false;
- timeout_start = GetTickCount();
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_CONNECTING,lastfn_status,256);
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- if (force_lpinfo[0])
- {
- free(lpinfo);
- lpinfo = _strdup(force_lpinfo);
- }
- if (!m_dns) jnl_dns_create(&m_dns);
- m_connection = CreateConnection(str, m_dns, 16384, recvbuffersize = max(32768, config_http_buffersize * 1024));
- if (!m_connection)
- return 1;
- if (!proxy_host || !proxy_host[0])
- {
- jnl_connection_connect(m_connection, host, port);
- jnl_connection_send_string(m_connection, "GET ");
- jnl_connection_send_string(m_connection, request);
- jnl_connection_send_string(m_connection, http_ver_str);
- }
- else
- {
- char s[32]={0};
- jnl_connection_connect(m_connection, proxy_host, proxy_port);
- jnl_connection_send_string(m_connection, "GET http://");
- if (lpinfo && lpinfo[0])
- {
- jnl_connection_send_string(m_connection, lpinfo);
- jnl_connection_send_string(m_connection, "@");
- }
- jnl_connection_send_string(m_connection, host);
- StringCchPrintfA(s, 32, ":%d", port);
- jnl_connection_send_string(m_connection, s);
- jnl_connection_send_string(m_connection, request);
- jnl_connection_send_string(m_connection, http_ver_str);
- if (proxy_lp && proxy_lp[0])
- {
- char temp[1024]={0};
- jnl_connection_send_string(m_connection, "Proxy-Authorization: Basic ");
- encodeMimeStr(proxy_lp, temp);
- jnl_connection_send_string(m_connection, temp);
- jnl_connection_send_string(m_connection, "\r\n");
- }
- }
- jnl_connection_send_string(m_connection, "Host: ");
- jnl_connection_send_string(m_connection, host);
- jnl_connection_send_string(m_connection, "\r\n");
- if (!start_offset)
- {
- jnl_connection_send_string(m_connection, GetUltravoxUserAgent());
- }
- else
- jnl_connection_send_string(m_connection, GetUserAgent());
- jnl_connection_send_string(m_connection, "Accept: */*\r\n");
- if (allow_sctitles && !start_offset) jnl_connection_send_string(m_connection, "Icy-MetaData:1\r\n");
- if (lpinfo && lpinfo[0])
- {
- char str[512] = {0};
- encodeMimeStr(lpinfo, str);
- jnl_connection_send_string(m_connection, "Authorization: Basic ");
- jnl_connection_send_string(m_connection, str);
- jnl_connection_send_string(m_connection, "\r\n");
- }
- if (start_offset > 0)
- {
- char str[512] = {0};
- StringCchPrintfA(str, 512, "Range: bytes=%d-\r\n", start_offset);
- jnl_connection_send_string(m_connection, str);
- }
- jnl_connection_send_string(m_connection, "Connection: close\r\n");
- jnl_connection_send_string(m_connection, "\r\n");
- return 0;
- }
- int CGioFile::Open(const wchar_t *pszName, int maxbufsizek)
- {
- peekBuffer.reserve(16384);
- m_vbr_flag = 0;
- m_vbr_frames = 0;
- m_vbr_samples = 0;
- m_vbr_ms = 0;
- m_vbr_frame_len = 0;
-
- m_id3v2_len = 0;
- m_id3v1_len = 0;
- m_apev2_len = 0;
-
- lyrics3_size = 0;
-
- m_is_stream = 0;
-
- mpeg_length = 0;
- mpeg_position = 0;
- file_position = 0;
-
- if ( !_wcsnicmp( pszName, L"file://", 7 ) )
- pszName += 7;
- if ( PathIsURL( pszName ) )
- {
- wchar_t str[ 8192 ] = { 0 };
- wchar_t *p;
- hFile = INVALID_HANDLE_VALUE;
- lstrcpyn( str, pszName, 8192 );
- save_filename[ 0 ] = 0;
- if ( p = wcsstr( str, L">save.file:" ) )
- {
- *p = 0;
- p += 11;
- if ( !wcsstr( p, L".." ) && !wcsstr( p, L"\\" ) && !wcsstr( p, L"/" ) )
- {
- lstrcpynA( save_filename, AutoChar( p ), 256 );
- }
- }
- if ( doConnect( AutoChar( str ), 0 ) )
- return NErr_ConnectionFailed;
- }
- else
- {
- hFile = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
- if (hFile != INVALID_HANDLE_VALUE)
- {
- GetFileTime( hFile, 0, 0, &last_write_time );
- mpeg_length = Seek64( hFile, 0, FILE_END );
- uint64_t startOffset = 0;
- unsigned char buf[ 1448 ] = { 0 };
- DWORD len = 0;
- while ( 1 ) // read all tags (sometimes programs get stupid and make multiple tags)
- {
- len = 0;
- Seek64( hFile, startOffset, FILE_BEGIN );
- ReadFile( hFile, buf, 10, &len, NULL );
- if ( len >= 10 &&
- buf[ 0 ] == 'I' &&
- buf[ 1 ] == 'D' &&
- buf[ 2 ] == '3' &&
- buf[ 3 ] != 255 &&
- buf[ 4 ] != 255 &&
- buf[ 6 ] < 0x80 &&
- buf[ 7 ] < 0x80 &&
- buf[ 8 ] < 0x80 &&
- buf[ 9 ] < 0x80 )
- {
- DWORD thisLen = 10;
- if ( buf[ 5 ] & 0x10 ) // check for footer flag
- thisLen += 10;
- thisLen += ( (int)buf[ 6 ] ) << 21;
- thisLen += ( (int)buf[ 7 ] ) << 14;
- thisLen += ( (int)buf[ 8 ] ) << 7;
- thisLen += ( (int)buf[ 9 ] );
- SetFilePointer( hFile, -10, NULL, FILE_CURRENT );
- if ( stream_id3v2_buf ) // already read a tag?
- {
- startOffset += thisLen;
- m_id3v2_len += thisLen;
- mpeg_length -= thisLen;
- mpeg_position += thisLen;
-
- SetFilePointer( hFile, thisLen, NULL, FILE_CURRENT );
- continue;
- }
- stream_id3v2_buf = (char *)malloc( thisLen );
- if ( stream_id3v2_buf )
- {
- memcpy( stream_id3v2_buf, buf, 10 );
- DWORD dummy = 0;
- if ( !ReadFile( hFile, stream_id3v2_buf, thisLen, &dummy, 0 ) || dummy < thisLen )
- {
- free( stream_id3v2_buf );
- stream_id3v2_buf = NULL;
-
- thisLen = 0;
- SetFilePointer( hFile, 0, NULL, FILE_END );
- break;
- }
- else
- {
- mpeg_position += thisLen;
- stream_id3v2_read = thisLen;
- mpeg_length -= thisLen;
- startOffset += thisLen;
- info.Decode( stream_id3v2_buf, thisLen );
- }
- }
- else
- {
- /* memory allocation failed, let's assume the ID3v2 tag was valid ... */
- mpeg_position += thisLen;
- stream_id3v2_read = thisLen;
- mpeg_length -= thisLen;
- startOffset += thisLen;
- }
- m_id3v2_len += thisLen;
- }
- else
- {
- // benski> unnecessary because we call SetFilePointer immediately after the loop:
- // CUT: SetFilePointer(hFile, -10, NULL, FILE_CURRENT);
- break;
- }
- }
- /* Read ID3v1 Tag */
- if ( mpeg_length >= 128 )
- {
- SetFilePointer( hFile, -128, NULL, FILE_END );
- len = 0;
- if ( ReadFile( hFile, id3v1_data, 128, &len, NULL ) && len == 128 )
- {
- if ( id3v1_data[ 0 ] == 'T' && id3v1_data[ 1 ] == 'A' && id3v1_data[ 2 ] == 'G' )
- {
- m_id3v1_len = 128;
- mpeg_length -= m_id3v1_len;
- }
- }
- }
- /* read appended ID3v2.4 tag */
- if ( mpeg_length >= 10 && Seek64( hFile, mpeg_position + mpeg_length - 10, FILE_BEGIN ) != -1 )
- {
- len = 0;
- ReadFile( hFile, buf, 10, &len, NULL );
- if ( len >= 10 &&
- buf[ 0 ] == '3' &&
- buf[ 1 ] == 'D' &&
- buf[ 2 ] == 'I' &&
- buf[ 3 ] != 255 &&
- buf[ 4 ] != 255 &&
- buf[ 6 ] < 0x80 &&
- buf[ 7 ] < 0x80 &&
- buf[ 8 ] < 0x80 &&
- buf[ 9 ] < 0x80 )
- {
- DWORD thisLen = 10;
- if ( buf[ 5 ] & 0x10 ) // check for header flag
- thisLen += 10;
- thisLen += ( (int)buf[ 6 ] ) << 21;
- thisLen += ( (int)buf[ 7 ] ) << 14;
- thisLen += ( (int)buf[ 8 ] ) << 7;
- thisLen += ( (int)buf[ 9 ] );
- mpeg_length -= thisLen;
- }
- }
- /* Read Lyrics3 Tag */
- if ( mpeg_length >= 15 )
- {
- free( lyrics3_data );
- lyrics3_data = NULL;
- lyrics3_size = 0;
- char lyrics3_end_signature[ 15 ] = { 0 };
- Seek64( hFile, ( mpeg_position + mpeg_length - 15 ), FILE_BEGIN );
- len = 0;
- if ( ReadFile( hFile, lyrics3_end_signature, 15, &len, NULL ) && len == 15 )
- {
- if ( !memcmp( lyrics3_end_signature + 6, "LYRICS200", 9 ) )
- {
- lyrics3_size = strtoul( lyrics3_end_signature, 0, 10 );
- if ( lyrics3_size )
- {
- lyrics3_data = (char *)malloc( lyrics3_size );
- if ( lyrics3_data )
- {
- SetFilePointer( hFile, -(LONG)( 15 + lyrics3_size ), NULL, FILE_CURRENT );
- len = 0;
- ReadFile( hFile, lyrics3_data, lyrics3_size, &len, 0 );
- if ( len != lyrics3_size || memcmp( lyrics3_data, "LYRICSBEGIN", 11 ) )
- {
- free( lyrics3_data );
- lyrics3_data = NULL;
- lyrics3_size = 0;
- }
- else
- {
- mpeg_length -= lyrics3_size + 15;
- }
- }
- }
- }
- }
- }
- if ( mpeg_length >= 32 )
- {
- /* Read APEv2 Tag */
- free( apev2_data );
- apev2_data = NULL;
-
- char ape[ 32 ] = { 0 };
- Seek64( hFile, ( mpeg_position + mpeg_length - 32 ), FILE_BEGIN );
- len = 0;
- if ( ReadFile( hFile, ape, 32, &len, NULL ) && len == 32 )
- {
- APEv2::Header footer( ape );
- if ( footer.Valid() )
- {
- m_apev2_len = footer.TagSize();
- if ( mpeg_length >= m_apev2_len )
- {
- Seek64( hFile, -(int64_t)( m_apev2_len ), FILE_CURRENT );
- apev2_data = (char *)malloc( m_apev2_len );
- if ( apev2_data )
- {
- len = 0;
- ReadFile( hFile, apev2_data, m_apev2_len, &len, NULL );
- if ( len != m_apev2_len || apev2.Parse( apev2_data, m_apev2_len ) != APEv2::APEV2_SUCCESS )
- {
- free( apev2_data );
- apev2_data = NULL;
- m_apev2_len = 0;
- }
- }
- mpeg_length -= m_apev2_len;
- }
- }
- }
- }
- {
- Seek64( hFile, mpeg_position, FILE_BEGIN );
- len = 0;
- ReadFile( hFile, buf, sizeof( buf ), &len, NULL );
-
- delete m_vbr_hdr;
- m_vbr_hdr = NULL;
-
- LAMEinfo lame;
- lame.toc = m_vbr_toc;
- m_vbr_frame_len = ReadLAMEinfo( buf, &lame );
- if ( m_vbr_frame_len )
- {
- lengthVerified = false;
- prepad = lame.encoderDelay;
- postpad = lame.padding;
- encodingMethod = lame.encodingMethod;
- if ( !encodingMethod && lame.cbr )
- encodingMethod = ENCODING_METHOD_CBR;
- if ( lame.flags & TOC_FLAG )
- {
- int x;
- for ( x = 0; x < 100; x++ )
- if ( m_vbr_toc[ x ] ) break;
- if ( x != 100 )
- m_vbr_flag = 1;
- }
- if ( lame.flags & BYTES_FLAG )
- {
- // some programs are stupid and count the id3v2 length in the lame header
- if ( mpeg_length + m_id3v2_len == lame.bytes || mpeg_length + m_id3v2_len + m_id3v1_len == lame.bytes )
- {
- m_vbr_bytes = mpeg_length;
- lengthVerified = true;
- }
- else if ( abs( (int)mpeg_length - lame.bytes ) < MAX_ACCEPTABLE_DEVIANCE )
- {
- m_vbr_bytes = lame.bytes;
- lengthVerified = true;
- }
- }
- if ( lame.flags & FRAMES_FLAG
- && m_vbr_bytes && lengthVerified ) // only use the length if we're sure it's unmodified
- {
- m_vbr_frames = lame.frames;
- m_vbr_samples = Int32x32To64( lame.frames, lame.h_id ? 1152 : 576 );
- m_vbr_samples -= ( prepad + postpad );
- m_vbr_ms = MulDiv( (int)m_vbr_samples, 1000, lame.samprate );
- }
- if ( !m_vbr_frames || encodingMethod == ENCODING_METHOD_CBR )
- m_vbr_flag = 0;
- mpeg_length -= m_vbr_frame_len;
- mpeg_position += m_vbr_frame_len;
- }
- else
- {
- m_vbr_hdr = new CVbriHeader;
- m_vbr_frame_len = m_vbr_hdr->readVbriHeader(buf);
- if (m_vbr_frame_len)
- {
- m_vbr_bytes = m_vbr_hdr->getBytes();
- m_vbr_frames = m_vbr_hdr->getNumFrames();
- m_vbr_ms = m_vbr_hdr->getNumMS();
-
- lengthVerified = true;
- mpeg_length -= m_vbr_frame_len;
- mpeg_position += m_vbr_frame_len;
- }
- else
- {
- delete m_vbr_hdr;
- m_vbr_hdr = NULL;
- }
- }
- }
- // read OFL
- {
- Seek64( hFile, mpeg_position, FILE_BEGIN );
- len = 0;
- ReadFile( hFile, buf, sizeof( buf ), &len, NULL );
- MPEGFrame frame;
- frame.ReadBuffer( buf );
- OFL ofl;
- if ( ofl.Read( frame, &buf[ 4 ], len - 4 ) == NErr_Success )
- {
- m_vbr_ms = (int)ofl.GetLengthSeconds() * 1000;
- m_vbr_samples = ofl.GetSamples();
- m_vbr_frames = ofl.GetFrames();
- size_t pre, post;
- if ( ofl.GetGaps( &pre, &post ) == NErr_Success )
- {
- prepad = (int)pre - 529;
- postpad = (int)post + 529;
- }
- }
- }
- ReadiTunesGaps();
- Seek64( hFile, mpeg_position, FILE_BEGIN );
- if ( maxbufsizek * 1024 >= mpeg_length )
- {
- DWORD m_full_buffer_len = 0;
- m_full_buffer = new unsigned char[ (unsigned int)mpeg_length ];
- if ( !ReadFile( hFile, m_full_buffer, (DWORD)mpeg_length, &m_full_buffer_len, NULL ) )
- {
- CloseHandle( hFile );
- hFile = INVALID_HANDLE_VALUE;
- delete[] m_full_buffer;
- m_full_buffer = NULL;
- return NErr_Error;
- }
- CloseHandle( hFile );
- hFile = INVALID_HANDLE_VALUE;
- m_full_buffer_pos = 0;
- }
- else
- {
- m_full_buffer = NULL;
- }
- fEof = false;
- return NErr_Success;
- }
- else
- {
- //DWORD dwError = GetLastError();
- return NErr_Error;
- }
- }
- return NErr_Success;
- }
- //-------------------------------------------------------------------------*
- // Close
- //-------------------------------------------------------------------------*
- int CGioFile::Close()
- {
- int dwReturn = NErr_Success;
- if (m_is_stream)
- {
- jnl_connection_release(m_connection);
- if (m_dns) jnl_dns_release(m_dns);
- m_dns = 0;
- if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
- hFile = INVALID_HANDLE_VALUE;
- m_is_stream = 0;
- }
- else
- {
- delete [] m_full_buffer;
- m_full_buffer = NULL;
- if (hFile != INVALID_HANDLE_VALUE)
- {
- dwReturn = CloseHandle(hFile) ? NErr_Success : NErr_Error;
- hFile = INVALID_HANDLE_VALUE;
- }
- }
- return dwReturn;
- }
- void CGioFile::processMetaData(char *data, int len, int msgId)
- {
- if (len && *data)
- {
- char *ld = NULL;
- int x;
- if (len > 4096) return ;
- for (x = 0; x < len; x ++)
- if (!data[x]) break;
- if (x == len) return ;
- while ((ld = strstr(data, "='")))
- {
- char * n = data;
- ld[0] = 0;
- ld += 2;
- data = strstr(ld, "';");
- if (data)
- {
- data[0] = 0;
- data += 2;
- if (!_stricmp(n, "StreamTitle"))
- {
- lstrcpynA(g_stream_title, ld, sizeof(g_stream_title));
- lstrcpynA(last_title_sent, g_stream_title, sizeof(last_title_sent));
- lstrcpynA(stream_current_title, g_stream_title, sizeof(stream_current_title));
- if (sctitle_format)
- {
- StringCchCatA(g_stream_title, 256, *stream_title_save ? *g_stream_title ? " (" : "(" : "");
- StringCchCatA(g_stream_title, 256, stream_title_save);
- StringCchCatA(g_stream_title, 256, *stream_title_save ? ")" : "");
- }
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- else if (!_stricmp(n, "StreamUrl"))
- {
- lstrcpynA(stream_url, ld, sizeof(stream_url));
- DWORD_PTR dw;
- if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, IPC_MBOPEN, SMTO_NORMAL, 500, &dw);
- }
- }
- else break;
- }
- }
- }
- INT_PTR CALLBACK CGioFile::httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- CGioFile *_this;
- switch (uMsg)
- {
- case WM_INITDIALOG:
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
- _this = (CGioFile *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- if (_this->force_lpinfo[0])
- SetDlgItemTextA(hwndDlg, IDC_EDIT1, _this->force_lpinfo);
- else SetDlgItemTextA(hwndDlg, IDC_EDIT1, _this->lpinfo?_this->lpinfo:"");
- SetDlgItemTextA(hwndDlg, IDC_REALM, _this->dlg_realm);
- return 1;
- case WM_COMMAND:
- _this = (CGioFile *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- if (LOWORD(wParam) == IDOK)
- {
- GetDlgItemTextA(hwndDlg, IDC_EDIT1, _this->force_lpinfo, sizeof(_this->force_lpinfo));
- EndDialog(hwndDlg, 1);
- }
- else if (LOWORD(wParam) == IDCANCEL)
- {
- EndDialog(hwndDlg, 0);
- }
- break;
- }
- return 0;
- }
- class GioFileFiller : public Filler
- {
- public:
- GioFileFiller(CGioFile *_file)
- {
- ret=NErr_Success;
- file=_file;
- }
- size_t Read(void *dest, size_t len)
- {
- int bytesRead=0;
- ret = file->Read(dest, (int)len, &bytesRead);
- return bytesRead;
- }
- CGioFile *file;
- int ret;
- };
- int CGioFile::Peek(void *pBuffer, int cbToRead, int *pcbRead)
- {
- GioFileFiller filler(this);
- // do we need to fill up?
- if (cbToRead > (int)peekBuffer.size())
- {
- no_peek_hack = true;// benski> HACK ALERT! we have to set this or else Read() will try to use the peek buffer
- peekBuffer.fill(&filler, cbToRead - peekBuffer.size());
- no_peek_hack=false;
- }
- *pcbRead = (int)peekBuffer.peek(pBuffer, cbToRead);
- return filler.ret;
- }
- //-------------------------------------------------------------------------*
- // Read
- //-------------------------------------------------------------------------*
- int CGioFile::Read(void *pBuffer, int cbToRead, int *pcbRead)
- {
- TITLELISTTYPE *mylist = TitleLinkedList;
- // these are used for SHOUTCAST2 metadata and artwork since it can provide
- // multi-packet metadata chunks which are out of order or are received in
- // a way which would otherwise cause these to be cleared incorrectly
- static int title_parts = 0, stream_art_parts = 0, stream_art_parts_total_len = 0,
- playing_art_parts = 0, playing_art_parts_total_len = 0;
- static char **title_blocks = 0, **stream_art_blocks = 0, **playing_art_blocks = 0;
- if (mylist != &TitleListTerminator && mod.outMod)
- {
- while (mylist->Next && mylist != &TitleListTerminator)
- {
- TITLELISTTYPE *next = (TITLELISTTYPE *)mylist->Next;
- long now = mod.outMod->GetOutputTime();
- if (mylist->title[0] || mylist->part_len)
- {
- if (!mylist->timer || now >= mylist->timer)
- {
- switch(mylist->style)
- {
- case UVOX_METADATA_STYLE_AOLRADIO:
- {
- EnterCriticalSection(&streamInfoLock);
- free(uvox_3901);
- uvox_3901 = _strdup(mylist->title);
- LeaveCriticalSection(&streamInfoLock);
- if (g_playing_file)
- {
- PostMessage(mod.hMainWindow, WM_USER, (WPARAM) "0x3901", IPC_METADATA_CHANGED);
- PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
- }
- }
- break;
- case UVOX_METADATA_STYLE_SHOUTCAST:
- {
- processMetaData(mylist->title, (int)strlen(mylist->title) + 1);
- }
- break;
- case UVOX_METADATA_STYLE_SHOUTCAST2:
- {
- EnterCriticalSection(&streamInfoLock);
- // so we can recombine multi-packets we'll store things and
- // when all of the packets have been read then we form them
- if(!title_blocks)
- title_blocks = (char **)malloc(sizeof(char*)*(mylist->total_parts));
- title_blocks[mylist->part-1] = _strdup(mylist->title);
- title_parts++;
- // sanity check so we only try to get the metadata if all parts were processed
- if (title_parts == mylist->total_parts)
- {
- free(uvox_3902);
- uvox_3902 = (char *)malloc(16377 * mylist->total_parts);
- uvox_3902[0] = 0;
- title_parts = 0;
- for(int i = 0; i < mylist->total_parts; i++)
- {
- StringCchCatA(uvox_3902, mylist->total_parts * 16384, title_blocks[i]);
- free(title_blocks[i]);
- }
- free(title_blocks);
- title_blocks = 0;
- // attempt to form a title as 'artist - album - title' as sc_serv2 feeds
- // changed for 5.61 to be just 'artist - title' to match v1 and v2 tools
- Ultravox3902 uvox_metadata;
- if (uvox_metadata.Parse(uvox_3902) != API_XML_FAILURE)
- {
- wchar_t stream_title[256] = {0};
- char* fields[] = {"artist", "title"};
- for(int i = 0; i < sizeof(fields)/sizeof(fields[0]); i++)
- {
- wchar_t temp[256] = {0};
- int ret = uvox_metadata.GetExtendedData(fields[i], temp, 256);
- if(ret && temp[0])
- {
- if(stream_title[0]) StringCchCatW(stream_title, 256, L" - ");
- StringCchCatW(stream_title, 256, temp);
- }
- }
- lstrcpynA(g_stream_title, AutoChar(stream_title, CP_UTF8), sizeof(g_stream_title));
- lstrcpynA(last_title_sent, g_stream_title, sizeof(last_title_sent));
- lstrcpynA(stream_current_title, g_stream_title, sizeof(stream_current_title));
- }
- }
- else
- {
- g_stream_title[0] = 0;
- last_title_sent[0] = 0;
- }
- if (sctitle_format)
- {
- StringCchCatA(g_stream_title, 256, *stream_title_save ? *g_stream_title ? " (" : "(" : "");
- StringCchCatA(g_stream_title, 256, stream_title_save);
- StringCchCatA(g_stream_title, 256, *stream_title_save ? ")" : "");
- }
- LeaveCriticalSection(&streamInfoLock);
-
- if (g_playing_file)
- {
- PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
- }
- }
- break;
- case UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK:
- {
- EnterCriticalSection(&streamInfoLock);
- // so we can recombine multi-packets we'll store things and
- // when all of the packets have been read then we form them
- if(!stream_art_blocks)
- {
- stream_art_parts_total_len = 0;
- stream_art_blocks = (char **)malloc(sizeof(char*)*(mylist->total_parts));
- }
- stream_art_blocks[mylist->part-1] = (char *)malloc(mylist->part_len+1);
- memcpy(stream_art_blocks[mylist->part-1], mylist->title, mylist->part_len);
- stream_art_parts++;
- stream_art_parts_total_len += mylist->part_len;
- // sanity check so we only try to get the metadata if all parts were processed
- if (stream_art_parts == mylist->total_parts)
- {
- free(uvox_artwork.uvox_stream_artwork);
- if (stream_art_parts_total_len <= 0) break;
- uvox_artwork.uvox_stream_artwork = (char *)malloc(stream_art_parts_total_len);
- uvox_artwork.uvox_stream_artwork[0] = 0;
- uvox_artwork.uvox_stream_artwork_len = stream_art_parts_total_len;
- uvox_artwork.uvox_stream_artwork_type = mylist->type;
- stream_art_parts = 0;
- char *art = uvox_artwork.uvox_stream_artwork;
- for(int i = 0; i < mylist->total_parts; i++)
- {
- int size = min(stream_art_parts_total_len, 16371);
- if (size > 0 && size <= 16371)
- {
- memcpy(art, stream_art_blocks[i], size);
- stream_art_parts_total_len -= size;
- art += size;
- }
- free(stream_art_blocks[i]);
- }
- free(stream_art_blocks);
- stream_art_blocks = 0;
- }
- LeaveCriticalSection(&streamInfoLock);
-
- if (g_playing_file)
- {
- PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
- }
- }
- break;
- case UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK_PLAYING:
- {
- EnterCriticalSection(&streamInfoLock);
- // so we can recombine multi-packets we'll store things and
- // when all of the packets have been read then we form them
- if(!playing_art_blocks)
- {
- playing_art_parts_total_len = 0;
- playing_art_blocks = (char **)malloc(sizeof(char*)*(mylist->total_parts));
- }
- playing_art_blocks[mylist->part-1] = (char *)malloc(mylist->part_len+1);
- memcpy(playing_art_blocks[mylist->part-1], mylist->title, mylist->part_len);
- playing_art_parts++;
- playing_art_parts_total_len += mylist->part_len;
- // sanity check so we only try to get the metadata if all parts were processed
- if (playing_art_parts == mylist->total_parts)
- {
- free(uvox_artwork.uvox_playing_artwork);
- if (playing_art_parts_total_len <= 0) break;
- uvox_artwork.uvox_playing_artwork = (char *)malloc(playing_art_parts_total_len);
- uvox_artwork.uvox_playing_artwork[0] = 0;
- uvox_artwork.uvox_playing_artwork_len = playing_art_parts_total_len;
- uvox_artwork.uvox_playing_artwork_type = mylist->type;
- playing_art_parts = 0;
- char *art = uvox_artwork.uvox_playing_artwork;
- for(int i = 0; i < mylist->total_parts; i++)
- {
- int size = min(playing_art_parts_total_len, 16371);
- if (size > 0 && size <= 16371)
- {
- memcpy(art, playing_art_blocks[i], size);
- playing_art_parts_total_len -= size;
- art += size;
- }
- free(playing_art_blocks[i]);
- }
- free(playing_art_blocks);
- playing_art_blocks = 0;
- }
- LeaveCriticalSection(&streamInfoLock);
-
- if (g_playing_file)
- {
- PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
- }
- }
- break;
- }
- removeTitleListEntry(mylist);
- }
- }
- mylist = next;
- }
- }
- if (!no_peek_hack && peekBuffer.size())
- {
- *pcbRead = (int)peekBuffer.read(pBuffer, cbToRead);
- return NErr_Success;
- }
- BOOL bSuccess;
- if (m_is_stream)
- {
- if (m_connection)
- {
- char str[4096]={0};
- if (pcbRead) *pcbRead = 0;
- jnl_connection_run(m_connection, -1, -1, 0, 0);
- if (constate == 0)
- {
- if ( jnl_connection_receive_lines_available( m_connection ) > 0 )
- {
- char *p = str;
- jnl_connection_receive_line( m_connection, str, 4096 );
- // check http version and type of data, partial or full
- if ( strlen( str ) >= 13 && !_strnicmp( str, "HTTP/1.1", 8 ) )
- {
- char *p = str + 8; while ( p && *p == ' ' ) p++;
- m_http_response = ( p ? atoi( p ) : 0 );
- if ( m_http_response == 200 )
- m_seek_reset = true;
- }
- EnterCriticalSection( &g_lfnscs );
- lstrcpynA( lastfn_status, str, 256 );
- LeaveCriticalSection( &g_lfnscs );
- PostMessage( mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE );
- while ( p && *p && *p != ' ' ) p++;
- if ( p && *p ) p++;
- if ( p[ 0 ] == '2' ) constate = 1;
- else if ( strstr( p, "301" ) == p || strstr( p, "302" ) == p ||
- strstr( p, "303" ) == p || strstr( p, "307" ) == p )
- {
- constate = 69;
- }
- else if ( strstr( p, "401" ) == p && m_auth_tries++ < 3 )
- {
- constate = 75;
- }
- else if ( strstr( p, "403" ) == p )
- {
- EnterCriticalSection( &g_lfnscs );
- lstrcpynA( lastfn_status, "access denied", 256 );
- lastfn_status_err = 1;
- LeaveCriticalSection( &g_lfnscs );
- jnl_connection_close( m_connection, 1 );
- }
- else if ( strstr( p, "503" ) == p )
- {
- EnterCriticalSection( &g_lfnscs );
- lstrcpynA( lastfn_status, "server full", 256 );
- lastfn_status_err = 1;
- LeaveCriticalSection( &g_lfnscs );
- jnl_connection_close( m_connection, 1 );
- }
- else
- {
- lastfn_status_err = 1;
- jnl_connection_close( m_connection, 1 );
- }
- }
- 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 )
- {
- const char *t = jnl_connection_get_error( m_connection );
- if ( t && *t )
- {
- EnterCriticalSection( &g_lfnscs );
- lstrcpynA( lastfn_status, t, 256 );
- lastfn_status_err = 1;
- LeaveCriticalSection( &g_lfnscs );
- }
- PostMessage( mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE );
- }
- }
- if (constate == 75) // authorization required
- {
- while (jnl_connection_receive_lines_available(m_connection) > 0)
- {
- char *wwwa = "WWW-Authenticate:";
- jnl_connection_receive_line(m_connection, str, 4096);
- if (!str[0])
- {
- lastfn_status_err = 1; jnl_connection_close(m_connection, 1); break;
- }
- if (!_strnicmp(str, wwwa, strlen(wwwa)))
- {
- int has = 0;
- char *s2 = "Basic realm=\"";
- char *p = str + strlen(wwwa); while (p && *p == ' ') p++;
- if (!_strnicmp(p, s2, strlen(s2)))
- {
- p += strlen(s2);
- if (strstr(p, "\""))
- {
- if (p && *p)
- {
- strstr(p, "\"")[0] = 0;
- extern char *get_inifile();
- if (!force_lpinfo[0]) GetPrivateProfileStringA("HTTP-AUTH", p, "", force_lpinfo, sizeof(force_lpinfo), get_inifile());
- if (!force_lpinfo[0] || (lpinfo && lpinfo[0]))
- {
- lstrcpynA(dlg_realm, p, sizeof(dlg_realm));
- if (!WASABI_API_DIALOGBOXPARAM(IDD_HTTPAUTH, GetDialogBoxParent(), httpDlgProc, (LPARAM)this))
- {
- force_lpinfo[0] = 0;
- }
- else
- {
- WritePrivateProfileStringA("HTTP-AUTH", p, force_lpinfo, get_inifile());
- }
- }
- if (force_lpinfo[0])
- {
- jnl_connection_release(m_connection);
- m_connection = NULL;
- doConnect(NULL, 0);
- has = 1;
- }
- }
- }
- }
- if (!has)
- {
- lastfn_status_err = 1;
- jnl_connection_close(m_connection, 1);
- }
- break;
- }
- }
- }
- if (constate == 69) // redirect city
- {
- while (jnl_connection_receive_lines_available(m_connection) > 0)
- {
- jnl_connection_receive_line(m_connection, str, 4096);
- if (!str[0])
- {
- jnl_connection_close(m_connection, 1); break;
- }
- if (!_strnicmp(str, "Location:", 9))
- {
- char *p = str + 9; while (p && *p == ' ') p++;
- if (p && *p)
- {
- if (m_redircnt++ < MAX_REDIRECTS)
- {
- jnl_connection_release(m_connection);
- m_connection = NULL;
- doConnect(p, 0);
- }
- else
- {
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_REDIRECT_LIMIT_EXCEEDED,lastfn_status,256);
- lastfn_status_err = 1;
- LeaveCriticalSection(&g_lfnscs);
- jnl_connection_close(m_connection, 1);
- }
- break;
- }
- }
- }
- }
- if (constate == 1)
- {
- while (jnl_connection_receive_lines_available(m_connection) > 0)
- {
- jnl_connection_receive_line(m_connection, str, 4096);
- if (!str[0])
- {
- if (config_http_save_dir[0] && (config_miscopts&16))
- {
- if (!save_filename[0] && m_is_stream == 1 &&
- strlen(stream_title_save) > 4 &&
- !strstr(stream_title_save, "..") &&
- !strstr(stream_title_save, "\\") &&
- !strstr(stream_title_save, "/"))
- {
- lstrcpynA(save_filename, stream_title_save, 251);
- char *p = strstr(save_filename, ".mp");
- if (!p) p = strstr(save_filename, ".MP");
- if (!p) p = strstr(save_filename, ".mP");
- if (!p) p = strstr(save_filename, ".Mp");
- if (!p)
- {
- StringCchCatA(save_filename, 256, ".mp3");
- }
- else
- {
- while (p && *p && *p != ' ') p++;
- if (p) *p = 0;
- }
- }
- if (save_filename[0])
- {
- char buf[4096] = {0};
- StringCchPrintfA(buf, 4096, "%s%s%s", config_http_save_dir, config_http_save_dir[strlen(config_http_save_dir) - 1] == '\\' ? "" : "\\", save_filename);
- hFile = CreateFileA(buf, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- }
- }
- else save_filename[0] = 0;
- constate = meta_interval ? 4 : 2;
- break;
- }
- // check if stream is seekable
- if (strlen(str) >= 14 && !_strnicmp(str, "Accept-Ranges:", 14))
- {
- m_is_stream_seekable = true;
- }
- if (!_strnicmp(str, "Content-Length:", 15))
- {
- char *p = str + 15; while (p && *p == ' ') p++;
- if (!is_stream_seek)
- mpeg_length = atoi(p);
- m_is_stream_seekable = true;
- }
- if (!_strnicmp(str, "content-type:", 13))
- {
- char *p = str + 13; while (p && *p == ' ') p++;
- free(m_content_type);
- m_content_type = _strdup(p);
- if (!_strnicmp(m_content_type, "misc/ultravox",13))
- {
- stream_title_save[0] = 0;
- stream_name[0]=0;
- g_stream_title[0] = 0;
- is_uvox = 1;
- // TODO get this to id as SC2 stream if possible...
- m_is_stream = 3;
- }
- }
- if (!_strnicmp(str, "Server:", 7))
- {
- char *p = str + 7; while (p && *p == ' ') p++;
- lstrcpynA(server_name, p, sizeof(server_name));
- }
- if (!_strnicmp(str, "ultravox-max-msg:", 17))
- {
- char *p = str + 17; while (p && *p == ' ') p++;
- uvox_maxmsg = (p ? atoi(p) : 0);
- 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
- uvox_maxmsg = UVOX_MAXMSG_CAP;
- m_is_stream = 3;
- }
- else if (!_strnicmp(str, "Ultravox-SID:", 13))
- {
- char *p = str + 13; while (p && *p == ' ') p++;
- uvox_sid = (p ? atoi(p) : 0);
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-Avg-Bitrate:", 21))
- {
- char *p = str + 21; while (p && *p == ' ') p++;
- uvox_avgbr = (p ? atoi(p) : 0);
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-Max-Bitrate:", 21))
- {
- char *p = str + 21; while (p && *p == ' ') p++;
- uvox_maxbr = (p ? atoi(p) : 0);
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-Bitrate:", 17))
- {
- char *p = str + 17; while (p && *p == ' ') p++;
- uvox_avgbr = uvox_maxbr = (p ? atoi(p) : 0);
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-Title:", 15))
- {
- char *p = str + 15; while (p && *p == ' ') p++;
- lstrcpynA(stream_title_save, p, 580);
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-Genre:", 15))
- {
- char *p = str + 15; while (p && *p == ' ') p++;
- lstrcpynA(stream_genre, p, sizeof(stream_genre));
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-URL:", 13)/* && !strstr(str, "shoutcast.com")*/)
- {
- char *p = str + 13; while (p && *p == ' ') p++;
- lstrcpynA(stream_url, p, sizeof(stream_url));
- DWORD_PTR dw = 0;
- if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, IPC_MBOPEN, SMTO_NORMAL, 500, &dw);
- m_is_stream = 3;
- }
- if (!_strnicmp(str, "Ultravox-Class-Type:", 19))
- {
- // id our stream for 'streamtype'
- // added for 5.63 as is a better way to check for
- // a SC2/UVOX2.1 stream when no metadata is sent
- m_is_stream = 5;
- }
- if (!_strnicmp(str, "icy-notice2:", 12))
- {
- char *p = str + 12; while (p && *p == ' ') p++;
- char *p2 = (p ? strstr(p, "<BR>") : 0);
- if (p2)
- {
- *p2 = 0;
- lstrcpynA(server_name, p, sizeof(server_name));
- }
- m_is_stream=2;
- }
- if (!_strnicmp(str, "content-disposition:", 20))
- {
- if (strstr(str, "filename="))
- lstrcpynA(g_stream_title, strstr(str, "filename=") + 9, sizeof(g_stream_title));
- lstrcpynA(stream_title_save, g_stream_title, 580);
- }
- if (!_strnicmp(str, "icy-name:", 9))
- {
- char *p = str + 9; while (p && *p == ' ') p++;
- lstrcpynA(g_stream_title, p, sizeof(g_stream_title));
- lstrcpynA(stream_title_save, g_stream_title, 580);
- lstrcpynA(stream_name, g_stream_title, 256);
- // 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
- }
- if (!_strnicmp(str, "icy-metaint:", 12))
- {
- char *p = str + 12; while (p && *p == ' ') p++;
- meta_interval = (p ? atoi(p) : 0);
- m_is_stream = 2;
- }
- if (!_strnicmp(str, "icy-genre:", 10))
- {
- char *p = str + 10; while (p && *p == ' ') p++;
- lstrcpynA(stream_genre, p, sizeof(stream_genre));
- m_is_stream = 2;
- }
- if (!_strnicmp(str, "icy-url:", 8) && !strstr(str, "shoutcast.com"))
- {
- char *p = str + 8; while (p && *p == ' ') p++;
- lstrcpynA(stream_url, p, sizeof(stream_url));
- //if (!strncmp(stream_url,"hTtP",4))
- //{
- // DWORD dw;
- // SendMessageTimeout(mod.hMainWindow,WM_USER,(WPARAM)0,241,SMTO_NORMAL,500,&dw);
- //} // Removed by Tag, Annoying.
- DWORD_PTR dw = 0;
- if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, IPC_MBOPEN, SMTO_NORMAL, 500, &dw);
- m_is_stream = 2;
- }
- }
- }
- if (constate == 2) // check for id3v2
- {
- if (jnl_connection_receive_bytes_available(m_connection) >= 10)
- {
- char buf[10]={0};
- constate = 4;
- jnl_connection_peek(m_connection, buf, 10);
- if (buf[0] == 'I'
- && buf[1] == 'D'
- && buf[2] == '3'
- && buf[3] != 255
- && buf[4] != 255
- && buf[6] < 0x80
- && buf[7] < 0x80
- && buf[8] < 0x80
- && buf[9] < 0x80)
- {
- jnl_connection_receive(m_connection, buf, 10);
- m_id3v2_len = 10;
- if (buf[5] & 0x10) // check for footer flag
- m_id3v2_len += 10;
- m_id3v2_len += ((int)buf[6]) << 21;
- m_id3v2_len += ((int)buf[7]) << 14;
- m_id3v2_len += ((int)buf[8]) << 7;
- m_id3v2_len += ((int)buf[9]);
- if (m_id3v2_len < 0) m_id3v2_len = 0;
- if (mpeg_length && m_id3v2_len > mpeg_length)
- {
- m_id3v2_len = 0;
- }
- if (m_id3v2_len)
- {
- constate = 3;
- stream_id3v2_read = 0;
- if (m_id3v2_len < 16*1024*1024)
- {
- stream_id3v2_buf = (char*)malloc(10 + m_id3v2_len);
- stream_id3v2_read = 10;
- memcpy(stream_id3v2_buf, buf, 10);
- }
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_READING_ID3,lastfn_status,256);
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- }
- }
- }
- if (constate == 3) // id3v2 found
- {
- while ((int)stream_id3v2_read < m_id3v2_len)
- {
- char buf[1024]={0};
- int btoread = m_id3v2_len - stream_id3v2_read;
- if (btoread > sizeof(buf)) btoread = sizeof(buf);
- int avail = (int)jnl_connection_receive_bytes_available(m_connection);
- if (btoread > avail) btoread = avail;
- if (!btoread) break;
- if (stream_id3v2_buf)
- stream_id3v2_read += (uint32_t)jnl_connection_receive(m_connection, stream_id3v2_buf + stream_id3v2_read, btoread);
- else
- stream_id3v2_read += (uint32_t)jnl_connection_receive(m_connection, buf, btoread);
- //stream_id3v2_read+=m_connection->ReceiveBytes(0,btoread);
- }
- if ((int)stream_id3v2_read >= m_id3v2_len)
- {
- if (stream_id3v2_buf)
- {
- if (m_is_stream_seekable /*m_is_stream != 2*/) /* don't want to do id3v2 on an internet stream */
- {
- EnterCriticalSection(&streamInfoLock);
- info.Decode(stream_id3v2_buf, stream_id3v2_read);
- // TODO: streamInfo = info;
- LeaveCriticalSection(&streamInfoLock);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- }
- constate = 4;
- }
- }
- if (constate == 4) // check for xing header
- {
- if (GetContentLength() < 1 || is_stream_seek) constate = 5;
- else
- {
- int avail = (int)jnl_connection_receive_bytes_available(m_connection);
- if (avail > 4096 || jnl_connection_get_state(m_connection) == JNL_CONNECTION_STATE_CLOSED)
- {
- char buf[4096]={0};
- jnl_connection_peek(m_connection, buf, sizeof(buf));
- constate++;
- {
- delete m_vbr_hdr;
- m_vbr_hdr = 0;
- LAMEinfo lame;
- lame.toc = m_vbr_toc;
- m_vbr_frame_len = ReadLAMEinfo((unsigned char *)buf, &lame);
- if (m_vbr_frame_len)
- {
- prepad = lame.encoderDelay;
- postpad = lame.padding;
- if (lame.flags&TOC_FLAG)
- {
- int x;
- for (x = 0; x < 100; x++)
- if (m_vbr_toc[x]) break;
- if (x != 100)
- m_vbr_flag = 1;
- }
- if (lame.flags&FRAMES_FLAG)
- {
- m_vbr_frames = lame.frames;
- m_vbr_samples = Int32x32To64(lame.frames, lame.h_id ? 1152 : 576);
- m_vbr_samples -= (prepad + postpad);
- m_vbr_ms = MulDiv((int)m_vbr_samples, 1000, lame.samprate);
- }
- if (!m_vbr_frames) m_vbr_flag = 0;
- jnl_connection_receive(m_connection, buf, m_vbr_frame_len);
- }
- else
- {
- m_vbr_hdr = new CVbriHeader;
- m_vbr_frame_len = m_vbr_hdr->readVbriHeader((unsigned char *)buf);
- if (m_vbr_frame_len)
- {
- m_vbr_bytes = m_vbr_hdr->getBytes();
- m_vbr_frames = m_vbr_hdr->getNumFrames();
- m_vbr_ms = m_vbr_hdr->getNumMS();
- }
- else
- {
- delete m_vbr_hdr;
- m_vbr_hdr = 0;
- }
- }
- }
- // TODO OFL
- }
- }
- }
- if (constate == 5) // time to stream
- {
- while (1)
- {
- // Process any timed titles
- int len = (int)jnl_connection_receive_bytes_available(m_connection);
- if (meta_interval && meta_pos >= meta_interval)
- {
- unsigned char b;
- if (len > 0 && jnl_connection_peek(m_connection, (char*)&b, 1) && len > (b << 4))
- {
- char metabuf[4096]={0};
- jnl_connection_receive(m_connection, metabuf, 1);
- jnl_connection_receive(m_connection, metabuf, b << 4);
- processMetaData(metabuf, b << 4);
- stream_metabytes_read += (b << 4) + 1;
- meta_pos = 0;
- }
- else break;
- }
- else if (is_uvox)
- {
- if (!uvox_stream_data)
- {
- /* benski> this was a security vulnerability.
- don't blindly multiply by 2 and pass to malloc
- if uvox_maxmsg happens to be 2^31, multiplying by 2 turns it into 0!
- CUT!!! uvox_stream_data = (unsigned char*)malloc(uvox_maxmsg * 2 + 4096);
- */
- uvox_stream_data = (unsigned char*)malloc(SAFE_MALLOC_MATH(uvox_maxmsg * 2 + 4096, uvox_maxmsg));
- }
- if (uvox_stream_data_len < 1)
- {
- again:
- if (len < 6) break;
- jnl_connection_peek(m_connection, (char*)uvox_stream_data, 6);
- int uvox_qos = uvox_stream_data[1];
- int classtype = (uvox_stream_data[2] << 8) | uvox_stream_data[3];
- int uvox_len = (uvox_stream_data[4] << 8) | uvox_stream_data[5];
- int uvox_class = (classtype >> 12) & 0xF;
- int uvox_type = classtype & 0xFFF;
- if (uvox_stream_data[0] != 0x5A || uvox_len > uvox_maxmsg)
- {
- jnl_connection_receive(m_connection, NULL, 1);
- len--;
- uvox_desyncs++;
- goto again;
- }
- if (uvox_len + 7 > len) break;
- // process uvox chunk
- jnl_connection_peek(m_connection, (char*)uvox_stream_data, 6 + uvox_len + 1);
- if (uvox_stream_data[6 + uvox_len])
- {
- jnl_connection_receive(m_connection, NULL, 1);
- uvox_desyncs++;
- len--;
- goto again;
- }
- else if (uvox_class == 0x2 && uvox_type == 0x003)
- {
- // failover gayness
- }
- else if (uvox_class == 0x2 && uvox_type == 0x002)
- {
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_STREAM_TERMINATED,lastfn_status,256);
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- jnl_connection_close(m_connection, 0);
- }
- else if (uvox_class == 0x2 && uvox_type == 0x001)
- {
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_STREAM_TEMPORARILY_INTERRUPTED,lastfn_status,256);
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- }
- else if (uvox_class == 0x3 && (uvox_type == 0x902 || uvox_type == 0x901)) // SHOUTcast 2 metadata
- {
- // id our stream for 'streamtype'
- m_is_stream = 5;
- // this will allow us to cope with multi-packet metadata messages
- // (used to be needed when the old SC2 spec used an APIC tag to
- // to send the artwork in the metadata message - now it's sent in
- // in the uvox_class == 0x4 messages for stream and playing cases)
- if (!uvox_stream_data[8])
- {
- char *mbuf = (char*)uvox_stream_data + 12;
- if (mbuf)
- {
- unsigned long delay = 0;
- if (uvox_avgbr)
- {
- long byterate = (uvox_avgbr / 8);
- long bytes = 1024 * 11;
- float localdelay = (float)bytes / (float)byterate;
- delay = (long)localdelay * 1000;
- }
- // make sure that we've got a packet which is within the specs
- // as id can only be 1-32, total parts can only be 1-32,
- // id cannot be more than total parts and if not then skip it.
- if(uvox_stream_data[11] < 1 || uvox_stream_data[11] > 32 ||
- uvox_stream_data[11] > uvox_stream_data[9] ||
- uvox_stream_data[9] < 1 || uvox_stream_data[9] > 32)
- {
- break;
- }
- TITLELISTTYPE *newtitle = newTitleListEntry();
- newtitle->style = (uvox_type == 0x902 ? UVOX_METADATA_STYLE_SHOUTCAST2 : UVOX_METADATA_STYLE_AOLRADIO);
- // we make sure to only copy up to the maximum metadata payload size
- newtitle->part_len = min((uvox_len - 6), 16371);
- memcpy(newtitle->title, mbuf, newtitle->part_len);
- newtitle->part = uvox_stream_data[11];
- newtitle->total_parts = uvox_stream_data[9];
- newtitle->timer = (stream_bytes_read && mod.outMod ? delay + mod.outMod->GetOutputTime() : 0);
- }
- }
- }
- else if (uvox_class == 0x4) // SHOUTcast 2 albumart
- {
- if (allow_scartwork && !uvox_stream_data[8])
- {
- char *mbuf = (char*)uvox_stream_data + 12;
- if (mbuf)
- {
- // [0x4] [0|1] [00|01|02|03]
- unsigned long delay = 0;
- if (uvox_avgbr)
- {
- long byterate = (uvox_avgbr / 8);
- long bytes = 1024 * 11;
- float localdelay = (float)bytes / (float)byterate;
- delay = (long)localdelay * 1000;
- }
- // make sure that we've got a packet which is within the specs
- // as id can only be 1-32, total parts can only be 1-32,
- // id cannot be more than total parts and if not then skip it.
- if(uvox_stream_data[11] < 1 || uvox_stream_data[11] > 32 ||
- uvox_stream_data[11] > uvox_stream_data[9] ||
- uvox_stream_data[9] < 1 || uvox_stream_data[9] > 32)
- {
- break;
- }
- TITLELISTTYPE *newtitle = newTitleListEntry();
- newtitle->style = (uvox_type & 0x100 ? UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK_PLAYING : UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK);
- // we make sure to only copy up to the maximum metadata payload size
- newtitle->part_len = min((uvox_len - 6), 16371);
- memcpy(newtitle->title, mbuf, newtitle->part_len);
- newtitle->part = uvox_stream_data[11];
- newtitle->total_parts = uvox_stream_data[9];
- newtitle->type = (uvox_type & 0x00FF);
- newtitle->timer = (stream_bytes_read && mod.outMod ? delay + mod.outMod->GetOutputTime() : 0);
- }
- }
- }
- else if (uvox_class == 0x3 && (uvox_type == 0x001 || uvox_type == 0x002))
- {
- int w = uvox_type - 1; // should be ID?
- int n = (uvox_stream_data[8] << 8) | uvox_stream_data[9];
- if (n && n < 33)
- {
- int t = (uvox_stream_data[10] << 8) | uvox_stream_data[11];
- if (t && t <= n)
- {
- int l = 0;
- int a;
- char *p = (char*)uvox_stream_data + 12; // this almost works
- free(uvox_meta[w][t - 1]);
- uvox_meta[w][t - 1] = _strdup(p);
- for (a = 0;a < n;a++)
- {
- if (!uvox_meta[w][a]) break;
- l += (int)strlen(uvox_meta[w][a]);
- }
- if (a == n)
- {
- char *outtext = (char*)malloc(l + 1);
- p = outtext;
- for (a = 0;a < n;a++)
- {
- lstrcpynA(p, uvox_meta[w][a], l + 1);
- free(uvox_meta[w][a]);
- uvox_meta[w][a] = 0;
- p += strlen(p);
- }
- processMetaData(outtext, l + 1);
- free(outtext);
- }
- }
- }
- }
- else if ((uvox_class == 0x7 && (uvox_type == 0x0 || uvox_type == 0x1))
- || (uvox_class == 0x8 && (uvox_type == 0x0 || uvox_type == 0x1 || uvox_type == 0x3)))
- {
- memcpy(uvox_stream_data, uvox_stream_data + 6, uvox_len);
- uvox_stream_data_len = uvox_len;
- uvox_last_message = uvox_class << 12 | uvox_type;
- }
- jnl_connection_receive(m_connection, NULL, 6 + uvox_len + 1);
- uvox_message_cnt++;
- }
- if (uvox_stream_data_len > 0)
- {
- len = min(cbToRead, uvox_stream_data_len);
- memcpy(pBuffer, uvox_stream_data, len);
- if (pcbRead) *pcbRead = len;
- stream_bytes_read += len;
- if (len < uvox_stream_data_len)
- {
- memcpy(uvox_stream_data, uvox_stream_data + len, uvox_stream_data_len - len);
- }
- uvox_stream_data_len -= len;
- break;
- }
- }
- else
- {
- len = min(cbToRead, len);
- if (meta_interval) len = min(meta_interval - meta_pos, len);
- if (len > 0)
- {
- DWORD dw = 0;
- len = (int)jnl_connection_receive(m_connection, (char*)pBuffer, len);
- if (hFile != INVALID_HANDLE_VALUE) WriteFile(hFile, pBuffer, len, &dw, NULL);
- if (pcbRead) *pcbRead = len;
- meta_pos += len;
- stream_bytes_read += len;
- }
- else if (pcbRead) *pcbRead = 0;
- break;
- }
- }
- }
- int state = m_connection ? jnl_connection_get_state(m_connection) : JNL_CONNECTION_STATE_CLOSED;
- if (state == JNL_CONNECTION_STATE_ERROR || state == JNL_CONNECTION_STATE_CLOSED)
- {
- if ((!pcbRead || !*pcbRead) && (!m_connection || jnl_connection_receive_bytes_available(m_connection) < 1))
- {
- fEof = 1;
- return NErr_Error;
- }
- }
- else if (constate != 5 && constate != 4 && constate != 3 && timeout_start + 15000 < GetTickCount()) // 15 second net connect timeout
- {
- EnterCriticalSection(&g_lfnscs);
- WASABI_API_LNGSTRING_BUF(IDS_TIMED_OUT,lastfn_status,256);
- lastfn_status_err = 1;
- LeaveCriticalSection(&g_lfnscs);
- PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
- fEof = 1;
- return NErr_Error;
- }
- return NErr_Success;
- }
- return NErr_Error;
- }
- else if (m_full_buffer)
- {
- int len = cbToRead;
- if ((uint64_t)len > (mpeg_length - m_full_buffer_pos))
- {
- len = (int)(mpeg_length - m_full_buffer_pos);
- }
- if (pcbRead) *pcbRead = len;
- if (len)
- {
- memcpy(pBuffer, m_full_buffer + m_full_buffer_pos, len);
- m_full_buffer_pos += len;
- }
- else
- {
- fEof = true;
- return NErr_EndOfFile;
- }
- return NErr_Success;
- }
- else
- {
- if (hFile != INVALID_HANDLE_VALUE)
- {
- if ((uint64_t)cbToRead >= (mpeg_length - file_position))
- {
- cbToRead = (int)(mpeg_length - file_position);
- fEof = true;
- }
- if (cbToRead == 0)
- {
- if (pcbRead)
- *pcbRead = 0;
- return NErr_Success;
- }
- DWORD dwRead = 0;
- bSuccess = ReadFile(hFile, pBuffer, cbToRead, &dwRead, NULL);
- if (bSuccess)
- {
- file_position += dwRead;
- // update pcbRead
- if (pcbRead)
- *pcbRead = dwRead;
- // check for EOF
- if (dwRead == 0)
- fEof = true;
- return NErr_Success;
- }
- else
- {
- // error reading from file
- return NErr_Error;
- }
- }
- else
- {
- // no valid file handle
- return NErr_Error;
- }
- }
- }
- //-------------------------------------------------------------------------*
- // IsEof
- //-------------------------------------------------------------------------*
- bool CGioFile::IsEof() const
- {
- return fEof;
- }
- //-------------------------------------------------------------------------*
- // GetContentLength
- //-------------------------------------------------------------------------*
- DWORD CGioFile::GetContentLength(void) const
- {
- DWORD dwSize = 0 ;
- dwSize = (DWORD)mpeg_length;
- return dwSize ;
- }
- //-------------------------------------------------------------------------*
- // GetCurrentPosition
- //-------------------------------------------------------------------------*
- DWORD CGioFile::GetCurrentPosition(void) const
- {
- DWORD dwPos = 0;
- if (m_is_stream)
- {
- dwPos = (DWORD)stream_bytes_read;
- }
- else if (m_full_buffer)
- {
- dwPos = (DWORD)m_full_buffer_pos;
- }
- else if (hFile != INVALID_HANDLE_VALUE)
- {
- dwPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
- dwPos -= (DWORD)(mpeg_position + peekBuffer.size());
- }
- return dwPos ;
- }
- //-------------------------------------------------------------------------*
- // SetCurrentPosition
- //-------------------------------------------------------------------------*
- void CGioFile::SetCurrentPosition(long dwPos, int How) // GIO_FILE_BEGIN only
- {
- fEof = false;
- if (m_full_buffer)
- {
- m_full_buffer_pos = dwPos;
- if (m_full_buffer_pos < 0) m_full_buffer_pos = 0;
- if (m_full_buffer_pos > mpeg_length) m_full_buffer_pos = mpeg_length;
- }
- else if (hFile != INVALID_HANDLE_VALUE)
- {
- Seek64(hFile, mpeg_position + dwPos, FILE_BEGIN);
- file_position = dwPos;
- peekBuffer.clear();
- }
- }
- int CGioFile::GetHeaderOffset()
- {
- return (int)mpeg_position;
- }
- /*-------------------------------------------------------------------------*/
- void CGioFile::Seek(int posms, int br)
- {
- int offs = 0;
- if (m_vbr_hdr)
- {
- offs = m_vbr_hdr->seekPointByTime((float)posms);
- }
- else if (!m_vbr_flag)
- offs = MulDiv(posms, br, 8);
- else
- {
- int ms = 0;
- int fl = GetContentLength();
- if (!m_vbr_frames)
- {
- ms = MulDiv(fl, 8 * 1000, br);
- }
- else ms = m_vbr_ms;
- offs = SeekPoint(m_vbr_toc, fl, (float)posms / ((float)ms / 100.0f));
- }
- if (m_is_stream)
- {
- if (GetContentLength() > 0)
- {
- if (m_connection && m_is_stream_seekable)
- {
- jnl_connection_release(m_connection);
- m_connection = NULL;
- m_is_stream_seek = true;
- m_seek_reset = false;
- doConnect(NULL, offs);
- }
- }
- }
- else
- {
- SetCurrentPosition(offs, GIO_FILE_BEGIN);
- }
- }
- bool CGioFile::IsSeekable()
- {
- return !m_is_stream || GetContentLength() > 0;
- }
- void CGioFile::GetStreamInfo(wchar_t *obuf, size_t len)
- {
- if (m_is_stream)
- {
- wchar_t langbuf[2048]={0};
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_NETWORK_RECEIVED_X_BYTES, langbuf, 2048), stream_bytes_read + stream_metabytes_read);
- if (server_name[0])
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_SERVER, langbuf, 2048), AutoWide(server_name,CP_UTF8));
- if (m_content_type && m_content_type[0])
- {
- if(is_uvox)
- {
- // report the actual content type instead of just misc/ultravox to make it easier to see what the stream type is (helps debugging)
- static const int MP3_DATA = 0x7000;
- static const int VLB_DATA = 0x8000;
- static const int AAC_LC_DATA = 0x8001;
- static const int AACP_DATA = 0x8003;
- static const int OGG_DATA = 0x8004;
- switch(uvox_last_message)
- {
- case MP3_DATA:
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/mpeg");
- break;
- case VLB_DATA:
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/vlb");
- break;
- case AAC_LC_DATA:
- case AACP_DATA:
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/aacp");
- break;
- case OGG_DATA:
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), L"audio/ogg");
- break;
- default:
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), AutoWide(m_content_type,CP_UTF8));
- break;
- }
- }
- else
- {
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_TYPE, langbuf, 2048), AutoWide(m_content_type,CP_UTF8));
- }
- }
- if (is_uvox)
- {
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ULTRAVOX_SYNC, langbuf, 2048), uvox_message_cnt, uvox_desyncs);
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ULTRAVOX_DATA_MESSAGE, langbuf, 2048), uvox_last_message);
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ULTRAVOX_SID_AVGBR_MAXBR, langbuf, 2048), uvox_sid, uvox_avgbr, uvox_maxbr);
- }
- if (stream_metabytes_read)
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_METADATA_RECEIVED, langbuf, 2048), stream_metabytes_read);
- if (meta_interval)
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_METADATA_INTERVAL, langbuf, 2048), meta_interval);
- if (m_id3v2_len)
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ID3v2_TAG, langbuf, 2048), m_id3v2_len);
- if (m_vbr_frame_len)
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_VBR_LEADING_FRAME, langbuf, 2048), m_vbr_frame_len);
- if (stream_title_save[0])
- {
- wchar_t name[580]={0};
- ConvertTryUTF8(stream_title_save, name, 580);
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_STREAM_NAME, langbuf, 2048), name/*AutoWide(stream_title_save,CP_UTF8)*/);
- }
- if (last_title_sent[0])
- {
- wchar_t title[256]={0};
- ConvertTryUTF8(last_title_sent, title, 256);
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CURRENT_TITLE, langbuf, 2048), title);
- }
- if (mpeg_length)
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_CONTENT_LENGTH, langbuf, 2048), mpeg_length);
- if (save_filename[0] && hFile != INVALID_HANDLE_VALUE)
- StringCchPrintfEx(obuf, len, &obuf, &len, 0, WASABI_API_LNGSTRINGW_BUF(IDS_SAVING_TO, langbuf, 2048), AutoWide(save_filename,CP_UTF8));
- }
- }
- static inline const wchar_t *IncSafe(const wchar_t *val, int x)
- {
- while (x--)
- {
- if (val && *val)
- val++;
- }
- return val;
- }
- void CGioFile::ReadiTunesGaps()
- {
- if (info.HasData() && !prepad && !postpad)
- {
- wchar_t str[128] = {0};
- if (info.GetString("pregap", str, 128) == 1)
- prepad = _wtoi(str);
- str[0]=0;
- if (info.GetString("postgap", str, 128) == 1)
- postpad = _wtoi(str);
- }
- }
- #define CBCLASS CGioFile
- START_DISPATCH;
- CB( MPEGSTREAM_PEEK, Peek )
- CB( MPEGSTREAM_READ, Read )
- CB( MPEGSTREAM_EOF, EndOf )
- CB( MPEGSTREAM_GAIN, GetGain )
- END_DISPATCH;
- #undef CBCLASS
|