12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136 |
- /** (c) Nullsoft, Inc. C O N F I D E N T I A L
- ** Filename:
- ** Project:
- ** Description: Utility functions for handling language support
- ** Author:
- ** Created:
- **/
- #include <locale.h>
- #include "main.h"
- #include "language.h"
- #include "../nu/AutoWide.h"
- #include "../nu/AutoChar.h"
- #include "minizip/unzip.h"
- #include <vector>
- #include "../nu/AutoCharFn.h"
- typedef struct {
- wchar_t *module;
- wchar_t *guidstr; // generally is 0 or 39 (38+null)
- int guid;
- int external;
- HINSTANCE hDllInstance;
- } winampLangStruct;
- static std::vector<winampLangStruct*> lnglist;
- int already_extracted = 0, prev_wlz_ex_state = 0, geno = 1, started = 0;
- // data storage of the read in values requires just the hash and the id to be stored
- // and has to be logged against the different id types so just need a list of structs
- // based against each type (dialog, string resource, etc)
- // for the moment we deal with the following resource types
- // RT_DIALOG, RT_MENU, RT_STRING & custom resources
- // so for initial implementation we only need to store upto 4 hash+id lists
- #if 0
- typedef struct {
- int id;
- char id_str[32];
- char hash[17];
- char str[64];
- } hashstruct;
- std::vector<hashstruct*> dialogList;
- std::vector<hashstruct*> menuList;
- std::vector<hashstruct*> stringList; // will be the largest of the lot
- std::vector<hashstruct*> customList; // should be very few of this
- #endif
- // have section header (text or int id)
- // then the hash and then the id that's related the hash eg the dialog resource id
- void ReadHashFileDetails(char* data, DWORD datalen)
- {
- #if 0
- char* p = data, *s = p, *t = 0, *u;
- while(s && *s)
- {
- // is it the start of a block that we've just gotten to...
- if(*s == '@' || *s == '#')
- {
- int id = -1;
- char id_str[32] = {0};
- u = s = CharNext(s);
- if(!*s){break;}
- // advance to the end of the line to get the block identifier
- // would need to use the @ or # to process the type used
- // ie if a type 5 then only use on dialog loading calls
- while(u && *u && *u != '\n'){u = CharNext(u);}
- if(*u == '\n'){u = CharNext(u);*CharPrev(p,u) = 0;}
- if(!*u){break;}
- // identifier of the block is found here :)
- if(*s)
- {
- id = atoi(s);
- if(!id)
- {
- lstrcpyn(id_str, s, sizeof(id_str));
- }
- }
- *CharPrev(p,u) = '\n';
- while(s && *s && (*s != '@' && *s != '#'))
- {
- int end = 0;
- while(s && *s && *s != '\n'){s = CharNext(s);}
- if(*s == '\n'){s = CharNext(s);}
- // if nothing else then need to abort (since we don't want to do bad things)
- // and have to take into account where in the buffer we are otherwise we can
- // end up going into the next part of the dll/exe resource data due to how
- // it is all stored/handled in them (ie butted up against each other)
- if(!*s || s >= p+datalen){break;}
- t = s;
- // do a check after we've advanced to the start of a new line
- // so that we can see if we've hit a new resource type block
- if(*s == '@' || *s == '#')
- {
- s = CharPrev(p,s);
- break;
- }
- // scan through to the start of the second part of the <hash:id> block
- while(t && *t && *t != ':')
- {
- t = CharNext(t);
- }
- if(*t == ':')
- {
- t = CharNext(t);
- *CharPrev(p,t) = 0;
- }
- // scan through to the end of the line so that we then have the id
- u = t;
- while(u && *u && *u != '\n')
- {
- u = CharNext(u);
- }
- if(*u == '\n')
- {
- u = CharNext(u);
- *CharPrev(p,u) = 0;
- }
- // hash and identifier of the entry is found here :)
- // -> need to check how it works with IDD_CRASHDLG$()
- if(*s)
- {
- hashstruct* tempList = reinterpret_cast<hashstruct*>(calloc(1, sizeof(hashstruct)));
- ZeroMemory(tempList,sizeof(hashstruct));
- /*if(*t == 1) wsprintf(a,"%s %d (%s)\n", s, *t, t+1);
- else wsprintf(a,"%s %s (%d)\n", s, t+1, *t);*/
- if(*t == 1) // int_id
- lstrcpyn(tempList->str, t+1, sizeof(tempList->str));
- else // string_id
- lstrcpyn(tempList->str, t+1, *t/*sizeof(tempList->str)*/);
- lstrcpyn(tempList->hash, s, sizeof(tempList->hash));
- if(id) tempList->id = id;
- switch(id)
- {
- case RT_MENU:
- {
- menuList.push_back(tempList);
- }
- break;
- case RT_DIALOG:
- {
- dialogList.push_back(tempList);
- }
- break;
- case RT_STRING:
- {
- stringList.push_back(tempList);
- }
- break;
- default:
- // only do if there's no id from atoi (indicates a custom resource id)
- if(!id)
- {
- lstrcpyn(tempList->id_str, id_str, sizeof(tempList->id_str));
- customList.push_back(tempList);
- }
- break;
- }
- {
- char zz[100] = {0};
- StringCchPrintf(zz,100,"ID: '%s' %d\t%s %s\n",
- tempList->id_str, tempList->id,
- tempList->hash, tempList->str);
- OutputDebugString(zz);
- }
- }
- *CharPrev(p,u) = '\n';
- s = CharPrev(p,u);
- }
- }
- s = CharNext(s);
- }
- #endif
- }
- int GetImageHashData(HINSTANCE imageInstance)
- {
- DWORD datalen = 0;
- void* data = langManager->LoadResourceFromFile(imageInstance,imageInstance,L"HASH",L"HASH",&datalen);
- ReadHashFileDetails((char*)data,datalen);
- UnlockResource(data);
- FreeResource(data);
- return 0;
- }
- #ifdef _DEBUG
- static void CheckLangThread()
- {
- if (mainThreadId != GetCurrentThreadId())
- {
- // DebugBreak();
- /**
- ** If you hit this breakpoint, it's because you tried to use WASABI_API_LANG->GetString on another thread,
- ** without supplying your own buffer.
- ** You really don't want to be doing that.
- ** Hit alt+7, check what function is calling GetString/GetStringW and go fix it.
- ** Now.
- **/
- }
- }
- #else
- #define CheckLangThread()
- #endif
- char *getString(UINT uID, char *str, size_t maxlen)
- {
- return langManager->GetString(language_pack_instance,hMainInstance, uID, str, maxlen);
- }
- int LPMessageBox(HWND parent, UINT idMessage, UINT idTitle, UINT type)
- {
- wchar_t message[32768] = {0};
- wchar_t title[256] = {0};
- // TODO consider exposing something in the winamp.lng file so we can follow this where possible as it should allow for a localised messagebox as long as the OS supports the language
- // return MessageBoxExW(parent,getStringW(idMessage,message,32768),getStringW(idTitle,title,256),type,MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH));
- return MessageBoxW(parent,getStringW(idMessage,message,32768),getStringW(idTitle,title,256),type);
- }
- char* Language::GetString(HINSTANCE hinst, HINSTANCE owner, UINT uID, char *str, size_t maxlen)
- {
- __declspec(thread) static char *buf;
- if (!str)
- {
- CheckLangThread();
- if (!buf)
- buf = (char *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
- str = buf;
- maxlen = LANG_STATIC_BUFFER_SIZE;
- }
- // sometimes we need to ignore things i.e. accessing on closing, etc
- if (((unsigned long)str >= 65536) && !LoadStringA((started ? hinst : owner), uID, str, (int)maxlen))
- {
- if (hinst == owner || !LoadStringA(owner, uID, str, (int)maxlen))
- {
- lstrcpynA(str, "Error loading string", (int)maxlen);
- }
- }
- return str;
- }
- wchar_t *getStringW(UINT uID, wchar_t *str, size_t maxlen)
- {
- return langManager->GetStringW(language_pack_instance,hMainInstance, uID, str, maxlen);
- }
- wchar_t* Language::GetStringW(HINSTANCE hinst, HINSTANCE owner, UINT uID, wchar_t *str, size_t maxlen)
- {
- __declspec(thread) static wchar_t *buf;
- if (!str)
- {
- CheckLangThread();
- if (!buf)
- buf = (wchar_t *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
- str = buf;
- maxlen = LANG_STATIC_BUFFER_SIZE;
- }
- // sometimes we need to ignore things i.e. accessing on closing, etc
- if (((unsigned long)str >= 65536) && !LoadStringW((started ? hinst : owner), uID, str, (int)maxlen))
- {
- if (hinst == owner || !LoadStringW(owner, uID, str, (int)maxlen))
- {
- lstrcpynW(str, L"Error loading string", (int)maxlen);
- }
- }
- return str;
- }
- char* Language::GetStringFromGUID(const GUID guid, HINSTANCE owner, UINT uID, char *str, size_t maxlen)
- {
- __declspec(thread) static char *buf;
- if (!str)
- {
- CheckLangThread();
- if (!buf)
- buf = (char *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
- str = buf;
- maxlen = LANG_STATIC_BUFFER_SIZE;
- }
- HINSTANCE tl = FindDllHandleByGUID(guid);
- if(!tl) tl = owner;
- // sometimes we need to ignore things i.e. accessing on closing, etc
- if (((unsigned long)str >= 65536) && !LoadStringA((started ? tl : owner), uID, str, (int)maxlen))
- {
- if (!LoadStringA(owner, uID, str, (int)maxlen))
- {
- lstrcpynA(str, "Error loading string", (int)maxlen);
- }
- }
- return str;
- }
- wchar_t* Language::GetStringFromGUIDW(const GUID guid, HINSTANCE owner, UINT uID, wchar_t *str, size_t maxlen)
- {
- __declspec(thread) static wchar_t *buf;
- if (!str)
- {
- CheckLangThread();
- if (!buf)
- buf = (wchar_t *)calloc(LANG_STATIC_BUFFER_SIZE, sizeof(buf[0]));
- str = buf;
- maxlen = LANG_STATIC_BUFFER_SIZE;
- }
- HINSTANCE tl = FindDllHandleByGUID(guid);
- if(!tl) tl = owner;
- // sometimes we need to ignore things i.e. accessing on closing, etc
- if (((unsigned long)str >= 65536) && !LoadStringW((started ? tl : owner), uID, str, (int) maxlen))
- {
- if (!LoadStringW(owner, uID, str, (int) maxlen))
- {
- lstrcpynW(str, L"Error loading string", (int) maxlen);
- }
- }
- return str;
- }
- const wchar_t *Language::GetLanguageFolder()
- {
- return (LANGTEMPDIR[0] ? LANGTEMPDIR : lang_directory);
- }
- void* Language::LoadResourceFromFileW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpType, LPCWSTR lpName, DWORD* size)
- {
- HINSTANCE hmod = hinst;
- HRSRC rsrc = FindResourceW(hmod, lpName, lpType);
- if(!rsrc)
- {
- hmod = owner;
- rsrc = FindResourceW(hmod, lpName, lpType);
- }
- if(rsrc)
- {
- HGLOBAL resourceHandle = LoadResource(hmod, rsrc);
- if(size){*size = SizeofResource(hmod, rsrc);}
- return LockResource(resourceHandle);
- }
- return 0;
- }
- void* Language::LoadResourceFromFile(HINSTANCE hinst, HINSTANCE owner, LPCTSTR lpType, LPCTSTR lpName, DWORD* size)
- {
- HINSTANCE hmod = hinst;
- HRSRC rsrc = FindResource(hmod, lpName, lpType);
- if(!rsrc)
- {
- hmod = owner;
- rsrc = FindResource(hmod, lpName, lpType);
- }
- if(rsrc)
- {
- HGLOBAL resourceHandle = LoadResource(hmod, rsrc);
- if(size){*size = SizeofResource(hmod, rsrc);}
- return LockResource(resourceHandle);
- }
- return 0;
- }
- const wchar_t *Language::GetLanguageIdentifier( int mode )
- {
- static wchar_t id_str[ 9 ] = { 0 };
- id_str[ 0 ] = 0;
- // 5.58 fix - was returning en-US on all calls to this via load_extra_lng(..)
- // make sure to try to use a loaded winamp.lng as load_extra_lng(..) relies on
- // this for the path to use but calls it before getStringW(..) will work fully
- GetStringFromGUIDW( WinampLangGUID, hMainInstance, LANG_PACK_LANG_ID, id_str, 9 );
- if ( !_wcsicmp( id_str, L"Error l" ) )
- {
- id_str[ 0 ] = 0;
- }
- if ( mode && id_str[ 0 ] )
- {
- wchar_t *iStr = id_str;
- while ( iStr && *iStr && *iStr != L'-' )
- {
- iStr = CharNextW( iStr );
- }
- if ( iStr && *iStr == '-' )
- {
- iStr = CharNextW( iStr );
- *CharPrevW( id_str, iStr ) = 0;
- }
- if ( mode == LANG_LANG_CODE )
- return id_str;
- else if ( mode == LANG_COUNTRY_CODE )
- return iStr;
- }
- return ( id_str[ 0 ] ? id_str : 0 );
- }
- HWND Language::CreateLDialogParam( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
- {
- HWND hwnd = (HWND)CreateDialogParamA( localised, MAKEINTRESOURCEA( id ), parent, proc, param );
- if ( !hwnd && localised != original )
- hwnd = (HWND)CreateDialogParamA( original, MAKEINTRESOURCEA( id ), parent, proc, param );
- return hwnd;
- }
- HWND Language::CreateLDialogParamW( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
- {
- HWND hwnd = (HWND)CreateDialogParamW( localised, MAKEINTRESOURCEW( id ), parent, proc, param );
- if ( !hwnd && localised != original )
- hwnd = (HWND)CreateDialogParamW( original, MAKEINTRESOURCEW( id ), parent, proc, param );
- return hwnd;
- }
- INT_PTR Language::LDialogBoxParam( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
- {
- INT_PTR ret = DialogBoxParamA( localised, MAKEINTRESOURCEA( id ), parent, proc, param );
- if ( ( ret == -1 && GetLastError() != ERROR_SUCCESS ) && localised != original )
- ret = DialogBoxParamA( original, MAKEINTRESOURCEA( id ), parent, proc, param );
- return ret;
- }
- INT_PTR Language::LDialogBoxParamW( HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param )
- {
- INT_PTR ret = DialogBoxParamW( localised, MAKEINTRESOURCEW( id ), parent, proc, param );
- if ( ( ret == -1 && GetLastError() != ERROR_SUCCESS ) && localised != original )
- ret = DialogBoxParamW( original, MAKEINTRESOURCEW( id ), parent, proc, param );
- return ret;
- }
- HWND LPCreateDialogParam( int id, HWND parent, DLGPROC proc, LPARAM param )
- {
- return langManager->CreateLDialogParam( language_pack_instance, hMainInstance, id, parent, proc, param );
- }
- HWND LPCreateDialogParamW( int id, HWND parent, DLGPROC proc, LPARAM param )
- {
- return langManager->CreateLDialogParamW( language_pack_instance, hMainInstance, id, parent, proc, param );
- }
- INT_PTR LPDialogBoxParam( int id, HWND parent, DLGPROC proc, LPARAM param )
- {
- return langManager->LDialogBoxParam( language_pack_instance, hMainInstance, id, parent, proc, param );
- }
- INT_PTR LPDialogBoxParamW( int id, HWND parent, DLGPROC proc, LPARAM param )
- {
- return langManager->LDialogBoxParamW( language_pack_instance, hMainInstance, id, parent, proc, param );
- }
- HMENU Language::LoadLMenu( HINSTANCE localised, HINSTANCE original, UINT id )
- {
- HMENU menu = LoadMenuA( localised, MAKEINTRESOURCEA( id ) );
- if ( !menu && localised != original )
- menu = LoadMenuA( original, MAKEINTRESOURCEA( id ) );
-
- return menu;
- }
- HMENU Language::LoadLMenuW(HINSTANCE localised, HINSTANCE original, UINT id)
- {
- HMENU menu = LoadMenuW(localised, MAKEINTRESOURCEW(id));
- if (!menu && localised != original)
- menu = LoadMenuW(original, MAKEINTRESOURCEW(id));
- return menu;
- }
- HACCEL Language::LoadAcceleratorsA(HINSTANCE hinst, HINSTANCE owner, LPCSTR lpTableName)
- {
- HACCEL hAccel = ::LoadAcceleratorsA(hinst, lpTableName);
- if (!hAccel && hinst != owner)
- hAccel = ::LoadAcceleratorsA(owner, lpTableName);
- return hAccel;
- }
- HACCEL Language::LoadAcceleratorsW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpTableName)
- {
- HACCEL hAccel = ::LoadAcceleratorsW(hinst, lpTableName);
- if (!hAccel && hinst != owner)
- hAccel = ::LoadAcceleratorsW(owner, lpTableName);
- return hAccel;
- }
- // Implemented in 5.58+
- // when we're loading a language pack we really need to specify if we're
- // going to require correct use of the user's locale setting so that the
- // output of certain text ie '%+6.1f' uses the correct decimal separator
- // ref: http://msdn.microsoft.com/en-us/library/aa246453%28VS.60%29.aspx
- BOOL Language::UseUserNumericLocale(void)
- {
- wchar_t tmp[4] = {0}, lang[4] = {0}, ctry[4] = {0};
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, 4);
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, ctry, 4);
- // do this check to ensure that the we only change the locale
- // if the language pack and the user locale identifiers match
- if(!_wcsicmp(lang, GetLanguageIdentifier(LANG_LANG_CODE)) &&
- !_wcsicmp(ctry, GetLanguageIdentifier(LANG_COUNTRY_CODE)) &&
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, tmp, 4))
- {
- _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
- // now we set the functions to use the user's numeric locale
- return !!_wsetlocale(LC_NUMERIC,tmp);
- }
- return FALSE;
- }
- _locale_t Language::Get_C_NumericLocale(void)
- {
- __declspec(thread) static _locale_t C_locale;
- if(!C_locale) C_locale = _create_locale(LC_NUMERIC, "C");
- return C_locale;
- }
- // Implemented in 5.64+
- wchar_t* Language::FormattedSizeString(wchar_t *pszDest, int cchDest, __int64 size)
- {
- if (!pszDest) return 0;
- size_t remaining = cchDest;
- DWORD part = 0;
- pszDest[0] = 0x00;
- if (size < 1024)
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS,
- L"%u %s", (DWORD)(size >> 10) + ((((DWORD)(size))&1023) ? 1: 0),
- getStringW(IDS_BYTES, NULL, 0));
- }
- else if (size < 1048576)
- {
- part = ((((DWORD)(size))&1023)*100) >> 10;
- if (part > 0)
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
- (DWORD)(size >> 10), part, getStringW(geno ? IDS_KB : IDS_KIB, NULL, 0));
- }
- else
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
- (DWORD)(size >> 10), getStringW(geno ? IDS_KB : IDS_KIB, NULL, 0));
- }
- }
- else if (size < 1073741824)
- {
- part = ((((DWORD)(size >> 10))&1023)*100) >> 10;
- if (part > 0)
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
- (DWORD)(size >> 20), part, getStringW(geno ? IDS_MB : IDS_MIB, NULL, 0));
- }
- else
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
- (DWORD)(size >> 20), getStringW(geno ? IDS_MB : IDS_MIB, NULL, 0));
- }
- }
- else if (size < 1099511627776)
- {
- part = ((((DWORD)(size >> 20))&1023)*100) >> 10;
- if (part > 0)
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
- (DWORD)(size >> 30), part, getStringW(geno ? IDS_GB : IDS_GIB, NULL, 0));
- }
- else
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
- (DWORD)(size >> 30), getStringW(geno ? IDS_GB : IDS_GIB, NULL, 0));
- }
- }
- else
- {
- part = ((((DWORD)(size >> 30))&1023)*100) >> 10;
- if (part > 0)
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u.%02u %s",
- (DWORD)(size >> 40), part, getStringW(geno ? IDS_TB : IDS_TIB, NULL, 0));
- }
- else
- {
- StringCchPrintfExW(pszDest, cchDest, NULL, &remaining, STRSAFE_IGNORE_NULLS, L"%u %s",
- (DWORD)(size >> 40), getStringW(geno ? IDS_TB : IDS_TIB, NULL, 0));
- }
- }
- return pszDest;
- }
- HMENU LPLoadMenu(UINT id)
- {
- return langManager->LoadLMenu(language_pack_instance, hMainInstance, id);
- }
- void Lang_CleanupZip(void)
- {
- if (!LANGTEMPDIR[0]) return ;
- if (_cleanupDirW(LANGTEMPDIR))
- {
- char str[78] = {0};
- StringCchPrintfA(str,78,"lang_clean_up%ws",szAppName);
- _w_s(str, 0);
- }
- }
- // attempt to cleanup the last extracted temp folder for a wlz incase Winamp crashed on exit
- void Lang_CleanupAfterCrash(void)
- {
- wchar_t buf[1024] = {0};
- char str[78] = {0};
- StringCchPrintfA(str,78,"lang_clean_up%ws",szAppName);
- _r_sW(str, buf, sizeof(buf));
- if (buf[0])
- {
- _cleanupDirW(buf);
- _w_s(str, 0);
- }
- }
- static int load_extra_lng(BOOL force)
- {
- int is_wlz = 0;
- if (langManager)
- {
- const wchar_t *lang_identifier = langManager->GetLanguageIdentifier(LANG_IDENT_STR);
- if (lang_identifier || force)
- {
- wchar_t extra_lang_path[MAX_PATH] = {0};
- wchar_t lng_file[MAX_PATH] = {0};
- if (!force)
- PathCombineW(extra_lang_path, LANGDIR, lang_identifier);
- else
- lstrcpynW(extra_lang_path, lang_directory, MAX_PATH);
- PathCombineW(lng_file, extra_lang_path, L"*.lng");
- WIN32_FIND_DATAW find_data = {0};
- HANDLE h = FindFirstFileW(lng_file, &find_data);
- if (h != INVALID_HANDLE_VALUE)
- {
- do
- {
- PathCombineW(lng_file, extra_lang_path, find_data.cFileName);
- is_wlz = 1;
- winampLangStruct* templng = reinterpret_cast<winampLangStruct*>(calloc(1, sizeof(winampLangStruct)));
- templng->module = _wcsdup(lng_file);
- bool exception = (!lstrcmpiW(templng->module, L"omBrowser.lng") || !lstrcmpiW(templng->module, L"ml_online.lng"));
- // the plain LoadLibrary(..) generally works though as we only want to
- // load the lng files for resources (and that some people's lng files
- // can generally end up being corrupted after a few edits), we instead
- // try to load as an image / data file (so doesn't re-map things, etc)
- templng->hDllInstance = LoadLibraryExW(lng_file, NULL, (!exception ? LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE : 0));
- // incase of running on an older OS, try it as a plain LoadLibrary(..)
- if (!templng->hDllInstance) templng->hDllInstance = LoadLibraryW(lng_file);
- if (templng->hDllInstance)
- {
- wchar_t s[39] = {0};
- if(LoadStringW(templng->hDllInstance, LANG_DLL_GUID_STRING_ID, s, 39))
- {
- templng->external = 1;
- templng->guidstr = _wcsdup(s);
- GetImageHashData(templng->hDllInstance);
- }
- // only keep if it's a valid lng dll ie doesn't have load issues
- lnglist.push_back(templng);
- }
- }
- while (FindNextFileW(h, &find_data));
- FindClose(h);
- }
- }
- }
- return is_wlz;
- }
- // return 1 if we're working from a wlz otherwise return 0
- int extract_wlz_to_dir(wchar_t* readme_only_wlz_extraction, BOOL *skip)
- {
- int is_wlz = 0;
- if (config_langpack[0] || readme_only_wlz_extraction && readme_only_wlz_extraction[0])
- {
- wchar_t* langpack = (readme_only_wlz_extraction?readme_only_wlz_extraction:config_langpack),
- tempdirbuf[MAX_PATH] = {0}, *TEMPDIR = LANGTEMPDIR;
- if (_wcsicmp(extensionW(langpack), L"zip") && _wcsicmp(extensionW(langpack), L"wlz"))
- {
- if (PathIsFileSpecW(langpack) || PathIsRelativeW(langpack))
- PathCombineW(lang_directory, LANGDIR, langpack);
- else
- StringCchCopyW(lang_directory, MAX_PATH, langpack);
- is_wlz = load_extra_lng(TRUE);
- if (skip) *skip = is_wlz;
- }
- else
- {
- wchar_t dirmask[MAX_PATH*4] = {0};
- char str[78] = {0};
- unzFile f = {0};
- // make sure that we use a different folder from the current wlz temp folder otherwise we have issues
- if(readme_only_wlz_extraction){
- wchar_t buf[MAX_PATH] = {0};
- GetTempPathW(MAX_PATH, buf);
- GetTempFileNameW(buf, L"WLZ", GetTickCount(), tempdirbuf);
- TEMPDIR = tempdirbuf;
- }
- CreateDirectoryW(TEMPDIR, NULL);
- StringCchPrintfA(str,78,"lang_clean_up%ws",szAppName);
- if(!readme_only_wlz_extraction){
- StringCchCopyW(lang_directory, MAX_PATH, TEMPDIR);
- _w_sW(str, TEMPDIR);
- }
- if (PathIsFileSpecW(langpack)|| PathIsRelativeW(langpack))
- PathCombineW(dirmask, LANGDIR, langpack);
- else
- StringCchCopyW(dirmask, MAX_PATH*4, langpack);
- // now we're going to extract, if doing a temp extraction then set the path into the passed buffer
- if(readme_only_wlz_extraction){
- StringCchCopyW(readme_only_wlz_extraction, MAX_PATH, TEMPDIR);
- }
- f = unzOpen(AutoCharFn(dirmask));
- if (f)
- {
- if (unzGoToFirstFile(f) == UNZ_OK)
- {
- OVERLAPPED asyncIO = {0};
- int isNT = (GetVersion() < 0x80000000);
- if (isNT)
- {
- asyncIO.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
- asyncIO.OffsetHigh = 0;
- }
- do
- {
- char filename[MAX_PATH] = {0}, *fn = 0, *p = 0;
- if (isNT)
- SetEvent(asyncIO.hEvent);
- unzGetCurrentFileInfo(f, NULL, filename, sizeof(filename), NULL, 0, NULL, 0);
- //Only extract the file-types that could be in a skin
- //If we don't filter here it's a security hole
- // expand out folders if we've got a freeform based folder
- if(!_strnicmp(filename,"freeform\\",9) || !_strnicmp(filename,"freeform/",9))
- fn = filename;
- // otherwise just extract to the root of the temp directory
- else
- fn = scanstr_back(filename, "\\/", filename - 1) + 1;
- p = extension(fn);
- // TODO: really should enum image loaders so we only extract supported image files
- if (!_stricmp(p, "lng") || !_stricmp(p, "ini") || !_stricmp(p, "txt") ||
- !_stricmp(p, "png") || !_stricmp(p, "bmp") || !_stricmp(p, "gif") ||
- !_stricmp(p, "jpg") || !_stricmp(p, "xml") || !_stricmp(p, "htm") ||
- // not too keen on dll in there but that's how the GN dlls are named
- !_stricmp(p, "dll"))
- {
- if (unzOpenCurrentFile(f) == UNZ_OK)
- {
- PathCombineW(dirmask, TEMPDIR, AutoWide(fn));
- CreateDirectoryForFileW(dirmask, TEMPDIR);
- HANDLE fp = CreateFileW(dirmask, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | (isNT ? FILE_FLAG_OVERLAPPED : 0), NULL);
- if (fp != INVALID_HANDLE_VALUE)
- {
- int l = 0, pos = 0, bufNum=0;
- #define LANG_ZIP_BUFFER_SIZE 2048
- char buf[LANG_ZIP_BUFFER_SIZE*2] = {0};
- int success = 1;
- do
- {
- DWORD written = 0;
- bufNum = !bufNum;
- l = unzReadCurrentFile(f, buf+LANG_ZIP_BUFFER_SIZE*bufNum, LANG_ZIP_BUFFER_SIZE);
- if (!l)
- unzCloseCurrentFile(f);
- if (isNT)
- {
- WaitForSingleObject(asyncIO.hEvent, INFINITE);
- if (l > 0)
- {
- asyncIO.Offset = pos;
- if (WriteFile(fp, buf+LANG_ZIP_BUFFER_SIZE*bufNum, l, NULL, &asyncIO) == FALSE
- && GetLastError() != ERROR_IO_PENDING)
- {
- success=0;
- }
- pos += l;
- }
- }
- else
- {
- if (l > 0)
- {
- if (WriteFile(fp, buf+LANG_ZIP_BUFFER_SIZE*bufNum, l, &written, NULL) == FALSE)
- success = 0;
- }
- }
- } while (l > 0 && success);
- CloseHandle(fp);
- // cache information about the extracted lng files
- if(!_stricmp(p, "lng") && !readme_only_wlz_extraction)
- {
- is_wlz = 1;
- winampLangStruct* templng = reinterpret_cast<winampLangStruct*>(calloc(1, sizeof(winampLangStruct)));
- templng->module = AutoWideDup(filename);
- bool exception = (!lstrcmpiW(templng->module, L"omBrowser.lng") || !lstrcmpiW(templng->module, L"ml_online.lng"));
- // the plain LoadLibrary(..) generally works though as we only want to
- // load the lng files for resources (and that some people's lng files
- // can generally end up being corrupted after a few edits), we instead
- // try to load as an image / data file (so doesn't re-map things, etc)
- templng->hDllInstance = LoadLibraryExW(dirmask, NULL, (!exception ? LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE : 0));
- if (!templng->hDllInstance) templng->hDllInstance = LoadLibraryW(dirmask);
- if (templng->hDllInstance)
- {
- wchar_t s[39] = {0};
- if(LoadStringW(templng->hDllInstance, LANG_DLL_GUID_STRING_ID, s, 39))
- {
- templng->guidstr = _wcsdup(s);
- GetImageHashData(templng->hDllInstance);
- }
- // only keep if it's a valid lng dll ie doesn't have load issues
- lnglist.push_back(templng);
- }
- }
- }
- }
- }
- }
- while (unzGoToNextFile(f) == UNZ_OK);
- if (isNT && asyncIO.hEvent)
- {
- CloseHandle(asyncIO.hEvent);
- }
- }
- unzClose(f);
- }
- }
- }
- else lang_directory[0] = 0;
- return is_wlz;
- }
- HINSTANCE Language::FindDllHandleByGUID(const GUID guid)
- {
- wchar_t gs[40] = {0};
- getGUIDstr(guid,gs);
- for ( winampLangStruct *l_lng : lnglist )
- {
- if( l_lng->guidstr && *l_lng->guidstr && !_wcsnicmp(gs, l_lng->guidstr, 38))
- return l_lng->hDllInstance;
- }
- return NULL;
- }
- HINSTANCE Language::FindDllHandleByString(const char* _str)
- {
- AutoWide str__(_str);
- const wchar_t *str = str__;
- if(str && *str)
- {
- for ( winampLangStruct *l_lng : lnglist )
- {
- if ( l_lng->module && *l_lng->module && !_wcsnicmp( l_lng->module, str, lstrlenW( str ) ) )
- return l_lng->hDllInstance;
- }
- }
- return NULL;
- }
- HINSTANCE Language::FindDllHandleByStringW(const wchar_t* _str)
- {
- AutoChar str__(_str);
- const wchar_t *str = _str;
- if(str && *str)
- {
- for ( winampLangStruct *l_lng : lnglist )
- {
- if( l_lng->module && *l_lng->module && !_wcsnicmp( l_lng->module, str, lstrlenW(str)))
- return l_lng->hDllInstance;
- }
- }
- return NULL;
- }
- HINSTANCE Lang_InitLangSupport(HINSTANCE hinst, const GUID guid)
- {
- geno = _r_i("geno", 1);
- started = 1;
- return langManager->StartLanguageSupport(hinst, guid);
- }
- void Lang_FollowUserDecimalLocale(void)
- {
- langManager->UseUserNumericLocale();
- }
- // use this to load based on the module specified so that we make sure
- // we've got the correct hinstance based on lng file or default handle
- HINSTANCE Language::StartLanguageSupport(HINSTANCE hinstance, const GUID guid)
- {
- if (!g_safeMode)
- {
- HWND agent = FindWindowW(L"WinampAgentMain", NULL);
- wchar_t winampaLngPath[MAX_PATH] = {0};
- int is_wlz = 0;
- // if we find Winamp Agent running then we need to tell it
- // to unload it's winampa.lng for what we're about to do..
- if (IsWindow(agent) && !already_extracted)
- {
- SendMessageW(agent, WM_USER + 16, 1, 0);
- }
- // always remove winampa.lng just incase we crashed and it leaves things out of synch
- if(!already_extracted){
- StringCchPrintfW(winampaLngPath, MAX_PATH, L"%s\\winampa.lng", CONFIGDIR);
- DeleteFileW(winampaLngPath);
- }
- config_load_langpack_var();
- if(!already_extracted)
- {
- BOOL skip = FALSE;
- already_extracted = 1;
- prev_wlz_ex_state = is_wlz = extract_wlz_to_dir(0, &skip);
- if (!skip) load_extra_lng(FALSE);
- else LANGTEMPDIR[0] = 0;
- }
- else
- {
- is_wlz = prev_wlz_ex_state;
- agent = 0;
- }
- // make sure that we don't try and load the exe/dll being localised as the lng dll
- wchar_t modulename[MAX_PATH] = {0}, *p = 0;
- GetModuleFileNameW(hinstance, modulename, MAX_PATH);
- p = scanstr_backW(modulename, L"\\/", NULL);
- if(p) p = CharNextW(p);
- // if is_wlz != 0 then we can attempt to use the wlz extracted files otherwise
- // (for the time being) we drop back to the older lng pack system
- // either way we still need to make sure that what we're using is valid
- if (config_langpack[0] && is_wlz)
- {
- HMODULE h = langManager->FindDllHandleByGUID(guid);
- if(!h) // possible fallback usage if things failed to work on guid look up
- { // though wouldn't be reliable if people change the lng file names
- wchar_t tmpfile[MAX_PATH], *t = 0;
- lstrcpynW(tmpfile,p,MAX_PATH);
- t = scanstr_backW(tmpfile, L".", NULL);
- lstrcpynW(t,L".lng",MAX_PATH);
- h = langManager->FindDllHandleByStringW(tmpfile);
- }
- if (h)
- {
- // if the wlz was able to be loaded (as we believe at this point)
- // then we see if Winamp Agent is running and tell it to refresh
- // it's version of winampa.lng once we've copied into %inidir%
- if (IsWindow(agent))
- {
- // copy from the wlz folder to the settings folder
- wchar_t winampaWlzPath[MAX_PATH] = {0};
- StringCchPrintfW(winampaWlzPath, MAX_PATH, L"%s\\winampa.lng", lang_directory);
- CopyFileW(winampaWlzPath,winampaLngPath,FALSE);
- SendMessageW(agent, WM_USER + 16, 0, 0);
- }
- // if we get here then we've managed to load the language pack
- // (still could be invalid but that's generally from failed dll files)
- return h;
- }
- }
- }
- // make sure we return the passed hinstance incase of failure to load/invalid lng file/etc
- return hinstance;
- }
- void Lang_EndLangSupport(void)
- {
- started = 0;
- // need to fully clean up things here including unloading of the langpack
- HINSTANCE old_language_pack_instance = language_pack_instance;
- if(language_pack_instance != hMainInstance)
- {
- FreeLibrary(language_pack_instance);
- language_pack_instance = hMainInstance;
- }
- for ( winampLangStruct *l_lng : lnglist )
- {
- if( l_lng->module)
- {
- free( l_lng->module);
- l_lng->module = 0;
- }
- if( l_lng->guidstr)
- {
- free( l_lng->guidstr);
- l_lng->guidstr = 0;
- }
- // this check is to prevent trying to re-free the winamp.lng (as it's done earlier)
- // as well as anything which is not in the temp folder to avoid any unloading issues
- if ( !l_lng->external && l_lng->hDllInstance && ( l_lng->hDllInstance != old_language_pack_instance ) )
- {
- FreeLibrary( l_lng->hDllInstance );
- l_lng->hDllInstance = 0;
- }
- }
- lnglist.clear();
- prev_wlz_ex_state = already_extracted = 0;
- }
- HINSTANCE Lang_FakeWinampLangHInst(HINSTANCE adjustedHInst){
- HINSTANCE previousHInst = language_pack_instance;
- language_pack_instance = adjustedHInst;
- started = !!adjustedHInst;
- return previousHInst;
- }
- void Lang_LocaliseAgentOnTheFly(BOOL refresh){
- // if we need to refresh then attempt to use the winampa.lng from the
- // current language pack if one is present and has been extracted so
- // we test to see if we've extracted a language pack already
- if(already_extracted){
- HWND agent = FindWindowW(L"WinampAgentMain", NULL);
- wchar_t winampaLngPath[MAX_PATH] = {0};
- // if we find Winamp Agent running then we need to tell it
- // to unload it's winampa.lng for what we're about to do...
- // although this is likely to be a new load, doing this will
- // help to ensure that things are unloaded incase of issues
- if(IsWindow(agent)){
- SendMessageW(agent, WM_USER + 16, 1, 0);
- }
- // always remove winampa.lng just incase we crashed and it leaves things out of synch
- StringCchPrintfW(winampaLngPath, MAX_PATH, L"%s\\winampa.lng", CONFIGDIR);
- DeleteFileW(winampaLngPath);
- if(refresh){
- wchar_t winampaWlzPath[MAX_PATH] = {0};
- StringCchPrintfW(winampaWlzPath, MAX_PATH, L"%s\\winampa.lng", lang_directory);
- CopyFileW(winampaWlzPath,winampaLngPath,FALSE);
- SendMessageW(agent, WM_USER + 16, 0, 0);
- }
- }
- }
- #ifdef CBCLASS
- #undef CBCLASS
- #endif
- #define CBCLASS Language
- START_DISPATCH;
- CB( API_LANGUAGE_GETSTRING, GetString )
- CB( API_LANGUAGE_GETSTRINGW, GetStringW )
- CB( API_LANGUAGE_GETSTRINGFROMGUID, GetStringFromGUID )
- CB( API_LANGUAGE_GETSTRINGFROMGUIDW, GetStringFromGUIDW )
- CB( API_LANGUAGE_GETHINSTANCEBYGUID, FindDllHandleByGUID )
- CB( API_LANGUAGE_GETHINSTANCEBYNAME, FindDllHandleByString )
- CB( API_LANGUAGE_GETHINSTANCEBYNAMEW, FindDllHandleByStringW )
- CB( API_LANGUAGE_STARTUP, StartLanguageSupport )
- CB( API_LANGUAGE_GETLANGUAGEFOLDER, GetLanguageFolder )
- CB( API_LANGUAGE_CREATELDIALOGPARAM, CreateLDialogParam )
- CB( API_LANGUAGE_LDIALOGBOXPARAM, LDialogBoxParam )
- CB( API_LANGUAGE_LOADLMENU, LoadLMenu )
- CB( API_LANGUAGE_CREATELDIALOGPARAMW, CreateLDialogParamW )
- CB( API_LANGUAGE_LDIALOGBOXPARAMW, LDialogBoxParamW )
- CB( API_LANGUAGE_LOADLMENUW, LoadLMenuW )
- CB( API_LANGUAGE_GETLANGUAGEIDENTIFIER, GetLanguageIdentifier )
- CB( API_LANGUAGE_LOADRESOURCEFROMFILEA, LoadResourceFromFile )
- CB( API_LANGUAGE_LOADRESOURCEFROMFILEW, LoadResourceFromFileW )
- CB( API_LANGUAGE_LOADACCELERATORSA, LoadAcceleratorsA )
- CB( API_LANGUAGE_LOADACCELERATORSW, LoadAcceleratorsW )
- CB( API_LANGUAGE_USEUSERNUMERICLOCALE, UseUserNumericLocale )
- CB( API_LANGUAGE_GET_C_NUMERICLOCALE, Get_C_NumericLocale )
- CB( API_LANGUAGE_FORMATTEDSIZESTRING, FormattedSizeString )
- END_DISPATCH
|