diff options
Diffstat (limited to 'Src/Plugins/Input/in_nsv')
-rw-r--r-- | Src/Plugins/Input/in_nsv/BigLib.cpp | 1428 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/Main.cpp | 976 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/api.h | 16 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/config.cpp | 197 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/in_nsv.rc | 294 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/in_nsv.sln | 30 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/in_nsv.vcxproj | 274 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/in_nsv.vcxproj.filters | 67 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/infodlg.cpp | 1089 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/nsv_logo.bmp | bin | 0 -> 7480 bytes | |||
-rw-r--r-- | Src/Plugins/Input/in_nsv/proxydt.h | 16 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/resource.h | 86 | ||||
-rw-r--r-- | Src/Plugins/Input/in_nsv/version.rc2 | 39 |
13 files changed, 4512 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_nsv/BigLib.cpp b/Src/Plugins/Input/in_nsv/BigLib.cpp new file mode 100644 index 00000000..5e8c541f --- /dev/null +++ b/Src/Plugins/Input/in_nsv/BigLib.cpp @@ -0,0 +1,1428 @@ +#ifdef WINAMPX +#define WIN32_LEAN_AND_MEAN 1 +#include <windows.h> +#include "stdio.h" +#include "proxydt.h" +#include <winsock2.h> +#include ".\ws2tcpip.h" +#include ".\wininet.h" +#include "../jnetlib/jnetlib.h" + +#include <urlmon.h> + + +extern void SendMetadata( char *data, int arg ); +HRESULT JNetLibDownloadToFile(LPVOID lpUnused1, LPSTR lpWPADLocation, LPSTR lpTempFile, LPVOID lpUnused2, LPVOID lpUnused3); +enum { + BK_UNKNOWN = 0, + BK_IE4 = 1, + BK_NETSCAPE4 = 2, + BK_NETSCAPE6 = 3, + BK_MOZILLA = 4, + BK_FIREFOX = 5 +}; + +// browser info struct +typedef struct{ + LPSTR lpName; + BOOL bSupported; +}BK_INFO; + +// browser info +BK_INFO BrowserInfo[] = { + "Unknown", FALSE, + "IE 4.0+", TRUE, + "Netscape 4 or 5", FALSE, + "Netscape 6+", TRUE, + "Mozilla", TRUE, + "Firefox", TRUE +}; + +// Global variables +int gBrowserKind = BK_UNKNOWN; + +int gTryAuto = 1; + +// Exported C functions +extern "C" BOOL ProxyInit(); +extern "C" void ProxyDeInit(); +extern "C" int ResolvProxyFromURL(LPSTR lpURL, LPSTR lpHostname, LPSTR lpDest); + +// Global C functions +BOOL IsIEProxySet(); +int GetIESettings(); +int ResolveURL_IE(LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort); +BOOL IsFirefoxProxySet(); +int GetFirefoxSettings(); +int ResolveURL_Firefox(LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort); +BOOL IsMozillaProxySet(); +int GetMozillaSettings(); +int ResolveURL_Mozilla(LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort); +int GetDefaultBrowser(); +int ReadWPADFile(LPSTR lpWPADLocation, LPSTR pIPAddress, int *pnPort); +int GetFirefoxOrMozillaSettings(BOOL bFirefox); +BOOL IsFirefoxOrMozillaProxySet(BOOL bFirefox); +int ResolveURL_MozillaOrFirefox(BOOL bFirefox, LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort); + +// exported functions +extern "C" BOOL ProxyInit() +{ + BOOL bRet; + + bRet = FALSE; + gBrowserKind = GetDefaultBrowser(); + + switch(gBrowserKind) { + case BK_IE4: + bRet = IsIEProxySet(); + break; + + case BK_MOZILLA: + bRet = IsMozillaProxySet(); + + break; + + case BK_FIREFOX: + bRet = IsFirefoxProxySet(); + break; + } + + return bRet; +} + +extern "C" void ProxyDeInit() +{ +} + +extern "C" int ResolvProxyFromURL(LPSTR lpURL, LPSTR lpHostname, LPSTR lpDest) +{ + // lpURL = URL to resolve + // lpHostname = hostname + // lpDest = where to store the result, such as "www.proxyserver.com:8080" + char szIPAddress[MAX_PATH] = {0}; + int ret, nPort=0; + + lpDest[0]=0; + + if(lpURL && lpHostname && lpDest) { + switch(gBrowserKind) { + case BK_IE4: + ret = ResolveURL_IE(lpURL, lpHostname, szIPAddress, sizeof(szIPAddress), &nPort); + break; + + case BK_MOZILLA: + ret = ResolveURL_Mozilla(lpURL, lpHostname, szIPAddress, sizeof(szIPAddress), &nPort); + break; + + case BK_FIREFOX: + ret = ResolveURL_Firefox(lpURL, lpHostname, szIPAddress, sizeof(szIPAddress), &nPort); + break; + } + + if(ret == 0) { + if ( szIPAddress[0] ) + { + wsprintf(lpDest, "%s:%d", szIPAddress, nPort); + return 1; + } + else return 0; + } + else return 0; + } + else return -1; + +} + +int GetDefaultBrowser() +{ + DWORD dwSize, dwType; + TCHAR valueBuf[MAX_PATH] = {0}; + DWORD valueSize = sizeof(valueBuf); + HKEY hKey; + long lRet; + + + memset(valueBuf, 0, sizeof(valueBuf)); + lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, "http\\shell\\open\\ddeexec\\Application", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + dwSize = valueSize; + lRet = RegQueryValueEx(hKey, "", NULL, &dwType, (LPBYTE)valueBuf, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_SZ) { + if (_tcsicmp(_T("NSShell"), valueBuf) == 0) { //NS 4.x + return BK_NETSCAPE4; + } else if (_tcsicmp(_T("IExplore"), valueBuf) == 0) { //IE 4+ + return BK_IE4; + } else if (_tcsicmp(_T("Mozilla"), valueBuf) == 0) { //Mozilla + return BK_MOZILLA; + } else if (_tcsicmp(_T("Firefox"), valueBuf) == 0) { //Firefox + return BK_FIREFOX; + } + } + } + RegCloseKey(hKey); + + lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, "http\\shell\\open\\command", 0, KEY_READ, &hKey); + if(lRet == ERROR_SUCCESS) { + dwSize = valueSize; + lRet = RegQueryValueEx(hKey, "", NULL, &dwType, (LPBYTE)valueBuf, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_SZ) { + if(strstr(valueBuf, "MOZILLA")) { + return BK_MOZILLA; + } + if(strstr(valueBuf, "NETSCAPE")) { + return BK_MOZILLA; + } + if(strstr(valueBuf, "FIREFOX")) { + return BK_FIREFOX; + } + } + } + RegCloseKey(hKey); + + return BK_UNKNOWN; +} + + + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// helper functions for JSProxy.dll +DWORD __stdcall ResolveHostName(LPSTR lpszHostName, LPSTR lpszIPAddress, LPDWORD lpdwIPAddressSize); +BOOL __stdcall IsResolvable(LPSTR lpszHost); +DWORD __stdcall GetIPAddress(LPSTR lpszIPAddress, LPDWORD lpdwIPAddressSize); +BOOL __stdcall IsInNet(LPSTR lpszIPAddress, LPSTR lpszDest, LPSTR lpszMask); + +// functions to get IE checkbox state +BOOL GetAutomaticallyDetectSettingsCheckboxState(); +BOOL GetUseAProxyServerForYourLanCheckboxState(); +BOOL GetAutomaticConfigurationScriptCheckboxState(); +BOOL GetBypassProxyServerForLocalAddressesCheckboxState(); + +// functions to actually get an IP address and port # of the proxy server +int GetAutomaticDetectSettings(LPSTR lpIPAddress, int *pnPort); +int GetProxyServerForLanProxySettings(LPSTR lpIPAddress, int *pnPort); +int GetAutoConfigScriptProxySettings(LPSTR lpIPAddress, int *pnPort); + +// various helper functions +BOOL IsDirect(LPSTR proxy); +BOOL IsAProxy(LPSTR proxy); +void reportFuncErr(TCHAR* funcName); +char * strstri(LPSTR lpOne, LPSTR lpTwo); +int GetProxyIP(LPSTR proxy, LPSTR szProxyIP); +int GetProxyPort(LPSTR proxy); + +// some global variables +char gszURL[1025] = {0}; +char gszHost[256] = {0}; + +// returns TRUE if the user has set a proxy in IE +BOOL IsIEProxySet() +{ + BOOL bAutomaticallyDetectSettings = GetAutomaticallyDetectSettingsCheckboxState(); + BOOL bUseAutomaticConfigurationScript = GetAutomaticConfigurationScriptCheckboxState(); + BOOL bUseAProxyServerForYourLan = GetUseAProxyServerForYourLanCheckboxState(); + + if(bAutomaticallyDetectSettings || bUseAutomaticConfigurationScript || bUseAProxyServerForYourLan) { + return TRUE; + } + + return FALSE; +} + +int ResolveURL_IE(LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort) +{ + // get the state of the four checkboxes in the proxy settings dialog for IE + BOOL bAutomaticallyDetectSettings = GetAutomaticallyDetectSettingsCheckboxState(); + BOOL bUseAutomaticConfigurationScript = GetAutomaticConfigurationScriptCheckboxState(); + BOOL bUseAProxyServerForYourLan = GetUseAProxyServerForYourLanCheckboxState(); + //BOOL bBypassProxyServerForLocalAddresses = GetBypassProxyServerForLocalAddressesCheckboxState(); + int ret; + + lstrcpyn(gszURL, lpURL, 1025); + lstrcpyn(gszHost, lpHostname, 256); + + // if nothing checked, return + if(!bAutomaticallyDetectSettings && !bUseAutomaticConfigurationScript && !bUseAProxyServerForYourLan) { + return 0; + } + + // if all three checkboxes on... + if(bAutomaticallyDetectSettings && gTryAuto) + { + // try the automatic configuration next + ret = GetAutomaticDetectSettings(lpIPAddress, pnPort); + if(ret == 0 && *pnPort) { + return 0; + } + gTryAuto = 0; + + } + + if ( bUseAutomaticConfigurationScript) + { + // try the automatic config script method first + ret = GetAutoConfigScriptProxySettings(lpIPAddress, pnPort); + if(ret == 0 && *pnPort ) { + return 0; + } + + } + + if ( bUseAProxyServerForYourLan) + { + // if still no success, try the "Use a proxy server for your lan" settings + ret = GetProxyServerForLanProxySettings(lpIPAddress, pnPort); + if(ret == 0 && *pnPort) { + return 0; + } + } + + + + + + // no success... + return 0; + + +} + +// handles the "Automatically Detect" checkbox +int GetAutomaticDetectSettings(LPSTR lpIPAddress, int *pnPort) +{ + // By not specifying a domain name, Windows uses the local domain name, + // so form an http request to go to http://wpad/wpad.dat, + // store results in szWPADLocation and call URLDownloadToFileA() + if(lpIPAddress && pnPort) { + // download wpad.dat from the URL in szURL + return ReadWPADFile("http://wpad/wpad.dat", lpIPAddress, pnPort); + } + + return -1; +} + +// handles the "Use automatic configuration script" checkbox +int GetAutoConfigScriptProxySettings(LPSTR lpIPAddress, int *pnPort) +{ + DWORD dwType, dwSize; + HKEY hKey; + char szWPADLocation[MAX_PATH] = {0}; + long lRet; + int retval = -1; + + + if(!lpIPAddress) { + return retval; + } + if(!pnPort) { + return retval; + } + + // use the registry read of HKCU\\software\microsoft\windows\current version\internet settings to see if "Use Automatic Configuration Script" is checked + lstrcpyn(szWPADLocation, "", MAX_PATH); + + lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + dwSize = sizeof(szWPADLocation); + lRet = RegQueryValueEx(hKey, "AutoConfigURL", NULL, &dwType, (LPBYTE)szWPADLocation, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_SZ) { + retval = ReadWPADFile(szWPADLocation, lpIPAddress, pnPort); + } + } + RegCloseKey(hKey); + + return retval; //0 = success +} + +// handles the "Use a proxy server for your LAN" checkbox +int GetProxyServerForLanProxySettings(LPSTR lpIPAddress, int *pnPort) +{ + DWORD dwType, dwSize; + HKEY hKey; + BOOL bDirectOrProxy; + char szProxy[MAX_PATH] = {0}; + long lRet; + int retval = -1; + + if(lpIPAddress) { + strcpy(lpIPAddress, ""); + } + if(pnPort) { + *pnPort = 0; + } + lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + dwSize = sizeof(szProxy); + lRet = RegQueryValueEx(hKey, "ProxyServer", NULL, &dwType, (LPBYTE)szProxy, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_SZ) { + retval = 0; + + bDirectOrProxy = FALSE; + if(IsDirect(szProxy)) { + // string is something like "DIRECT" + // It's a 'direct' kind of proxy. + bDirectOrProxy = TRUE; + + // set the 'out' parameters + if(lpIPAddress) { + strcpy(lpIPAddress, ""); + } + if(pnPort) { + *pnPort = 0; + } + } + + if(IsAProxy(szProxy)) { + char szProxyIP[MAX_PATH] = {0}; + + // string is something like "D + bDirectOrProxy = TRUE; + GetProxyIP(szProxy, szProxyIP); + // It's a 'regular' kind of proxy, with an IP of %s and a port of %d\n", szProxyIP, GetProxyPort(szProxy) + + // set the 'out' parameters + if(lpIPAddress) { + strcpy(lpIPAddress, szProxyIP); + } + if(pnPort) { + *pnPort = GetProxyPort(szProxy); + } + } + + if(!bDirectOrProxy) { + // string is something like "10.0.0.1:4543" + LPSTR lpColon = NULL; + + if ( isdigit(szProxy[0]) ) + { + lpColon = strchr(szProxy, ':'); + if(lpColon) { + *lpColon = '\0'; + + // set the 'out' parameters + if(lpIPAddress) { + strcpy(lpIPAddress, szProxy); + } + *lpColon = ':'; + if(pnPort) { + *pnPort = GetProxyPort(szProxy); + } + } + } + else if ( strstr(szProxy,"http=") ) + { + char *p = strstr(szProxy,"http="); + int offset= strlen("http="); + char *semi = strchr(p+offset, ';'); + if(semi) { + *semi= '\0'; + } + lpColon = strchr(p+offset, ':'); + if(lpColon) { + *lpColon = '\0'; + } + // set the 'out' parameters + if(lpIPAddress) { + strcpy(lpIPAddress, p+offset); + } + if (lpColon) + if(pnPort) { + *pnPort = (short)atoi(lpColon+1); + } + if ( !*pnPort ) *pnPort = 80; + + } + else + { + if(lpIPAddress) { + strcpy(lpIPAddress, ""); + } + if(pnPort) { + *pnPort = 0; + } + } + } + } + } + RegCloseKey(hKey); + + return retval; +} + +int ReadWPADFile(LPSTR lpWPADLocation, LPSTR lpIPAddress, int *pnPort) +{ + // Declare function pointers for the three autoproxy functions + pfnInternetInitializeAutoProxyDll pInternetInitializeAutoProxyDll; + pfnInternetDeInitializeAutoProxyDll pInternetDeInitializeAutoProxyDll; + pfnInternetGetProxyInfo pInternetGetProxyInfo; + + // Declare and populate an AutoProxyHelperVtbl structure, and then + // place a pointer to it in a containing AutoProxyHelperFunctions + // structure, which will be passed to InternetInitializeAutoProxyDll: + AutoProxyHelperVtbl Vtbl = {IsResolvable, GetIPAddress, ResolveHostName, IsInNet }; + AutoProxyHelperFunctions HelperFunctions = { &Vtbl }; + HMODULE hModJS; + HRESULT hr; + char szTempPath[MAX_PATH] = {0}; + char szTempFile[MAX_PATH] = {0}; + int retval = 0; + + + if(!(hModJS = LoadLibrary("jsproxy.dll"))) { + reportFuncErr("LoadLibrary"); + return -1; + } + + if(!(pInternetInitializeAutoProxyDll = (pfnInternetInitializeAutoProxyDll) + GetProcAddress(hModJS, "InternetInitializeAutoProxyDll")) || + !(pInternetDeInitializeAutoProxyDll = (pfnInternetDeInitializeAutoProxyDll) + GetProcAddress(hModJS, "InternetDeInitializeAutoProxyDll")) || + !(pInternetGetProxyInfo = (pfnInternetGetProxyInfo) + GetProcAddress(hModJS, "InternetGetProxyInfo"))) { + FreeLibrary(hModJS); + reportFuncErr("GetProcAddress"); + return -1; + } + + if(lpIPAddress) + { + strcpy(lpIPAddress, ""); + } + if(pnPort) { + *pnPort = 0; + } + + GetTempPathA(sizeof(szTempPath)/sizeof(szTempPath[0]), szTempPath); + GetTempFileNameA(szTempPath, "X", 2, szTempFile); + //printf(" Downloading %s ...\n", lpWPADLocation); + hr = JNetLibDownloadToFile(NULL, lpWPADLocation, szTempFile, NULL, NULL); + if(hr == S_OK) { + if(!pInternetInitializeAutoProxyDll(0, szTempFile, NULL, &HelperFunctions, NULL)) { + //printf(" Calling 'InternetInitializeAutoProxyDll' in JSPROXY.DLL failed\n (usually because 'Use Automatic Configuration Script' checkbox is OFF)\n"); + pInternetDeInitializeAutoProxyDll(NULL, 0); + FreeLibrary(hModJS); + retval = -1; + }else{ + // printf("\n InternetInitializeAutoProxyDll returned: %d\n", returnVal); + + // Delete the temporary file + // (or, to examine the auto-config script, comment out the + // file delete and substitute the following printf call) + // printf("\n The auto-config script temporary file is:\n %s\n", szTempFile); + DeleteFileA(szTempFile); + + DWORD dwSize = 0; + LPSTR pProxy = NULL; + if(!pInternetGetProxyInfo((LPSTR)gszURL, sizeof(gszURL), (LPSTR)gszHost, sizeof(gszHost), &pProxy, &dwSize)) { + reportFuncErr("InternetGetProxyInfo"); + retval = -1; + }else{ + // printf("\n Proxy is: %s\n", proxy); + if(IsDirect(pProxy)) { + //printf(" It's a 'direct' kind of proxy.\n"); + + // set the 'out' parameters + if(lpIPAddress) { + strcpy(lpIPAddress, ""); + } + if(pnPort) { + *pnPort = 0; + } + } + + if(IsAProxy(pProxy)) { + char szProxyIP[MAX_PATH] = {0}; + + GetProxyIP(pProxy, szProxyIP); + //printf(" It's a 'regular' kind of proxy, with an IP of %s and a port of %d\n", szProxyIP, GetProxyPort(szProxy)); + + // set the 'out' parameters + if(lpIPAddress) { + strcpy(lpIPAddress, szProxyIP); + } + if(pnPort) { + *pnPort = GetProxyPort(pProxy); + } + } + } + } + }else{ + //printf(" Error downloading %s (hr=0x%X)\n", lpWPADLocation, hr); + // there is no proxy, go direct + if(lpIPAddress) { + strcpy(lpIPAddress, ""); + } + if(pnPort) { + *pnPort = 0; + } + retval = 0; + } + + if(!pInternetDeInitializeAutoProxyDll(NULL, 0)) { + reportFuncErr("InternetDeInitializeAutoProxyDll"); + } + + return retval; // 0 = success +} + + +// Puts "10.0.0.1" into lpDest from a string like "PROXY 10.0.0.1:8088" +// Returns 0 if success, -1 if an error +int GetProxyIP(LPSTR lpProxy, LPSTR lpDest) +{ + LPSTR lpData; + LPSTR lpLastColon; + BOOL bDone; + char szProxy[MAX_PATH] = {0}; + int ret = 0; + + if(lpProxy && lpDest) { + lstrcpyn(szProxy, lpProxy, MAX_PATH); + + // find the last ":" in the string + lpLastColon = NULL; + lpData = szProxy; + while(*lpData) { + if(*lpData == ':') { + lpLastColon = lpData; + } + lpData++; + } + + if(lpLastColon) { + // truncate the string at the last colon + *lpLastColon = '\0'; + + bDone = FALSE; + while(lpData > szProxy && !bDone) { + if(*lpData == ' ') { + bDone = TRUE; + lpData++; + }else{ + lpData--; + } + } + strcpy(lpDest, lpData); + ret = 0; + }else { + strcpy(lpDest, lpProxy); + ret =0; + } + }else{ + ret = -1; + } + + return ret; +} + +// Returns 8088 from a string like "PROXY 10.0.0.1:8088" +// Returns a port # if success, -1 if an error +int GetProxyPort(LPSTR lpProxy) +{ + LPSTR lpData; + LPSTR lpLastColon = NULL; + char szProxy[MAX_PATH] = {0}; + int ret = -1; + + if(lpProxy) { + lstrcpyn(szProxy, lpProxy, MAX_PATH); + + // find the last ":" in the string + lpData = szProxy; + while(*lpData) { + if(*lpData == ':') { + lpLastColon = lpData; + } + lpData++; + } + + // from the last colon to the end of the string is the port number + if ( lpLastColon ) + { + lpLastColon++; + ret = (unsigned short)atoi(lpLastColon); + } + else ret = 80; + } + + return ret; +} + +BOOL IsDirect(LPSTR proxy) +{ + BOOL bRet = FALSE; + + if(proxy) { + if(strstri("DIRECT", proxy)) { + bRet = TRUE; + } + } + + return bRet; +} + +BOOL IsAProxy(LPSTR proxy) +{ + BOOL bRet = FALSE; + + if(proxy) { + if(strstri("PROXY", proxy)) { + bRet = TRUE; + } + } + + return bRet; +} + +// like strstr() but case-insensitive +char * strstri(LPSTR lpOne, LPSTR lpTwo) +{ + unsigned int b; + char szOne[MAX_PATH] = {0}, szTwo[MAX_PATH] = {0}; + + if(lpOne && lpTwo) { + strcpy(szOne, lpOne); + strcpy(szTwo, lpTwo); + + for(b=0; b<strlen(szOne); b++) { + szOne[b] = tolower(szOne[b]); + } + + for(b=0; b<strlen(szTwo); b++) { + szTwo[b] = tolower(szTwo[b]); + } + } + + return strstr(szTwo, szOne); +} + +BOOL GetAutomaticallyDetectSettingsCheckboxState() +{ + DWORD dwSize, dwType; + HKEY hKey; + BOOL bAutomaticallyDetectSettings = FALSE; + long lRet; + + // see if the "Automatically Detect Settings" checkbox is on (I know, it's ugly) + // I noticed that the 9th byte in a binary struct at HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections\DefaultConnectionSettings" + // changes a bit to 1 or 0 based on the state of the checkbox. I'm using Windows XP. Not sure what byte to check on other Windows versions. + BYTE Buffer[200] = {0}; + + lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + dwSize = sizeof(Buffer); + lRet = RegQueryValueEx(hKey, "DefaultConnectionSettings", NULL, &dwType, (LPBYTE)&Buffer, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_BINARY) { + if(Buffer[8] & 8) { + bAutomaticallyDetectSettings = TRUE; + } + } + } + RegCloseKey(hKey); + + return bAutomaticallyDetectSettings; +} + +BOOL GetUseAProxyServerForYourLanCheckboxState() +{ + DWORD dwSize, dwValue, dwType; + HKEY hKey; + BOOL bUseAProxyServerForYourLan = FALSE; + long lRet; + + + // see if the "Use a proxy server for your LAN" checkbox is on + lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + dwSize = sizeof(DWORD); + lRet = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dwType, (LPBYTE)&dwValue, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_DWORD) { + bUseAProxyServerForYourLan = dwValue; + } + } + RegCloseKey(hKey); + + return bUseAProxyServerForYourLan; +} + +BOOL GetAutomaticConfigurationScriptCheckboxState() +{ + DWORD dwType, dwSize; + HKEY hKey; + BOOL bUseAutomaticConfigurationScript = FALSE; + char szWPAD[MAX_PATH] = {0}; + long lRet; + + +#if 1 + // use the registry read of HKCU\\software\microsoft\windows\current version\internet settings to see if "Use Automatic Configuration Script" is checked + szWPAD[0] = '\0'; + + lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + dwSize = sizeof(szWPAD); + lRet = RegQueryValueEx(hKey, "AutoConfigURL", NULL, &dwType, (LPBYTE)szWPAD, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_SZ) { + + } + } + RegCloseKey(hKey); +#else + // use DetectAutoProxyURL + if(!DetectAutoProxyUrl(szWPADLocation, sizeof(szWPADLocation), PROXY_AUTO_DETECT_TYPE_DHCP | PROXY_AUTO_DETECT_TYPE_DNS_A)) { + reportFuncErr("DetectAutoProxyUrl"); + } +#endif + + if(strlen(szWPAD)) { + bUseAutomaticConfigurationScript = TRUE; + } + + return bUseAutomaticConfigurationScript; +} + +BOOL GetBypassProxyServerForLocalAddressesCheckboxState() +{ + DWORD dwSize, dwType; + HKEY hKey; + BOOL bBypassProxyServerForLocalAddresses = FALSE; + char szBuffer[MAX_PATH] = {0}; + long lRet; + + dwSize = sizeof(szBuffer); + lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (lRet == ERROR_SUCCESS) { + lRet = RegQueryValueEx(hKey, "ProxyOverride", NULL, &dwType, (LPBYTE)&szBuffer, &dwSize); + if(lRet == ERROR_SUCCESS && dwType == REG_SZ) { + + } + } + RegCloseKey(hKey); + + if(strcmp(szBuffer, "<local>") == 0) { + bBypassProxyServerForLocalAddresses = TRUE; + } + + return bBypassProxyServerForLocalAddresses; +} + + +/* ================================================================== + HELPER FUNCTIONS + ================================================================== */ +// ResolveHostName (a helper function) +DWORD __stdcall ResolveHostName(LPSTR lpszHostName, LPSTR lpszIPAddress, LPDWORD lpdwIPAddressSize) +{ + DWORD dwIPAddressSize; + addrinfo Hints; + LPADDRINFO lpAddrInfo; + LPADDRINFO IPv4Only; + DWORD error; + + // Figure out first whether to resolve a name or an address literal. + // If getaddrinfo() with the AI_NUMERICHOST flag succeeds, then + // lpszHostName points to a string representation of an IPv4 or IPv6 + // address. Otherwise, getaddrinfo() should return EAI_NONAME. + ZeroMemory(&Hints, sizeof(addrinfo)); + Hints.ai_flags = AI_NUMERICHOST; // Only check for address literals. + Hints.ai_family = PF_UNSPEC; // Accept any protocol family. + Hints.ai_socktype = SOCK_STREAM; // Constrain results to stream socket. + Hints.ai_protocol = IPPROTO_TCP; // Constrain results to TCP. + + error = getaddrinfo(lpszHostName, NULL, &Hints, &lpAddrInfo); + if(error != EAI_NONAME) { + if(error != 0) { + error = (error == EAI_MEMORY) ? + ERROR_NOT_ENOUGH_MEMORY : ERROR_INTERNET_NAME_NOT_RESOLVED; + goto quit; + } + freeaddrinfo(lpAddrInfo); + + // An IP address (either v4 or v6) was passed in, so if there is + // room in the lpszIPAddress buffer, copy it back out and return. + dwIPAddressSize = lstrlen(lpszHostName); + + if((*lpdwIPAddressSize < dwIPAddressSize) || (lpszIPAddress == NULL)) { + *lpdwIPAddressSize = dwIPAddressSize + 1; + error = ERROR_INSUFFICIENT_BUFFER; + goto quit; + } + lstrcpy(lpszIPAddress, lpszHostName); + goto quit; + } + + // Call getaddrinfo() again, this time with no flag set. + Hints.ai_flags = 0; + error = getaddrinfo(lpszHostName, NULL, &Hints, &lpAddrInfo); + if(error != 0) { + error = (error == EAI_MEMORY) ? + ERROR_NOT_ENOUGH_MEMORY : ERROR_INTERNET_NAME_NOT_RESOLVED; + goto quit; + } + + // Convert the IP address in addrinfo into a string. + // (the following code only handles IPv4 addresses) + IPv4Only = lpAddrInfo; + while(IPv4Only->ai_family != AF_INET) { + IPv4Only = IPv4Only->ai_next; + if(IPv4Only == NULL) + { + error = ERROR_INTERNET_NAME_NOT_RESOLVED; + goto quit; + } + } + error = getnameinfo(IPv4Only->ai_addr, (socklen_t)IPv4Only->ai_addrlen, lpszIPAddress, *lpdwIPAddressSize, NULL, 0, NI_NUMERICHOST); + if(error != 0) + error = ERROR_INTERNET_NAME_NOT_RESOLVED; + +quit: + return(error); +} + + +// IsResolvable (a helper function) +BOOL __stdcall IsResolvable(LPSTR lpszHost) +{ + char szDummy[255] = {0}; + DWORD dwDummySize = sizeof(szDummy) - 1; + + if(ResolveHostName(lpszHost, szDummy, &dwDummySize)) + return(FALSE); + + return TRUE; +} + + +// GetIPAddress (a helper function) +DWORD __stdcall GetIPAddress(LPSTR lpszIPAddress, LPDWORD lpdwIPAddressSize) +{ + char szHostBuffer[255] = {0}; + + if(gethostname(szHostBuffer, sizeof(szHostBuffer) - 1) != ERROR_SUCCESS) + return(ERROR_INTERNET_INTERNAL_ERROR); + + return(ResolveHostName(szHostBuffer, lpszIPAddress, lpdwIPAddressSize)); +} + + +// IsInNet (a helper function) +BOOL __stdcall IsInNet(LPSTR lpszIPAddress, LPSTR lpszDest, LPSTR lpszMask) +{ + DWORD dwDest; + DWORD dwIpAddr; + DWORD dwMask; + + dwIpAddr = inet_addr(lpszIPAddress); + dwDest = inet_addr(lpszDest); + dwMask = inet_addr(lpszMask); + + if((dwDest == INADDR_NONE) || (dwIpAddr == INADDR_NONE) || ((dwIpAddr & dwMask) != dwDest)) + return(FALSE); + + return(TRUE); +} + + +// reportFuncErr (simple error reporting) +void reportFuncErr(TCHAR* funcName) +{ + //printf(" ERROR: %s failed with error number %d.\n", funcName, GetLastError()); +} + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +class CProfileFolder +{ +public: + int GetProfileFolder(LPSTR lpProfileFolder, BOOL bFirefox); + +private: + int GetProfileFolder_9598ME(LPSTR lpProfileFolder, BOOL bFirefox); + int GetProfileFolder_2000XP(LPSTR lpProfileFolder, BOOL bFirefox); +}; + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +class CMozSettings +{ +public: + CMozSettings(BOOL bFirefox); + virtual ~CMozSettings(); + int GetPreference(LPSTR lpPreferenceWanted, int *pnDest); + int GetPreference(LPSTR lpPreferenceWanted, LPSTR lpDest, int sizeof_dest); + +private: + CProfileFolder m_pf; + HGLOBAL m_hData; + LPSTR m_lpData; + int m_sizeof_data; +}; + +int CProfileFolder::GetProfileFolder(LPSTR lpProfileFolder, BOOL bFirefox) +{ + // See http://www.mozilla.org/support/firefox/edit for where I got this info: + // On Windows XP/2000, the path is usually %AppData%\Mozilla\Firefox\Profiles\xxxxxxxx.default\, where xxxxxxxx is a random string of characters. Just browse to C:\Documents and Settings\[User Name]\Application Data\Mozilla\Firefox\Profiles\ and the rest should be obvious. + // On Windows 95/98/Me, the path is usually C:\WINDOWS\Application Data\Mozilla\Firefox\Profiles\xxxxxxxx.default\ + // On Linux, the path is usually ~/.mozilla/firefox/xxxxxxxx.default/ + // On Mac OS X, the path is usually ~/Library/Application Support/Firefox/Profiles/xxxxxxxx.default/ + OSVERSIONINFO version; + + ZeroMemory(&version, sizeof(version)); + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + if(version.dwMajorVersion == 3) { + return -1; // NT 3.51 not supported + } + if(version.dwMajorVersion == 4) { + return GetProfileFolder_9598ME(lpProfileFolder, bFirefox); + } + if(version.dwMajorVersion >= 5) { + return GetProfileFolder_2000XP(lpProfileFolder, bFirefox); + } + + return -1; +} + +// private function for GetProfileFolder() +// on my test system, the folder to get is c:\windows\application data\mozilla\profiles\default\y3h9azmi.slt +int CProfileFolder::GetProfileFolder_9598ME(LPSTR lpProfileFolder, BOOL bFirefox) +{ + WIN32_FIND_DATA fd; + HANDLE hFind; + BOOL bDone, bFound; + char szHomePath[MAX_PATH] = {0}; + char szTemp[MAX_PATH] = {0}; + + + if(lpProfileFolder) { + GetEnvironmentVariable("WINDIR", szHomePath, sizeof(szHomePath)); + strcpy(lpProfileFolder, szHomePath); + if(bFirefox) { + strcat(lpProfileFolder, "\\Application Data\\Mozilla\\Firefox\\Profiles\\"); + }else{ + strcat(lpProfileFolder, "\\Application Data\\Mozilla\\Profiles\\default\\"); + } + + // find the first folder in the the path specified in szProfileFolder + lstrcpyn(szTemp, lpProfileFolder, MAX_PATH-4); + strcat(szTemp, "*.*"); + + bDone = FALSE; + bFound = FALSE; + hFind = FindFirstFile(szTemp, &fd); + while(hFind != INVALID_HANDLE_VALUE && !bDone) { + if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // we're at a directory. + // make sure it's not "." or ".." + if(fd.cFileName[0] != '.') { + bFound = TRUE; + } + } + + bDone = !FindNextFile(hFind, &fd); + } + FindClose(hFind); + + if(bFound) { + strcat(lpProfileFolder, fd.cFileName); + return 0; + } + } + + return -1; +} + +// private function for GetProfileFolder() +int CProfileFolder::GetProfileFolder_2000XP(LPSTR lpProfileFolder, BOOL bFirefox) +{ + WIN32_FIND_DATA fd; + HANDLE hFind; + BOOL bDone, bFound; + char szHomePath[MAX_PATH] = {0}; + char szTemp[MAX_PATH] = {0}; + + + if(lpProfileFolder) { + GetEnvironmentVariable("APPDATA", szHomePath, sizeof(szHomePath)); + strcpy(lpProfileFolder, szHomePath); + if(bFirefox) { + strcat(lpProfileFolder, "\\Mozilla\\Firefox\\Profiles\\"); + }else{ + strcat(lpProfileFolder, "\\Mozilla\\Profiles\\default\\"); + } + + // find the first folder in the the path specified in szProfileFolder + strcpy(szTemp, lpProfileFolder); + strcat(szTemp, "*.*"); + + bDone = FALSE; + bFound = FALSE; + hFind = FindFirstFile(szTemp, &fd); + while(hFind != INVALID_HANDLE_VALUE && !bDone) { + if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // we're at a directory. + // make sure it's not "." or ".." + if(fd.cFileName[0] != '.') { + bFound = TRUE; + } + } + + bDone = !FindNextFile(hFind, &fd); + } + FindClose(hFind); + + if(bFound) { + strcat(lpProfileFolder, fd.cFileName); + return 0; + } + } + + return -1; +} + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +CMozSettings::CMozSettings(BOOL bFirefox) +{ + WIN32_FIND_DATA fd; + OFSTRUCT of; + HANDLE hFind; + HFILE hPrefsFile; + char szProfileFolder[MAX_PATH] = {0}; + char szPrefsFile[MAX_PATH] = {0}; + int ret; + + + m_hData = NULL; + m_lpData = NULL; + + ret = m_pf.GetProfileFolder(szProfileFolder, bFirefox); + + + if(ret == 0) { + // We found the folder where prefs.js lives. Read it in. + strcpy(szPrefsFile, szProfileFolder); + strcat(szPrefsFile, "\\prefs.js"); + + // get the size of the file and alloc memory for it + hFind = FindFirstFile(szPrefsFile, &fd); + if(hFind != INVALID_HANDLE_VALUE) { + m_hData = GlobalAlloc(GHND, fd.nFileSizeLow + 256); + if(m_hData) { + m_lpData = (LPSTR)GlobalLock(m_hData); + if(m_lpData) { + hPrefsFile = OpenFile(szPrefsFile, &of, OF_READ); + if(hPrefsFile) { + m_sizeof_data = fd.nFileSizeLow; + _lread(hPrefsFile, m_lpData, m_sizeof_data); + _lclose(hPrefsFile); + hPrefsFile = NULL; + } + } + } + + FindClose(hFind); + } + } +} + +CMozSettings::~CMozSettings() +{ + if(m_lpData) { + GlobalUnlock(m_hData); + m_lpData = NULL; + } + + if(m_hData) { + GlobalFree(m_hData); + m_hData = NULL; + } +} + +int CMozSettings::GetPreference(LPSTR lpPreferenceWanted, LPSTR lpDest, int sizeof_dest) +{ + LPSTR lpPointer, lpPointerEnd, lpData; + LPSTR lpLineStart, lpSearchStart, lpFoundString, lpResult; + BOOL bDone; + int nDoubleQuoteCount, retval; + + + retval = -1; + if(m_lpData) { + if(lpPreferenceWanted) { + if(lpDest) { + *lpDest = '\0'; + bDone = FALSE; + lpPointer = m_lpData; + lpPointerEnd = lpPointer + m_sizeof_data; + + while(lpPointer < lpPointerEnd && !bDone) { + if(strncmp(lpPointer, "user_pref(", 10) == 0) { + lpLineStart = lpPointer; + lpSearchStart = lpLineStart + 11; + if(strncmp(lpSearchStart, lpPreferenceWanted, strlen(lpPreferenceWanted)) == 0) { + lpFoundString = lpSearchStart + strlen(lpPreferenceWanted); + + // lpFoundString almost points to what we want. Skip over the " character it's at now, skip over the " character + // starting the value we want and null-terminate what we want when we find the 3rd " character + lpData = lpFoundString; + nDoubleQuoteCount = 0; + while(nDoubleQuoteCount <= 3 && !bDone && lpData < lpPointerEnd) { + if(*lpData == '"') { + nDoubleQuoteCount++; + if(nDoubleQuoteCount == 2) { + // we're at the starting quote + lpResult = lpData; + lpResult++; + } + if(nDoubleQuoteCount == 3) { + // we're at the ending quote + // null-terminate what we want, and copy it to the dest buffer + *lpData = '\0'; + lstrcpyn(lpDest, lpResult, sizeof_dest); + + bDone = TRUE; + retval = 0; + } + } + lpData++; + } + } + } + + lpPointer++; + } + } + } + } + + return retval; +} + +int CMozSettings::GetPreference(LPSTR lpPreferenceWanted, int *pnDest) +{ + LPSTR lpPointer, lpPointerEnd, lpData; + LPSTR lpLineStart, lpSearchStart, lpFoundString; + BOOL bDone; + int retval; + + + retval = -1; + if(m_lpData) { + if(lpPreferenceWanted) { + if(pnDest) { + bDone = FALSE; + lpPointer = m_lpData; + lpPointerEnd = lpPointer + m_sizeof_data; + + while(lpPointer < lpPointerEnd && !bDone) { + if(strncmp(lpPointer, "user_pref(", 10) == 0) { + lpLineStart = lpPointer; + lpSearchStart = lpLineStart + 11; + if(strncmp(lpSearchStart, lpPreferenceWanted, strlen(lpPreferenceWanted)) == 0) { + lpFoundString = lpSearchStart + strlen(lpPreferenceWanted); + + // lpFoundString almost points to what we want. Skip over the " character it's at now, skip over the "," + // starting the value we want and null-terminate what we want when we find the 3rd " character + lpData = lpFoundString; + while(*lpData != ',' && lpData < lpPointerEnd) { + lpData++; + } + if(*lpData == ',') { + lpData++; + + lpFoundString = lpData; + while(*lpData != ')' && lpData < lpPointerEnd) { + lpData++; + } + if(*lpData == ')') { + // null-terminate what we want, and copy it to the dest buffer + *lpData = '\0'; + *pnDest = atoi(lpFoundString); + bDone = TRUE; + + retval = 0; + } + } + } + } + + lpPointer++; + } + } + } + } + + return retval; +} + +//////////////////////////////////////////////////////////////////////// +BOOL IsFirefoxProxySet() +{ + return IsFirefoxOrMozillaProxySet(TRUE); +} + +BOOL IsMozillaProxySet() +{ + return IsFirefoxOrMozillaProxySet(FALSE); +} + +BOOL IsFirefoxOrMozillaProxySet(BOOL bFirefox) +{ + CMozSettings settings(bFirefox); + int ret, nValue; + + ret = settings.GetPreference("network.proxy.type", &nValue); + if(ret == 0) { + switch(nValue) { + case 0: // shouldn't get here + break; + case 1: // manual configuration + return TRUE; + case 2: // automatic configuration + return TRUE; + case 4: // auto-detect + return TRUE; + default: // don't know + break; + } + } + + return FALSE; +} + +int ResolveURL_Mozilla(LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort) +{ + return ResolveURL_MozillaOrFirefox(FALSE, lpURL, lpHostname, lpIPAddress, sizeof_address, pnPort); +} + +int ResolveURL_Firefox(LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort) +{ + return ResolveURL_MozillaOrFirefox(TRUE, lpURL, lpHostname, lpIPAddress, sizeof_address, pnPort); +} + +int ResolveURL_MozillaOrFirefox(BOOL bFirefox, LPSTR lpURL, LPSTR lpHostname, LPSTR lpIPAddress, int sizeof_address, int *pnPort) +{ + CMozSettings setting(bFirefox); + int ret, nValue; + + + // search for the "network.proxy.http" preference + ret = setting.GetPreference("network.proxy.type", &nValue); + if(ret == 0) { + switch(nValue) { + case 0: + // shouldn't get here + break; + + case 1: + // manual configuration + setting.GetPreference("network.proxy.http", lpIPAddress, sizeof_address); + setting.GetPreference("network.proxy.http_port", pnPort); + break; + + case 2: + // automatic configuration + { + char szWPADLocation[MAX_PATH] = {0}; + + setting.GetPreference("network.proxy.autoconfig_url", szWPADLocation, sizeof(szWPADLocation)); + ret = ReadWPADFile(szWPADLocation, lpIPAddress, pnPort); + } + break; + + case 4: + // Auto-detect proxy settings for this network + ret = ReadWPADFile("http://wpad/wpad.dat", lpIPAddress, pnPort); + break; + + default: + break; + } + } + + return ret; +} + + +// My function that downloads from a URL to a file using the Nullsoft JNetLib library instead of using +// URLDownloadToFile(). Only parameters 2 and 3 are used, to mimick the parameters of URLDownloadToFile(). +HRESULT JNetLibDownloadToFile(LPVOID lpUnused1, LPSTR lpWPADLocation, LPSTR lpTempFile, LPVOID lpUnused2, LPVOID lpUnused3) +{ + api_httpreceiver *http=0; + waServiceFactory *sf=0; + + OFSTRUCT of; + HGLOBAL hData; + HRESULT hRet = S_FALSE; // default return value + LPSTR lpData; + DWORD dwSize; + HFILE hFile; + BOOL bDone; + //JNL jNetLib; + int ret; + + + if(lpWPADLocation && lpTempFile) + { + if (WASABI_API_SVC) + { + sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID); + if (sf) http = (api_httpreceiver *)sf->getInterface(); + } + if (!http) + return S_FALSE; + + // init the library and open a connection to the URL + http->Open(); + http->Connect(lpWPADLocation); + + // loop until JNetLib gets the data. + // run() returns 0 if OK, -1 if error (call geterrorstr()), or 1 if connection closed. + bDone = FALSE; + while(!bDone) { + ret = http->Run(); + if(ret == -1 || ret == 1) { + bDone = TRUE; + } + Sleep(50); + } + + + dwSize = (DWORD)http->GetContentLength(); + if(dwSize && ret == 1) { + // Got something! + // Allocate memory for it and write it to lpTempFile + hData = GlobalAlloc(GHND, dwSize + 100); + if(hData) { + lpData = (LPSTR)GlobalLock(hData); + if(lpData) { + http->GetBytes(lpData, (int)dwSize); + + // create the output file and write to it + hFile = OpenFile(lpTempFile, &of, OF_CREATE); + if(hFile != HFILE_ERROR) { + _lwrite(hFile, lpData, (UINT)dwSize); + _lclose(hFile); + + hRet = S_OK; // success + } + + GlobalUnlock(hData); + lpData = NULL; + } + + GlobalFree(hData); + hData = NULL; + } + } + } +if (http && sf) +sf->releaseInterface(http); + return hRet; +} +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/Main.cpp b/Src/Plugins/Input/in_nsv/Main.cpp new file mode 100644 index 00000000..159ee873 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/Main.cpp @@ -0,0 +1,976 @@ +#define PLUGIN_NAME "Nullsoft NSV Decoder" +#define PLUGIN_VERSION L"1.76" + +#include <windows.h> +#include "../Winamp/in2.h" +#include "../nsv/nsvplay/main.h" +#include "resource.h" +#include "../nu/AutoWide.h" +#include "../nu/AutoCharFn.h" +#define NO_IVIDEO_DECLARE +#include "../winamp/wa_ipc.h" +#include "../Winamp/strutil.h" +#include "api.h" +extern In_Module mod; // the output module (filled in near the bottom of this file) + +#define g_hInstance mod.hDllInstance +#define WNDMENU_CAPTION L"Winamp in_nsv" +#define MODAL_ABOUT +#define LOC_MODAL_ABOUT +#include "../nsv/nsvplay/about.h" +#undef g_hInstance + +#include <shlwapi.h> +#include <strsafe.h> +extern int config_precseek; +extern int config_vidoffs; +extern int config_bufms; +extern int config_prebufms; +extern int config_underunbuf; +extern int config_bufms_f; +extern int config_prebufms_f; +extern int config_underunbuf_f; + +// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F} +static const GUID playbackConfigGroupGUID = + { + 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } + }; + + +char lastfn[1024] = {0}; // currently playing file (used for getting info on the current file) +static char statusbuf[1024]; + +char stream_url[1024] = {0}; + +ULONGLONG g_bufferstat; +int m_last_bitrate; +void config_read(); +void config_write(); +void config(HWND hwndParent); + +int file_length = 0; // file length, in bytes +// Used for correcting DSP plug-in pitch changes +int paused = 0; // are we paused? +volatile int seek_needed; // if != -1, it is the point that the decode +// thread should seek to, in ms. + +CRITICAL_SECTION g_decoder_cs; +char g_streaminfobuf[512] = {0}; +int g_streaminfobuf_used = 0; + +char error_string[128] = {0}; + +volatile int killDecodeThread = 0; // the kill switch for the decode thread +HANDLE thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread + +int has_opened_outmod = 0; +int m_srate = 0; // seek needs this + +int decoders_initted = 0; + +api_config *AGAVE_API_CONFIG = 0; +api_memmgr *WASABI_API_MEMMGR = 0; +// wasabi based services for localisation support +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; + +void process_url(char *url) +{ + lstrcpynA(stream_url, url, sizeof(stream_url)); + + // if (!strncmp(stream_url,"hTtP",4)) + // { + // DWORD dw; + // SendMessageTimeout(mod.hMainWindow,WM_USER,(WPARAM)0,241,SMTO_NORMAL,500,&dw); + // } // I (Tag) removed this support, its annoying. + DWORD_PTR dw = 0; + if (stream_url[0]) SendMessageTimeout(mod.hMainWindow, WM_USER, (WPARAM)stream_url, 241, SMTO_NORMAL, 500, &dw); +} + +char last_title_sent[256] = {0}; + +void process_metadata(char *data, int len) +{ + if (len && *data) + { + char *ld; + 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 (!lstrcmpiA(n, "StreamTitle")) + { + lstrcpynA(last_title_sent, ld, sizeof(last_title_sent)); + last_title_sent[sizeof(last_title_sent) - 1] = 0; + PostMessage(mod.hMainWindow, WM_USER, 0, 243); + } + else if (!lstrcmpiA(n, "StreamUrl")) + { + process_url(ld); + } + } + else break; + } + } +} + +class WA2AudioOutput : public IAudioOutput +{ +public: + WA2AudioOutput(int srate, int nch, int bps) + { + memset(m_stuffbuf, 0, sizeof(m_stuffbuf)); + decode_pos_samples = 0; + m_srate = srate; m_bps = bps; m_nch = nch; + m_open_success = 0; + m_stuffbuf_u = 0; + int maxlat = mod.outMod->Open(srate, nch, bps, -1, -1); + if (maxlat == 0 && strstr(lastfn, "://")) + { + maxlat = -1; + mod.outMod->Close(); // boom + } + if (maxlat >= 0) + { + mod.SetInfo( -1, srate / 1000, nch, 1); + mod.SAVSAInit(maxlat, srate); + mod.VSASetInfo(srate, nch); + mod.outMod->SetVolume( -666); + m_open_success = 1; + has_opened_outmod = 1; + } + } + ~WA2AudioOutput(){} + + int canwrite() + { + int a = mod.outMod->CanWrite(); + if (mod.dsp_isactive() == 1) a /= 2; + return a & ~((m_nch * (m_bps / 8)) - 1); + } // returns bytes writeable + + void write(void *buf, int len) + { + char *b = (char *)buf; + int s = 576 * m_nch * (m_bps / 8); + if (s > sizeof(m_stuffbuf)) s = sizeof(m_stuffbuf); + + while (len > 0) + { + int l = s; + if (!m_stuffbuf_u && len >= s) // straight copy of data + { + int dms = (int) ((decode_pos_samples * (__int64)1000) / (__int64)m_srate); + mod.SAAddPCMData(b, m_nch, m_bps, dms); + mod.VSAAddPCMData(b, m_nch, m_bps, dms); + } + else if (m_stuffbuf_u + len >= s) + { + int dms = (int) (((decode_pos_samples - (m_stuffbuf_u / m_nch / (m_bps / 8))) * (__int64)1000) / (__int64)m_srate); + l = (s - m_stuffbuf_u); + memcpy(m_stuffbuf + m_stuffbuf_u, b, l); + m_stuffbuf_u = 0; + + mod.SAAddPCMData(m_stuffbuf, m_nch, m_bps, dms); + mod.VSAAddPCMData(m_stuffbuf, m_nch, m_bps, dms); + } + else // put all of len into m_stuffbuf + { + memcpy(m_stuffbuf + m_stuffbuf_u, b, len); + m_stuffbuf_u += len; + l = len; + } + + if (l > len)l = len; // this shouldn't happen but we'll leave it here just in case + + decode_pos_samples += (l / m_nch / (m_bps / 8)); + + if (mod.dsp_isactive()) + { + static char sample_buffer[576*2*(16 / 8)*2]; + int spll = l / m_nch / (m_bps / 8); + memcpy(sample_buffer, b, l); + int l2 = l; + if (spll > 0) l2 = mod.dsp_dosamples((short *)sample_buffer, spll, m_bps, m_nch, m_srate) * (m_nch * (m_bps / 8)); + mod.outMod->Write(sample_buffer, l2); + } + else mod.outMod->Write(b, l); + len -= l; + b += l; + } + } + ULONGLONG getwritepos() + { + return (unsigned int) ((decode_pos_samples * 1000) / m_srate); + } + ULONGLONG getpos() + { + if (seek_needed != -1) return seek_needed; + return (unsigned int) ((decode_pos_samples * 1000) / m_srate) + + (mod.outMod->GetOutputTime() - mod.outMod->GetWrittenTime()) - config_vidoffs; + } + void flush(unsigned int newtime) + { + m_stuffbuf_u = 0; + mod.outMod->Flush(newtime); + decode_pos_samples = (((__int64)newtime) * m_srate) / 1000; + } + void pause(int pause) + { + mod.outMod->Pause(pause); + } + int get_open_success() { return m_open_success; } + int isplaying(void) { return mod.outMod->IsPlaying(); } +private: + __int64 decode_pos_samples; // current decoding position, in milliseconds. + int m_nch, m_bps; + int m_open_success; + int m_stuffbuf_u; + char m_stuffbuf[576*2*2]; +}; + +IAudioOutput *PCMOUT_CREATE(unsigned int outfmt[8]) +{ + if (outfmt[1] && outfmt[2] && outfmt[3] && outfmt[0] == NSV_MAKETYPE('P', 'C', 'M', ' ')) + { + WA2AudioOutput *r = new WA2AudioOutput(outfmt[1], outfmt[2], outfmt[3]); + if (r->get_open_success()) return r; + delete r; + } + return NULL; +} + +DWORD WINAPI DecodeThread(LPVOID b); // the decode thread procedure + +void about(HWND hwndParent) +{ + do_about(hwndParent,WASABI_API_LNG_HINST); +} + +void SetFileExtensions(void) +{ + static char fileExtensionsString[1200] = {0}; // "NSV;NSA\0Nullsoft Audio/Video File (*.NSV;*.NSA)\0" + char* end = 0; + StringCchCopyExA(fileExtensionsString, 1200, "NSV;NSA", &end, 0, 0); + StringCchCopyExA(end+1, 1200, WASABI_API_LNGSTRING(IDS_NSA_NSV_FILE), 0, 0, 0); + mod.FileExtensions = fileExtensionsString; +} + +int init() +{ + if (!IsWindow(mod.hMainWindow)) + return IN_INIT_FAILURE; + + waServiceFactory *sf = mod.service->service_getServiceByGuid(AgaveConfigGUID); + if (sf) AGAVE_API_CONFIG = (api_config *)sf->getInterface(); + + sf = mod.service->service_getServiceByGuid(memMgrApiServiceGuid); + if (sf) WASABI_API_MEMMGR = reinterpret_cast<api_memmgr*>(sf->getInterface()); + + // loader so that we can get the localisation service api for use + sf = mod.service->service_getServiceByGuid(languageApiGUID); + if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface()); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(mod.hDllInstance,InNSVLangGUID); + + static wchar_t szDescription[256]; + StringCchPrintfW(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_NSV_DECODER),PLUGIN_VERSION); + mod.description = (char*)szDescription; + + SetFileExtensions(); + + config_read(); + InitializeCriticalSection(&g_decoder_cs); + return IN_INIT_SUCCESS; +} + +void quit() +{ + Decoders_Quit(); + DeleteCriticalSection(&g_decoder_cs); + waServiceFactory *sf = mod.service->service_getServiceByGuid(AgaveConfigGUID); + if (sf) sf->releaseInterface(AGAVE_API_CONFIG); + + sf = mod.service->service_getServiceByGuid(memMgrApiServiceGuid); + if (sf) sf->releaseInterface(WASABI_API_MEMMGR); +} + +int isourfile(const char *fn) +{ + // used for detecting URL streams.. unused here. + // return !strncmp(fn,"http://",7); to detect HTTP streams, etc + return !_strnicmp( fn, "unsv://", 7 ); +} + +NSVDecoder *m_decoder = 0; +IVideoOutput *m_video_output = 0; + +int g_play_needseek = -1; + +int play(const char *fn) +{ + m_last_bitrate = -1; + g_play_needseek = -1; + last_title_sent[0] = 0; + g_bufferstat = 0; + mod.is_seekable = 0; + has_opened_outmod = 0; + error_string[0] = 0; + if (!decoders_initted) + { + decoders_initted = 1; + char buf[MAX_PATH] = {0}, *p = buf; + GetModuleFileNameA(mod.hDllInstance, buf, sizeof(buf)); + while (p && *p) p++; + while (p && p > buf && *p != '\\') p--; + if (p) *p = 0; + Decoders_Init(buf); + } + + unsigned long thread_id = 0; + + paused = 0; + seek_needed = -1; + EnterCriticalSection(&g_decoder_cs); + if (strstr(fn, "://")) + WASABI_API_LNGSTRING_BUF(IDS_CONNECTING,error_string,128); + else + WASABI_API_LNGSTRING_BUF(IDS_OPENING,error_string,128); + + LeaveCriticalSection(&g_decoder_cs); + + m_video_output = (IVideoOutput *)SendMessage(mod.hMainWindow, WM_USER, 0, IPC_GET_IVIDEOOUTPUT); + if (!m_video_output) return 1; + + m_video_output->open(0, 0, 0, 0, 0); + + m_decoder = new NSVDecoder(fn, m_video_output, NULL); + lstrcpynA(lastfn, fn, sizeof(lastfn)); + + if (strstr(fn, "://") || !strncmp(fn, "\\\\", 2)) + { + m_decoder->SetPreciseSeeking(config_precseek&2); + m_decoder->SetBuffering(config_bufms, config_prebufms, config_underunbuf); + } + else + { + m_decoder->SetPreciseSeeking(config_precseek&1); + m_decoder->SetBuffering(config_bufms_f, config_prebufms_f, config_underunbuf_f); + } + + // launch decode thread + killDecodeThread = 0; + thread_handle = (HANDLE)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, NULL, 0, &thread_id); + SetThreadPriority(thread_handle, (int)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST)); + + return 0; +} + +// standard pause implementation +void pause() +{ + paused = 1; + // if (has_opened_outmod) mod.outMod->Pause(1); + // else + if (m_decoder) m_decoder->pause(1); +} +void unpause() +{ + paused = 0; + // if (has_opened_outmod) mod.outMod->Pause(0); + //else + if (m_decoder) m_decoder->pause(0); +} +int ispaused() { return paused; } + +// stop playing. +void stop() +{ + g_play_needseek = -1; + + if (thread_handle != INVALID_HANDLE_VALUE) + { + killDecodeThread = 1; + int nTimes = 0; + const int maxTimes = 1000; + while (WaitForSingleObject(thread_handle, 0) == WAIT_TIMEOUT) + { + MSG msg = {0}; + if (PeekMessage(&msg, NULL, 0, 0, 1)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + Sleep(10); + + nTimes++; + if (nTimes == maxTimes) + { +#ifdef WINAMPX + SendStatus( WINAMPX_STATUS_ERROR_KILLING_THREAD, 0 ); +#else + /*MessageBox(mod.hMainWindow, "error asking thread to die!\n", + "error killing decode thread", 0);*/ +#endif + TerminateThread(thread_handle, 0); + break; + } + } + CloseHandle(thread_handle); + thread_handle = INVALID_HANDLE_VALUE; + } + if (has_opened_outmod) mod.outMod->Close(); + g_bufferstat = 0; + has_opened_outmod = 0; + mod.SAVSADeInit(); + + EnterCriticalSection(&g_decoder_cs); + delete(m_decoder); + m_decoder = NULL; +LeaveCriticalSection(&g_decoder_cs); + g_streaminfobuf[0] = 0; +} + +int getlength() +{ + if (m_decoder) + { + int x = m_decoder->getlen(); + if (x != -1) return x; + } + return -1000; +} + +int getoutputtime() +{ + if (g_bufferstat) return (int)g_bufferstat; + EnterCriticalSection(&g_decoder_cs); + if (m_decoder) + { + LeaveCriticalSection(&g_decoder_cs); + return (int)(m_decoder ? m_decoder->getpos() + config_vidoffs : 0); + } + LeaveCriticalSection(&g_decoder_cs); + return 0; +} + +void setoutputtime(int time_in_ms) +{ + seek_needed = time_in_ms; +} + +void setvolume(int volume) { mod.outMod->SetVolume(volume); } + +void setpan(int pan) { mod.outMod->SetPan(pan); } + +int infoDlg(const char *fn, HWND hwnd); + +// this is an odd function. it is used to get the title and/or +// length of a track. +// if filename is either NULL or of length 0, it means you should +// return the info of lastfn. Otherwise, return the information +// for the file in filename. +// if title is NULL, no title is copied into it. +// if length_in_ms is NULL, no length is copied into it. +void getfileinfo(const char *filename, char *title, int *length_in_ms) +{ + if (!filename || !*filename) // currently playing file + { + EnterCriticalSection(&g_decoder_cs); + if (length_in_ms) *length_in_ms = getlength(); + if (title) // get non-path portion.of filename + { + char *p = NULL; + if (m_decoder) + { + p = m_decoder->getTitle(); + } + if (!p) + { + p = lastfn + strlen(lastfn); + while (p && *p != '\\' && p >= lastfn) p--; + p++; + } + while (p && *p == ';') p++; + title[0] = 0; + + if (error_string[0]) + { + StringCchPrintfA(title, GETFILEINFO_TITLE_LENGTH, "[%s] ", error_string); + } + if (!error_string[0] && last_title_sent[0]) + { + StringCchPrintfA(title, GETFILEINFO_TITLE_LENGTH-strlen(title), "%s (%s)", last_title_sent, p); + } + else + lstrcpynA(title + strlen(title), p, FILETITLE_SIZE); + } + LeaveCriticalSection(&g_decoder_cs); + } + else if (1) // some other file + { + if ((length_in_ms || title) && !strstr(filename, "://")) + { + nsv_InBS bs; + nsv_fileHeader hdr = {0, }; + if (length_in_ms) // calculate length + { + *length_in_ms = -1000; // the default is unknown file length (-1000). + } + if (title) // get non path portion of filename + { + const char *p = filename + strlen(filename); + while (p && *p != '\\' && p >= filename) p--; + lstrcpynA(title, ++p, GETFILEINFO_TITLE_LENGTH); + } + + IDataReader *rdr = CreateReader(filename); + + if (rdr) + { + while (!rdr->iseof()) + { + char buf[1024] = {0}; + int l = (int)rdr->read(buf, sizeof(buf)); + if (!l) break; + bs.add(buf, l); + l = nsv_readheader(bs, &hdr); + if (l <= 0) + { + if (!l) + { + if (length_in_ms) *length_in_ms = hdr.file_lenms; + if (title && hdr.metadata) + { + char *t = nsv_getmetadata(hdr.metadata, "TITLE"); + if (t) lstrcpynA(title, t, 1024); + } + } + free(hdr.metadata); + free(hdr.toc); + break; + } + } + delete rdr; + } + // try to parse out lengths + } + } +} + +void eq_set(int on, char data[10], int preamp) +{} + +DWORD WINAPI DecodeThread(LPVOID b) +{ + int last_bpos = -1; + int firstsynch = 0; + ULONGLONG next_status_time = 0; + while (!killDecodeThread) + { + EnterCriticalSection(&g_decoder_cs); + int r = m_decoder->run((int*)&killDecodeThread); + LeaveCriticalSection(&g_decoder_cs); + if (r < 0) + { + if (m_decoder->get_error()) + { + EnterCriticalSection(&g_decoder_cs); + lstrcpynA(error_string, m_decoder->get_error(), sizeof(error_string)); + LeaveCriticalSection(&g_decoder_cs); + PostMessage(mod.hMainWindow, WM_USER, 0, 243); + Sleep(200); + } + break; + } + else if (!r) + { + Sleep(1); + int br = m_decoder->getBitrate() / 1000; + if (br != m_last_bitrate) + { + m_last_bitrate = br; + mod.SetInfo(br, -1, -1, -1); + } + + int bpos = m_decoder->getBufferPos(); + if (bpos > 255) + { + ULONGLONG obuf = g_bufferstat; + g_bufferstat = 0; + if (last_bpos >= 0) + { + EnterCriticalSection(&g_decoder_cs); + error_string[0] = 0; + LeaveCriticalSection(&g_decoder_cs); + PostMessage(mod.hMainWindow, WM_USER, 0, 243); + last_bpos = -1; + int csa = mod.SAGetMode(); + if (csa && obuf) + { + char tempdata[75*2] = {0, }; + mod.SAAdd(tempdata, (int)++obuf, (csa == 3) ? 0x80000003 : csa); + } + } + } + else + { + if (!g_bufferstat) + { + if (!has_opened_outmod) mod.SAVSAInit(10, 44100); + + g_bufferstat = m_decoder->getpos() + 1; + } + + if (bpos != last_bpos) + { + last_bpos = bpos; + EnterCriticalSection(&g_decoder_cs); + StringCchPrintfA(error_string, 128, WASABI_API_LNGSTRING(IDS_BUFFER_X), (bpos*100) / 256); + LeaveCriticalSection(&g_decoder_cs); + int csa = mod.SAGetMode(); + char tempdata[2*75] = {0, }; + int x; + if (csa&1) + { + for (x = 0; x < bpos*75 / 256; x ++) + { + tempdata[x] = x * 16 / 75; + } + } + if (csa&2) + { + int offs = (csa & 1) ? 75 : 0; + x = 0; + while (x < bpos*75 / 256) + { + tempdata[offs + x++] = -6 + x * 14 / 75; + } + while (x < 75) + { + tempdata[offs + x++] = 0; + } + } + if (csa == 4) + { + tempdata[0] = tempdata[1] = (bpos * 127 / 256); + } + + if (csa) mod.SAAdd(tempdata, (int)++g_bufferstat, (csa == 3) ? 0x80000003 : csa); + PostMessage(mod.hMainWindow, WM_USER, 0, 243); + } + } + + if (GetTickCount64() > next_status_time || GetTickCount64() < next_status_time - 5000) + { + char statusbuf[1024] = {0}; + EnterCriticalSection(&g_decoder_cs); + g_streaminfobuf[0] = 0; + + if (g_streaminfobuf_used) + { + char *outp = g_streaminfobuf; + size_t size = 512; + const char *p = m_decoder->getServerHeader("server"); + if (!p) p = m_decoder->getServerHeader("icy-notice2"); + + if (p && strlen(p) < sizeof(g_streaminfobuf) - (outp - g_streaminfobuf) - 32) + StringCchPrintfExA(outp, size, &outp, &size, 0, "%s: %s\r\n", WASABI_API_LNGSTRING(IDS_SERVER), p); + + p = m_decoder->getServerHeader("content-type"); + if (p && strlen(p) < sizeof(g_streaminfobuf) - (outp - g_streaminfobuf) - 32) + StringCchPrintfExA(outp, size, &outp, &size, 0, "%s: %s\r\n", WASABI_API_LNGSTRING(IDS_CONTENT_TYPE), p); + + p = m_decoder->getServerHeader("content-length"); + if (p && strlen(p) < sizeof(g_streaminfobuf) - (outp - g_streaminfobuf) - 32) + StringCchPrintfExA(outp, size, &outp, &size, 0, "%s: %s\r\n", WASABI_API_LNGSTRING(IDS_CONTENT_LENGTH), p); + + p = m_decoder->getServerHeader("icy-name"); + if (p && strlen(p) < sizeof(g_streaminfobuf) - (outp - g_streaminfobuf) - 32) + StringCchPrintfExA(outp, size, &outp, &size, 0, "%s: %s\r\n", WASABI_API_LNGSTRING(IDS_STREAM_NAME), p); + } + + lstrcpynA(statusbuf, "NSV: ", 1024); + { // codecs + char *sb = statusbuf; + size_t size = 1024; + + int l = m_decoder->getlen(); + if (l > 0) + { + l /= 1000; + if (l >= 3600) + { + StringCchPrintfExA(sb, size, &sb, &size, 0, "%d:", l / 3600); + l %= 3600; + StringCchPrintfExA(sb, size, &sb, &size, 0, "%02d:%02d", l / 60, l % 60); + } + else + StringCchPrintfExA(sb, size, &sb, &size, 0, "%d:%02d", l / 60, l % 60); + } + + int a = (m_decoder->getBitrate() + 500) / 1000; + if (a) + { + if (strlen(statusbuf) > 5) + StringCchCatExA(sb, size, " @ ", &sb, &size, 0); + StringCchPrintfExA(sb, size, &sb, &size, 0, "%d%s", a, WASABI_API_LNGSTRING(IDS_KBPS)); + } + + if (strlen(statusbuf) > 5) + StringCchCatExA(sb, size, ", ", &sb, &size, 0); + + char *p = statusbuf + strlen(statusbuf); + m_decoder->getVideoDesc(p); + if (p && !*p) StringCchCopyExA(p, size, "?, ", &p, &size, 0); + else if (!strncmp(p, "NONE", 4)) *p = 0; + else StringCchCatExA(p, size, ", ", &p, &size, 0); + + p = statusbuf + strlen(statusbuf); + m_decoder->getAudioDesc(p); + if (p && !*p) StringCchCopyExA(p, size, "?", &p, &size, 0); + else if (!strncmp(p, "NONE", 4)) *p = 0; + } + LeaveCriticalSection(&g_decoder_cs); + m_video_output->extended(VIDUSER_SET_INFOSTRING, (intptr_t)statusbuf, 0); + + next_status_time = GetTickCount64() + 2500; + } + } + else + { + if (!firstsynch) + { + if (m_decoder->canseek()) + { + mod.is_seekable = 1; + if (g_play_needseek >= 0) seek_needed = g_play_needseek; + g_play_needseek = -1; + } + firstsynch++; + PostMessage(mod.hMainWindow, WM_USER, 0, 243); + } + } + if (seek_needed >= 0) + { + EnterCriticalSection(&g_decoder_cs); + m_decoder->seek(seek_needed); + seek_needed = -1; + LeaveCriticalSection(&g_decoder_cs); + } + } + if (!killDecodeThread) + { + PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0); + } + m_decoder->CloseVideo(); + return 0; +} + +// module definition. +In_Module mod = + { + IN_VER_RET, // defined in IN2.H + "nullsoft(in_nsv.dll)", + 0, // hMainWindow (filled in by winamp) + 0, // hDllInstance (filled in by winamp) + 0, // this is a double-null limited list. "EXT\0Description\0EXT\0Description\0" etc. + 1, // is_seekable + 1, // uses output plug-in system + config, + about, + init, + quit, + getfileinfo, + infoDlg, + isourfile, + play, + pause, + unpause, + ispaused, + stop, + + getlength, + getoutputtime, + setoutputtime, + + setvolume, + setpan, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, // visualization calls filled in by winamp + + 0, 0, // dsp calls filled in by winamp + + eq_set, + + NULL, // setinfo call filled in by winamp + + 0 // out_mod filled in by winamp + }; + +static FILETIME ftLastWriteTime; + +// is used to determine if the last write time of the file has changed when +// asked to get the metadata for the same cached file so we can update things +BOOL HasFileTimeChanged(const wchar_t *fn) +{ + WIN32_FILE_ATTRIBUTE_DATA fileData = {0}; + if (GetFileAttributesExW(fn, GetFileExInfoStandard, &fileData) == TRUE) + { + if(CompareFileTime(&ftLastWriteTime, &fileData.ftLastWriteTime)) + { + ftLastWriteTime = fileData.ftLastWriteTime; + return TRUE; + } + } + return FALSE; +} + +extern "C" +{ + __declspec( dllexport ) In_Module * winampGetInModule2() + { + return &mod; + } + + wchar_t lastextfn[1024] = {0}; + // Keep track of file timestamp for file system change notification handling + FILETIME last_write_time = {0, 0}; + static int valid; + static nsv_fileHeader hdr; + + bool isFileChanged(const wchar_t* file) + { + WIN32_FIND_DATAW FindFileData = {0}; + HANDLE hFind = FindFirstFileW(file, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + return true; + FindClose(hFind); + + if ((last_write_time.dwHighDateTime == + FindFileData.ftLastWriteTime.dwHighDateTime) && + (last_write_time.dwLowDateTime == + FindFileData.ftLastWriteTime.dwLowDateTime)) + { + return false; + } + return true; + } + + __declspec( dllexport ) int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, int destlen) + { + if (!_stricmp(data, "type")) + { + if (!fn || !fn[0] || _wcsicmp(PathFindExtensionW(fn), L".nsa")) // if extension is NOT nsa + lstrcpyn(dest, L"1", destlen); //video + else + lstrcpyn(dest, L"0", destlen); // audio + return 1; + } + + if (!fn || (fn && !fn[0])) + return 0; + + if (!_stricmp(data, "family")) + { + int pID = -1; + LPCWSTR e = PathFindExtensionW(fn); + if (L'.' != *e) return 0; + e++; + DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, e, -1, L"NSV", -1)) pID = IDS_FAMILY_STRING_NSV; + if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, e, -1, L"NSA", -1)) pID = IDS_FAMILY_STRING_NSA; + if (pID != -1 && S_OK == StringCchCopyW(dest, destlen, WASABI_API_LNGSTRINGW(pID))) return 1; + return 0; + } + + //the file name differs from the last file + //name but we need to check the time stamp too + if (_wcsicmp(fn, lastextfn) || isFileChanged(fn) || HasFileTimeChanged(fn)) + { + free(hdr.metadata); + memset(&hdr, 0, sizeof(hdr)); + valid = 0; + + lstrcpyn(lastextfn, fn, ARRAYSIZE(lastextfn)); + + nsv_InBS bs; + + IDataReader *rdr = CreateReader(AutoCharFn(lastextfn)); + + if (rdr) + { + while (!rdr->iseof()) + { + char buf[1024] = {0}; + int l = (int)rdr->read(buf, sizeof(buf)); + if (!l) break; + bs.add(buf, l); + l = nsv_readheader(bs, &hdr); + if (l <= 0) + { + free(hdr.toc); + if (!l) + { + valid = 1; + + //Save time stamp + WIN32_FIND_DATAW FindFileData = {0}; + HANDLE hFind = FindFirstFileW(fn, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + last_write_time.dwHighDateTime = NULL; + last_write_time.dwLowDateTime = NULL; + } + else + { + last_write_time.dwHighDateTime = FindFileData.ftLastWriteTime.dwHighDateTime; + last_write_time.dwLowDateTime = FindFileData.ftLastWriteTime.dwLowDateTime; + FindClose(hFind); + } + break; + } + break; + } + } + delete rdr; + } + } + + dest[0] = 0; + + if (!valid) + { + return 0; + } + + if (!_stricmp(data, "length")) + { + if (hdr.file_lenms > 0) + { + StringCchPrintfW(dest, destlen, L"%d", hdr.file_lenms); + } + } + else if (hdr.metadata) + { + const char *t = nsv_getmetadata(hdr.metadata, (char*)data); + if (t) lstrcpyn(dest, AutoWide(t), destlen); + } + + return 1; + } +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/api.h b/Src/Plugins/Input/in_nsv/api.h new file mode 100644 index 00000000..e94bdd9c --- /dev/null +++ b/Src/Plugins/Input/in_nsv/api.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_API_H +#define NULLSOFT_API_H + +#include "../Agave/Config/api_config.h" +extern api_config *configApi; +#define AGAVE_API_CONFIG configApi + +#include <api/memmgr/api_memmgr.h> +extern api_memmgr *memmgrApi; +#define WASABI_API_MEMMGR memmgrApi + +#include <api/service/waServiceFactory.h> + +#include "../Agave/Language/api_language.h" + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/config.cpp b/Src/Plugins/Input/in_nsv/config.cpp new file mode 100644 index 00000000..6c4ada01 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/config.cpp @@ -0,0 +1,197 @@ +#include <windows.h> +#include "api.h" +#include "resource.h" +#include "../Winamp/wa_ipc.h" +#include "../Winamp/in2.h" + +extern In_Module mod; // the output module (filled in near the bottom of this file) + +static char app_name[] = "Nullsoft NSV Decoder2"; + +//char config_http_proxynonport80=1; + +int config_padtag=1024; +int config_bufms=10000; +int config_prebufms=2000; +int config_underunbuf=3000; +int config_bufms_f=1000; +int config_prebufms_f=1000; +int config_underunbuf_f=1000; +int config_vidoffs=0; +int config_precseek=3; +int config_subtitles=1; + +void config_write(); + +char INI_FILE[512] = {0}; + +static int _r_i(char *name, int def) +{ + if (!_strnicmp(name,"config_",7)) name += 7; + return GetPrivateProfileIntA(app_name,name,def,INI_FILE); +} +#define RI(x) (( x ) = _r_i(#x,( x ))) +static void _w_i(char *name, int d) +{ + char str[120] = {0}; + wsprintfA(str,"%d",d); + if (!_strnicmp(name,"config_",7)) name += 7; + WritePrivateProfileStringA(app_name,name,str,INI_FILE); +} +#define WI(x) _w_i(#x,( x )) + +static void _r_s(char *name,char *data, int mlen) +{ + char buf[2048] = {0}; + strncpy(buf, data, 2048); + if (!_strnicmp(name,"config_",7)) name += 7; + GetPrivateProfileStringA(app_name,name,buf,data,mlen,INI_FILE); +} +#define RS(x) (_r_s(#x,x,sizeof(x))) + +static void _w_s(char *name, char *data) +{ + if (!_strnicmp(name,"config_",7)) name += 7; + WritePrivateProfileStringA(app_name,name,data,INI_FILE); +} +#define WS(x) (_w_s(#x,x)) + + + +static void config_init() +{ +char *p; + if (mod.hMainWindow && + (p = (char *)SendMessageA(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE)) + && p!= (char *)1) + { + strncpy(INI_FILE, p, MAX_PATH); + } + else + { + GetModuleFileNameA(NULL,INI_FILE,sizeof(INI_FILE)); + p=INI_FILE+strlen(INI_FILE); + while (p >= INI_FILE && *p != '.') p--; + strcpy(++p,"ini"); + } +} + +static INT_PTR CALLBACK configProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + // show config + SetDlgItemInt(hwndDlg,IDC_BUF1,config_bufms,FALSE); + SetDlgItemInt(hwndDlg,IDC_BUF2,config_prebufms,FALSE); + SetDlgItemInt(hwndDlg,IDC_BUF3,config_underunbuf,FALSE); + SetDlgItemInt(hwndDlg,IDC_BUF4,config_bufms_f,FALSE); + SetDlgItemInt(hwndDlg,IDC_BUF5,config_prebufms_f,FALSE); + SetDlgItemInt(hwndDlg,IDC_BUF6,config_underunbuf_f,FALSE); + SetDlgItemInt(hwndDlg,IDC_OFFS,config_vidoffs,TRUE); + SetDlgItemInt(hwndDlg,IDC_TAGPAD,config_padtag,FALSE); + if (config_precseek&1)CheckDlgButton(hwndDlg,IDC_CHECK1,BST_CHECKED); + if (config_precseek&2)CheckDlgButton(hwndDlg,IDC_CHECK2,BST_CHECKED); + if (config_subtitles)CheckDlgButton(hwndDlg,IDC_CHECK3,BST_CHECKED); +// if (!config_http_proxynonport80) CheckDlgButton(hwndDlg,IDC_CHECK5,BST_CHECKED); + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CHECK1: + case IDC_CHECK2: + config_precseek=(IsDlgButtonChecked(hwndDlg,IDC_CHECK1)?1:0)| + (IsDlgButtonChecked(hwndDlg,IDC_CHECK2)?2:0); + + break; + case IDC_CHECK3: + config_subtitles=(IsDlgButtonChecked(hwndDlg,IDC_CHECK3)?1:0); + + break; + case IDC_OFFS: + if (HIWORD(wParam) == EN_CHANGE) + { + BOOL t; + config_vidoffs=GetDlgItemInt(hwndDlg,IDC_OFFS,&t,TRUE); + } + break; + case IDCANCEL: EndDialog(hwndDlg,0); break; + case IDOK: + // save config +// config_http_proxynonport80=!IsDlgButtonChecked(hwndDlg,IDC_CHECK5); + { + BOOL t; + config_bufms=GetDlgItemInt(hwndDlg,IDC_BUF1,&t,FALSE); + if (config_bufms < 100) config_bufms=100; + if (config_bufms > 100000) config_bufms=100000; + + config_prebufms=GetDlgItemInt(hwndDlg,IDC_BUF2,&t,FALSE); + if (config_prebufms < 100) config_prebufms=100; + if (config_prebufms > config_bufms) config_prebufms=config_bufms; + + config_underunbuf=GetDlgItemInt(hwndDlg,IDC_BUF3,&t,FALSE); + if (config_underunbuf < 100) config_underunbuf=100; + if (config_underunbuf > config_bufms) config_underunbuf=config_bufms; + + config_bufms_f=GetDlgItemInt(hwndDlg,IDC_BUF4,&t,FALSE); + if (config_bufms_f < 100) config_bufms_f=100; + if (config_bufms_f > 100000) config_bufms_f=100000; + + config_prebufms_f=GetDlgItemInt(hwndDlg,IDC_BUF5,&t,FALSE); + if (config_prebufms_f < 100) config_prebufms_f=100; + if (config_prebufms_f > config_bufms_f) config_prebufms_f=config_bufms_f; + + config_underunbuf_f=GetDlgItemInt(hwndDlg,IDC_BUF6,&t,FALSE); + if (config_underunbuf_f < 100) config_underunbuf_f=100; + if (config_underunbuf_f > config_bufms_f) config_underunbuf_f=config_bufms_f; + + config_vidoffs=GetDlgItemInt(hwndDlg,IDC_OFFS,&t,TRUE); + + config_padtag=GetDlgItemInt(hwndDlg,IDC_TAGPAD,&t,FALSE); + } + config_write(); + EndDialog(hwndDlg,1); + break; + } + break; + } + return 0; +} + +void config(HWND hwndParent) +{ + WASABI_API_DIALOGBOXW(IDD_DIALOG1,hwndParent,configProc); +} + +void config_read() +{ + config_init(); + RI(config_bufms); + RI(config_prebufms); + RI(config_underunbuf); + RI(config_bufms_f); + RI(config_prebufms_f); + RI(config_underunbuf_f); + RI(config_vidoffs); + RI(config_padtag); +// RI(allow_uvox); +// RI(config_http_proxynonport80); + RI(config_precseek); + RI(config_subtitles); +} + +void config_write() +{ + WI(config_bufms); + WI(config_prebufms); + WI(config_underunbuf); + WI(config_bufms_f); + WI(config_prebufms_f); + WI(config_underunbuf_f); + WI(config_vidoffs); + WI(config_padtag); + WI(config_precseek); + WI(config_subtitles); +// WI(allow_uvox); +// WI(config_http_proxynonport80); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/in_nsv.rc b/Src/Plugins/Input/in_nsv/in_nsv.rc new file mode 100644 index 00000000..55fac0cc --- /dev/null +++ b/Src/Plugins/Input/in_nsv/in_nsv.rc @@ -0,0 +1,294 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 185, 158 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Nullsoft NSV Decoder Configuration" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Buffering",IDC_STATIC,4,4,177,86 + LTEXT "Stream",IDC_STATIC,83,15,23,8 + LTEXT "Local File",IDC_STATIC,132,15,31,8 + RTEXT "Buffer size:",IDC_STATIC,14,28,66,8 + EDITTEXT IDC_BUF1,83,26,27,12,ES_NUMBER + LTEXT "ms",IDC_STATIC,113,28,10,8 + EDITTEXT IDC_BUF4,132,26,27,12,ES_NUMBER + LTEXT "ms",IDC_STATIC,162,28,10,8 + RTEXT "Prebuffer at start:",IDC_STATIC,14,44,66,8 + EDITTEXT IDC_BUF2,83,42,27,12,ES_NUMBER + LTEXT "ms",IDC_STATIC,113,44,10,8 + EDITTEXT IDC_BUF5,132,42,27,12,ES_NUMBER + LTEXT "ms",IDC_STATIC,162,44,10,8 + LTEXT "Rebuffer on underrun:",IDC_STATIC,8,60,77,8 + EDITTEXT IDC_BUF3,83,58,27,12,ES_NUMBER + LTEXT "ms",IDC_STATIC,113,60,10,8 + EDITTEXT IDC_BUF6,132,58,27,12,ES_NUMBER + LTEXT "ms",IDC_STATIC,162,60,10,8 + LTEXT "Precise seeking:",IDC_STATIC,29,75,55,8 + CONTROL "enabled",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,83,74,41,10 + CONTROL "enabled",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,132,74,41,10 + RTEXT "Offset video from audio by:",IDC_STATIC,4,97,91,8 + EDITTEXT IDC_OFFS,101,95,27,12 + LTEXT "ms",IDC_STATIC,133,97,10,8 + LTEXT "Pad NSV tags with: ",IDC_STATIC,34,113,63,8 + EDITTEXT IDC_TAGPAD,101,111,27,12,ES_NUMBER + LTEXT "bytes",IDC_STATIC,133,113,18,8 + LTEXT "Display Subtitles:",IDC_STATIC,40,128,60,8 + CONTROL "enabled",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,127,41,10 + DEFPUSHBUTTON "OK",IDOK,131,141,50,13 +END + +IDD_DIALOG2 DIALOGEX 0, 0, 276, 84 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "NSV Tag Metadata Editor" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Metadata should be in the format of NAME=value. Examples:",IDC_STATIC,7,6,197,8 + LTEXT "TITLE=My Movie (sets the title of the video)",IDC_STATIC,21,17,160,8 + LTEXT "ASPECT=1.0 (sets the aspect ratio of the video)",IDC_STATIC,22,27,186,8 + LTEXT "FRAMERATE=18.79 (overrides the default NSV framerate)",IDC_STATIC,22,37,194,8 + EDITTEXT IDC_EDIT1,7,50,262,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,7,67,50,13 + PUSHBUTTON "Cancel",IDCANCEL,61,67,50,13 +END + +IDD_DIALOG3 DIALOGEX 0, 0, 355, 204 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "NSV File Info / Tag Editor" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + EDITTEXT IDC_FN,5,5,345,12,ES_AUTOHSCROLL | ES_READONLY + GROUPBOX "NSV Bitstream Information",IDC_STATIC,5,22,345,30 + EDITTEXT IDC_BSINFO,11,34,333,12,ES_AUTOHSCROLL | ES_READONLY + GROUPBOX "Length/TOC Information",IDC_STATIC,5,56,151,106 + LTEXT "Stream size:",IDC_STATIC,12,70,50,8 + EDITTEXT IDC_LENBYTES,67,68,78,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP + LTEXT "Stream length:",IDC_STATIC,12,82,50,8 + EDITTEXT IDC_LENMS,67,81,78,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP + LTEXT "Avg bitrate:",IDC_STATIC,12,96,50,8 + EDITTEXT IDC_AVGBITRATE,67,94,78,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP + CONTROL "Table of contents (for seeking)",IDC_TOC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,111,112,10 + RTEXT "TOC size:",IDC_STATIC,20,127,40,8 + EDITTEXT IDC_TOCSIZE,67,123,78,12,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER | NOT WS_TABSTOP + LTEXT "Max TOC size:",IDC_STATIC,15,142,48,8 + EDITTEXT IDC_SETTOCSIZE,67,139,30,12,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "Analyze",IDC_ANALYZE,105,139,40,12 + CONTROL "Fast tag update (don't shrink tag)",IDC_FASTUPD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,166,119,10 + LTEXT "ttl",IDC_TAG_LEN,5,175,127,8 + GROUPBOX "Metadata",IDC_STATIC,161,56,189,143 + LISTBOX IDC_METADATA,167,67,177,109,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Add item",IDC_ADD,167,180,41,13 + PUSHBUTTON "Delete item",IDC_REM,211,180,49,13 + PUSHBUTTON "Edit item",IDC_EDIT,263,180,40,13 + LTEXT "tml",IDC_METADATA_LEN,307,183,37,8 + DEFPUSHBUTTON "Update tag",IDOK,5,186,46,13 + PUSHBUTTON "Remove tag",IDC_REMTAG,55,186,45,13 + PUSHBUTTON "Cancel",IDCANCEL,102,186,45,13 +END + +IDD_DIALOG4 DIALOGEX 0, 0, 266, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "NSV Stream Info" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + EDITTEXT IDC_FN,4,5,258,13,ES_AUTOHSCROLL | ES_READONLY + GROUPBOX "Stream Info",IDC_INFOBORDER,4,22,258,89 + EDITTEXT IDC_INFO,9,32,246,75,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + DEFPUSHBUTTON "Close",IDCANCEL,4,115,45,13 +END + +IDD_ABOUT DIALOGEX 0, 0, 184, 54 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Nullsoft NSV Decoder" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL 102,IDC_STATIC,"Static",SS_BITMAP,7,7,67,39 + CTEXT "",IDC_VERSION,74,7,103,8 + CTEXT "© 2003-2023 Winamp SA",IDC_STATIC,74,16,103,8 + DEFPUSHBUTTON "OK",IDOK,105,34,50,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 181 + TOPMARGIN, 4 + BOTTOMMARGIN, 154 + END + + IDD_DIALOG2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 269 + TOPMARGIN, 6 + BOTTOMMARGIN, 80 + END + + IDD_DIALOG3, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 350 + TOPMARGIN, 5 + BOTTOMMARGIN, 199 + END + + IDD_DIALOG4, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 262 + TOPMARGIN, 5 + BOTTOMMARGIN, 128 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 177 + TOPMARGIN, 7 + BOTTOMMARGIN, 47 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP "nsv_logo.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_NULLSOFT_NSV_DECODER "Nullsoft NSV Decoder v%s" + 65535 "{11B847DB-29A7-47ac-B386-43B40385B817}" +END + +STRINGTABLE +BEGIN + IDS_TOTAL_TAG_SIZE "Total tag size: 0 bytes" + IDS_NO_METADATA "No metadata" + IDS_TOTAL_TAG_SIZE_X_BYTES "Total tag size: %d bytes" + IDS_NO_TAG "No tag" + IDS_ERROR_WRITING_STRING_TO_TAG + "Error writing string to tag (string too complex!) - string may be corrupted with a !\n" + IDS_NSV_TAG_EDITOR_ERROR "NSV Tag Editor Error" + IDS_LARGE_DATA "[LARGE DATA] - " + IDS_NO_VALID_NSV_BITSTREAM_FOUND "No valid NSV bitstream found\n" + IDS_VIDEO_X_AUDIO_X "Video: %s %dx%d@%d.%02dfps, Audio: %s" + IDS_METADATA_STRING_MUST_CONTAIN_ONE_EQUAL_SIGN + "Metadata string must contain at least one equal sign (=)." + IDS_NSV_TAG_EDITOR "NSV Tag Editor" + IDS_CANNOT_CREATE_TEMPFILE_CANNOT_UPDATE_TAG + "Cannot create tempfile - cannot update tag!" + IDS_ERROR_COPYING_SOURCE "Error copying source - cannot update tag!" + IDS_COPYING_X_BYTES "Copying %d bytes..." + IDS_ERROR_SIZE_MISMATCH "Error size mismatch - cannot update tag!" +END + +STRINGTABLE +BEGIN + IDS_ERROR_RENAMING_SOURCE "Error renaming source - cannot update tag!" + IDS_ERROR_RENAMING_NEW_FILE "Error renaming new file - cannot update tag!" + IDS_READING_X_FRAMES "Reading %d frames..." + IDS_NSV_ANALYSIS_FAILED "NSV analysis failed" + IDS_METADATA_ITEM_CONTAINS_LARGE_AMOUNT_DATA + "This metadata item appear to contain a large amount of data.\nA binary metadata editor is coming soon, until then, you can\ndelete it if you wish to create something new." + IDS_CONNECTING "Connecting" + IDS_OPENING "Opening" + IDS_BUFFER_X "Buffer: %d%%" + IDS_SERVER "Server" + IDS_CONTENT_TYPE "Content Type" + IDS_CONTENT_LENGTH "Content Length" + IDS_STREAM_NAME "Stream name" + IDS_NSA_NSV_FILE "Nullsoft Audio/Video File (*.NSV;*.NSA)" + IDS_KBPS "kbps" + IDS_FPS "fps" +END + +STRINGTABLE +BEGIN + IDS_FAMILY_STRING_NSV "Nullsoft Streaming Video File" + IDS_FAMILY_STRING_NSA "Nullsoft Streaming Audio File" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Plugins/Input/in_nsv/in_nsv.sln b/Src/Plugins/Input/in_nsv/in_nsv.sln new file mode 100644 index 00000000..f06edb48 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/in_nsv.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29609.76 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_nsv", "in_nsv.vcxproj", "{9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Debug|Win32.Build.0 = Debug|Win32 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Debug|x64.ActiveCfg = Debug|x64 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Debug|x64.Build.0 = Debug|x64 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Release|Win32.ActiveCfg = Release|Win32 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Release|Win32.Build.0 = Release|Win32 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Release|x64.ActiveCfg = Release|x64 + {9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {382549BF-5E52-402C-8150-3E8BFCEF1439} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Input/in_nsv/in_nsv.vcxproj b/Src/Plugins/Input/in_nsv/in_nsv.vcxproj new file mode 100644 index 00000000..1f3c68a4 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/in_nsv.vcxproj @@ -0,0 +1,274 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{9E4B1D43-137A-4AE1-A05A-92EEE0028BF0}</ProjectGuid> + <RootNamespace>in_nsv</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnabled>false</VcpkgEnabled> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_USRDLL;IN_NSV_EXPORTS;WINAMP_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_ABOUT_EGG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;WIN64;_WINDOWS;_USRDLL;IN_NSV_EXPORTS;WINAMP_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_ABOUT_EGG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_USRDLL;IN_NSV_EXPORTS;WINAMP_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_ABOUT_EGG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>NDEBUG;WIN64;_WINDOWS;_USRDLL;IN_NSV_EXPORTS;WINAMP_PLUGIN;_CRT_SECURE_NO_WARNINGS;NO_ABOUT_EGG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <SubSystem>Windows</SubSystem> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\..\..\nsv\nsvbs.h" /> + <ClInclude Include="..\..\..\nsv\nsvlib.h" /> + <ClInclude Include="api.h" /> + <ClInclude Include="resource.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\..\nsv\nsvlib.cpp" /> + <ClCompile Include="..\..\..\nsv\nsvplay\decoders.cpp" /> + <ClCompile Include="..\..\..\nsv\nsvplay\nsvdecode.cpp" /> + <ClCompile Include="..\..\..\nsv\nsvplay\readers.cpp" /> + <ClCompile Include="..\..\..\nsv\nsvplay\subtitles.cpp" /> + <ClCompile Include="config.cpp" /> + <ClCompile Include="infodlg.cpp" /> + <ClCompile Include="Main.cpp" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="in_nsv.rc" /> + </ItemGroup> + <ItemGroup> + <Image Include="nsv_logo.bmp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/in_nsv.vcxproj.filters b/Src/Plugins/Input/in_nsv/in_nsv.vcxproj.filters new file mode 100644 index 00000000..12bf6b29 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/in_nsv.vcxproj.filters @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="Main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="infodlg.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="config.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nsv\nsvplay\decoders.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nsv\nsvplay\nsvdecode.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nsv\nsvlib.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nsv\nsvplay\readers.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nsv\nsvplay\subtitles.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nsv\nsvbs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nsv\nsvlib.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{a867382b-03bf-4021-989d-458eb1ef9db6}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{6ccfd425-b17c-4d1c-985a-d58134034d50}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{17af3ae5-8365-4ae7-aab5-737661ec6b5a}</UniqueIdentifier> + </Filter> + <Filter Include="Image Files"> + <UniqueIdentifier>{78b43273-fca3-401e-9ca5-bbf4cfe27a2c}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <Image Include="nsv_logo.bmp"> + <Filter>Image Files</Filter> + </Image> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="in_nsv.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/infodlg.cpp b/Src/Plugins/Input/in_nsv/infodlg.cpp new file mode 100644 index 00000000..99a99342 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/infodlg.cpp @@ -0,0 +1,1089 @@ +#include <windows.h> +#include "api.h" +#include "resource.h" + +#include "../Winamp/in2.h" + +extern In_Module mod; // the output module (filled in near the bottom of this file) + +extern "C" { extern wchar_t lastextfn[1024]; }; + +#define MAX_EDITABLE_METASTRING 8192 + +#include "../nsv/nsvlib.h" + static int isplaying; + static int timems; +extern char lastfn[1024]; +extern int g_play_needseek; + + static void restartPlayback() + { + if (isplaying) + { + SendMessage(mod.hMainWindow,WM_USER,0,3007); // disable stats updating + SendMessage(mod.hMainWindow,WM_COMMAND,40045,0); + if (timems) + { + g_play_needseek=timems; +// SendMessage(mod.hMainWindow,WM_USER,timems,106); + } + if (isplaying & 2) + { + SendMessage(mod.hMainWindow,WM_COMMAND,40046,0); + } + SendMessage(mod.hMainWindow,WM_USER,1,3007); // enable stats updating + } + } + + static void stopPlayback(const char *fn) + { + isplaying=0; + timems=0; + if (!_stricmp(lastfn,fn)) + { + isplaying= (int)SendMessage(mod.hMainWindow,WM_USER,0,104); + if (isplaying) + { + timems= (int)SendMessage(mod.hMainWindow,WM_USER,0,105); + SendMessage(mod.hMainWindow,WM_COMMAND,40047,0); + } + } + } + + +extern int config_padtag; +int fillBs(HANDLE hFile, nsv_InBS &bs, int lenbytes); + static nsv_fileHeader m_set_lhdr; + static char m_set_lfile[1024]; + + static void closeset() + { + free(m_set_lhdr.toc); + free(m_set_lhdr.metadata); + memset(&m_set_lhdr,0,sizeof(m_set_lhdr)); + m_set_lfile[0]=0; + } + +extern int config_bufms, config_prebufms, config_underunbuf; + +extern "C" +{ + + __declspec( dllexport ) int winampSetExtendedFileInfo(const char *fn, const char *data, char *val) + { + if(!fn || !fn[0]) return 0; + + //muahaha, <3 hacks + if(!_stricmp(data,"setHttpConfigValues")) + { + config_bufms=atoi(val); + char *p=strstr(val,","); + if(!p) return 0; + config_prebufms=atoi(p+1); + p=strstr(p+1,","); + if(!p) return 0; + config_underunbuf=atoi(p+1); + return 1; + } + + if(strcmpi(fn,m_set_lfile)) + { + closeset(); + + lstrcpynA(m_set_lfile,fn,sizeof(m_set_lfile)); + + HANDLE hFile = CreateFileA(fn,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + nsv_InBS bs; + for (;;) + { + int ret=nsv_readheader(bs,&m_set_lhdr); + if (ret <= 0 || fillBs(hFile,bs,ret)) break; + } + CloseHandle(hFile); + } + } + + char *p=(char*)m_set_lhdr.metadata; + unsigned int pos=0; + + int omdl=m_set_lhdr.metadata_len; + if (p) while (pos < m_set_lhdr.metadata_len) + { + // scan for = + while (pos < m_set_lhdr.metadata_len && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) { pos++; p++; } + if (pos >= m_set_lhdr.metadata_len) break; + + char *lp=p; + while (pos < m_set_lhdr.metadata_len && *p != '=') { pos++; p++; } + if (pos >= m_set_lhdr.metadata_len) break; + + // skip = + p++; if (++pos >= m_set_lhdr.metadata_len) break; + + // get delim char + char divc=*p++; if (++pos >= m_set_lhdr.metadata_len) break; + + // scan for new delim char + while (pos < m_set_lhdr.metadata_len && *p != divc) { pos++; p++; } + + p++; // advance over our delim char + if (++pos > m_set_lhdr.metadata_len) break; + + + if (!strncmp(lp,data,strlen(data)) && lp[strlen(data)]=='=') + { + if (pos >= m_set_lhdr.metadata_len) + { + m_set_lhdr.metadata_len = (unsigned int)(lp - (char*)m_set_lhdr.metadata); + } + else + { + memcpy(lp,p,m_set_lhdr.metadata_len - (p-(char*)m_set_lhdr.metadata)); + m_set_lhdr.metadata_len -= (unsigned int)(p-lp); + } + break; + } + } + + if (val && *val) + { + unsigned char divc; //fucko + int x; + for (x = 1; x < 256 && strchr(val,x); x ++); + if (x == 256) return 1; + divc=(unsigned char)x; + + int nmdl= (int)(m_set_lhdr.metadata_len + 5 + strlen(data) + strlen(val)); + + if (!m_set_lhdr.metadata || omdl<nmdl) + m_set_lhdr.metadata=realloc(m_set_lhdr.metadata,nmdl); + memcpy((char*)m_set_lhdr.metadata + m_set_lhdr.metadata_len,data,strlen(data)); + m_set_lhdr.metadata_len+= (int)strlen(data); + memcpy((char*)m_set_lhdr.metadata + m_set_lhdr.metadata_len,"=",1); + m_set_lhdr.metadata_len++; + memcpy((char*)m_set_lhdr.metadata + m_set_lhdr.metadata_len,&divc,1); + m_set_lhdr.metadata_len++; + + memcpy((char*)m_set_lhdr.metadata + m_set_lhdr.metadata_len,val,strlen(val)); + m_set_lhdr.metadata_len+= (int)strlen(val); + + memcpy((char*)m_set_lhdr.metadata + m_set_lhdr.metadata_len,&divc,1); + m_set_lhdr.metadata_len++; + + memcpy((char*)m_set_lhdr.metadata + m_set_lhdr.metadata_len," ",1); //space to be ghey + m_set_lhdr.metadata_len++; + } + + return 1; + } + + + __declspec( dllexport ) int winampWriteExtendedFileInfo() + { + lastextfn[0]=0; // flush cache + + if (m_set_lfile[0]) + { + + + + HANDLE hFile = CreateFileA(m_set_lfile,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + if (hFile == INVALID_HANDLE_VALUE) + { +// MessageBox(mod.hMainWindow,"Error opening NSV file for update","NSV Tag Error",MB_OK); + return 0; + } + + nsv_OutBS bs; + int osize=m_set_lhdr.header_size; + nsv_writeheader(bs,&m_set_lhdr,osize); + + int hdrlen; + char *hdr=(char*)bs.get(&hdrlen); + + if (hdr && hdrlen == (int)osize) // fast update of header + { + DWORD dw = 0; + SetFilePointer(hFile,0,NULL,SEEK_SET); + WriteFile(hFile,hdr,hdrlen,&dw,NULL); + CloseHandle(hFile); + } + else + { + if (hdr && config_padtag>0) // enlarge header by config_padtag bytes =) + { + bs.clear(); + nsv_writeheader(bs,&m_set_lhdr,config_padtag+m_set_lhdr.header_size); + hdr=(char*)bs.get(&hdrlen); // update + } + + char tmpfn[1024+8]; + char tmpfn2[1024+8]; + wsprintfA(tmpfn,"%s.new",m_set_lfile); + wsprintfA(tmpfn2,"%s.old",m_set_lfile); + + HANDLE hTempFile=CreateFileA(tmpfn,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); + if (hTempFile == INVALID_HANDLE_VALUE) + { + // MessageBox(mod.hMainWindow,"Can't create tempfile - can't update tag!","NSV Tag Editor Error",MB_ICONSTOP|MB_OK); + CloseHandle(hFile); + return 0; + } + SetFilePointer(hFile,osize,NULL,SEEK_SET); + if (hdrlen) + { + DWORD dw = 0; + if (!WriteFile(hTempFile,hdr,hdrlen,&dw,NULL) || (int)dw != hdrlen) + { + CloseHandle(hTempFile); + CloseHandle(hFile); + DeleteFileA(tmpfn); + // MessageBox(mod.hMainWindow,"Error copying source - can't update tag!","NSV Tag Editor Error",MB_ICONSTOP|MB_OK); + return 0; + } + } + + for (;;) + { + char buf[8192] = {0}; + DWORD dw = 0; + BOOL r1=ReadFile(hFile,buf,sizeof(buf),&dw,NULL); + if (r1 && !dw) break; + DWORD dwout = 0; + if (!r1 || !WriteFile(hTempFile,buf,dw,&dwout,NULL) || dwout < dw) + { + CloseHandle(hTempFile); + DeleteFileA(tmpfn); + // MessageBox(mod.hMainWindow,"Error copying source - can't update tag!","NSV Tag Editor Error",MB_ICONSTOP|MB_OK); + return 0; + } + } + if (GetFileSize(hFile,NULL)-osize != GetFileSize(hTempFile,NULL)-hdrlen) + { + CloseHandle(hTempFile); + CloseHandle(hFile); + DeleteFileA(tmpfn); + // MessageBox(mod.hMainWindow,"Error size mismatch - can't update tag!","NSV Tag Editor Error",MB_ICONSTOP|MB_OK); + return 0; + } + CloseHandle(hFile); + CloseHandle(hTempFile); + + stopPlayback(m_set_lfile); + + if (!MoveFileA(m_set_lfile,tmpfn2)) + { + DeleteFileA(tmpfn); + restartPlayback(); + // MessageBox(mod.hMainWindow,"Error renaming source - can't update tag!","NSV Tag Editor Error",MB_ICONSTOP|MB_OK); + return 0; + } + if (!MoveFileA(tmpfn,m_set_lfile)) + { + MoveFileA(tmpfn2,m_set_lfile); + DeleteFileA(tmpfn); + restartPlayback(); + // MessageBox(mod.hMainWindow,"Error renaming new file - can't update tag!","NSV Tag Editor Error",MB_ICONSTOP|MB_OK); + return 0; + } + DeleteFileA(tmpfn2); + restartPlayback(); + } + } + closeset(); + lastextfn[0]=0; + return 1; + } +} + + + +const char *g_lastfile; +HANDLE g_hFile=INVALID_HANDLE_VALUE; +nsv_fileHeader g_filehdr={0,~0,~0,}; +unsigned int g_oldtag_size; +unsigned int *g_toc_save, *g_toc_save_ex, g_toc_savesize; + +void enableControls(HWND hwndDlg, int en) +{ + EnableWindow(GetDlgItem(hwndDlg,IDC_SETTOCSIZE),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_TOC),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_ANALYZE),en); + EnableWindow(GetDlgItem(hwndDlg,IDOK),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_REMTAG),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_ADD),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_REM),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_EDIT),en); + EnableWindow(GetDlgItem(hwndDlg,IDC_FASTUPD),en); +} + +void closeNsv(HWND hwndDlg) +{ + if (g_hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(g_hFile); + g_hFile=INVALID_HANDLE_VALUE; + } + free(g_filehdr.metadata); + g_filehdr.metadata=0; + g_filehdr.metadata_len=0; + free(g_filehdr.toc); + g_filehdr.toc=0; + g_filehdr.toc_ex=0; + free(g_toc_save); + g_toc_save=0; + g_toc_save_ex=0; + + g_toc_savesize=0; + g_filehdr.toc_size=0; + g_filehdr.toc_alloc=0; + g_filehdr.file_lenbytes=~0; + g_filehdr.file_lenms=~0; + g_filehdr.header_size=0; + SetDlgItemTextA(hwndDlg,IDC_LENBYTES,""); + SetDlgItemTextA(hwndDlg,IDC_LENMS,""); + SetDlgItemTextA(hwndDlg,IDC_AVGBITRATE,""); + CheckDlgButton(hwndDlg,IDC_TOC,0); + SetDlgItemTextA(hwndDlg,IDC_TOCSIZE,""); + SetDlgItemTextA(hwndDlg,IDC_SETTOCSIZE,""); + SetDlgItemTextA(hwndDlg,IDC_FN,""); + int x; + int cnt= (int)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETCOUNT,0,0); + for ( x= 0; x < cnt; x ++) + { + void *v=(void *)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETITEMDATA,x,0); + if (v) free(v); + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_SETITEMDATA,x,0); + } + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_RESETCONTENT,0,0); + SetDlgItemTextA(hwndDlg,IDC_TAG_LEN,WASABI_API_LNGSTRING(IDS_TOTAL_TAG_SIZE)); + SetDlgItemTextA(hwndDlg,IDC_METADATA_LEN,WASABI_API_LNGSTRING(IDS_NO_METADATA)); + + enableControls(hwndDlg,0); +} + +int fillBs(HANDLE hFile, nsv_InBS &bs, int lenbytes) +{ + while (lenbytes > 0) + { + DWORD r=0; + char buf[8192] = {0}; + BOOL ret=ReadFile(hFile,buf,sizeof(buf),&r,NULL); + lenbytes-=r; + bs.add(buf,r); + if (!ret || !r) return 1; + } + return lenbytes > 0; +} + +void makeNewHeaderInfo(HWND hwndDlg) +{ + nsv_OutBS bs; + g_filehdr.toc_alloc=0; + nsv_writeheader(bs,&g_filehdr,0); + EnableWindow(GetDlgItem(hwndDlg,IDC_FASTUPD),g_filehdr.header_size <= g_oldtag_size); + char buf[128] = {0}; + if (g_filehdr.header_size) wsprintfA(buf,WASABI_API_LNGSTRING(IDS_TOTAL_TAG_SIZE_X_BYTES),g_filehdr.header_size); + else WASABI_API_LNGSTRING_BUF(IDS_NO_TAG,buf,128); + SetDlgItemTextA(hwndDlg,IDC_TAG_LEN,buf); +} + +void populateInfo(HWND hwndDlg) +{ + if (g_filehdr.file_lenbytes != ~0) + { + wchar_t buf[128] = {0}; + unsigned int low=g_filehdr.file_lenbytes; + SetDlgItemTextW(hwndDlg,IDC_LENBYTES,WASABI_API_LNG->FormattedSizeString(buf, 128, low)); + } + else SetDlgItemTextA(hwndDlg,IDC_LENBYTES,"?"); + + if (g_filehdr.file_lenms != ~0) + { + char buf[128] = {0}; + unsigned int timems=g_filehdr.file_lenms; + if (timems < 1000) wsprintfA(buf,"%ums",timems); + else if (timems < 1000*60) wsprintfA(buf,"%02u.%03us",timems/1000,timems%1000); + else if (timems < 1000*60*60) wsprintfA(buf,"%02u:%02u.%03us",timems/60000,(timems/1000)%60,timems%1000); + else wsprintfA(buf,"%u:%02u:%02u.%03us",timems/3600000,(timems/60000)%60,(timems/1000)%60,timems%1000); + + SetDlgItemTextA(hwndDlg,IDC_LENMS,buf); + } + else SetDlgItemTextA(hwndDlg,IDC_LENMS,"?"); + CheckDlgButton(hwndDlg,IDC_TOC,g_filehdr.toc_size?BST_CHECKED:BST_UNCHECKED); + if (g_filehdr.toc_size) + { + char buf[128] = {0}; + wsprintfA(buf,"%d%s",g_filehdr.toc_size,g_filehdr.toc_ex ? " (TOC 2.0)":""); + SetDlgItemTextA(hwndDlg,IDC_TOCSIZE,buf); + SetDlgItemInt(hwndDlg,IDC_SETTOCSIZE,g_filehdr.toc_size,FALSE); + } + else + { + SetDlgItemTextA(hwndDlg,IDC_TOCSIZE,""); + SetDlgItemTextA(hwndDlg,IDC_SETTOCSIZE,"4096"); + } + + if (g_filehdr.file_lenms != ~0 && g_filehdr.file_lenbytes != ~0) + { + unsigned int bitrate = g_filehdr.file_lenms ? MulDiv(g_filehdr.file_lenbytes,8000,g_filehdr.file_lenms) : 0; + char buf[1024] = {0}; + wsprintfA(buf,"%u %s",bitrate/1000,WASABI_API_LNGSTRING(IDS_KBPS)); + SetDlgItemTextA(hwndDlg,IDC_AVGBITRATE,buf); + } + else SetDlgItemTextA(hwndDlg,IDC_AVGBITRATE,"?"); + + char buf[128] = {0}; + if (g_filehdr.header_size) wsprintfA(buf,WASABI_API_LNGSTRING(IDS_TOTAL_TAG_SIZE_X_BYTES),g_filehdr.header_size); + else WASABI_API_LNGSTRING_BUF(IDS_NO_TAG,buf,128); + SetDlgItemTextA(hwndDlg,IDC_TAG_LEN,buf); +} + +void updateMetaData(HWND hwndDlg) +{ + free(g_filehdr.metadata); + g_filehdr.metadata=0; + g_filehdr.metadata_len=0; + int n= (int)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETCOUNT,0,0); + int x; + int total_size=0; + + for (x = 0; x < n; x ++) + { + int l; + char *bigstr = (char *)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETITEMDATA,x,0); + if (bigstr) l = (int)strlen((char *)bigstr)+2; + else l= (int)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETTEXTLEN,x,0); + total_size+=l+2; // text+ two chars + if (x) total_size++; // space + } + + g_filehdr.metadata=malloc(total_size+1); + char *metaout=(char*)g_filehdr.metadata; + for (x = 0; x < n; x ++) + { + if (x) *metaout++=' '; + + const char *bigstr = (const char *)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETITEMDATA,x,0); + + char *this_text; + if (bigstr) this_text=_strdup((const char *)bigstr); + else + { + int l= (int)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETTEXTLEN,x,0); + this_text=(char*)malloc(l+1); + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETTEXT,x,(LPARAM)this_text); + } + char *p=this_text; + while (p && *p != '=' && *p) *metaout++=*p++; + if (p && *p) + { + *metaout++=*p++; + int x; + for (x = 1; x < 256 && strchr(p,x); x ++); + + if (x == 256) + { + char title[64] = {0}; + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERROR_WRITING_STRING_TO_TAG), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_OK|MB_ICONSTOP); + x=1; + } + + *metaout++=x; + while (p && *p) + { + int a=*p++; + if (a == x) a = '!'; + *metaout++=a; + } + *metaout++=x; + } + free(this_text); + } + g_filehdr.metadata_len= unsigned int(metaout - (char*)g_filehdr.metadata); + *metaout=0; +} + +void populateMetaData(HWND hwndDlg) +{ + wchar_t buf[128] = {0}; + if (g_filehdr.metadata_len) WASABI_API_LNG->FormattedSizeString(buf,128,g_filehdr.metadata_len); + else WASABI_API_LNGSTRINGW_BUF(IDS_NO_METADATA, buf, 128); + SetDlgItemTextW(hwndDlg,IDC_METADATA_LEN,buf); + + int x; + int cnt= (int)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETCOUNT,0,0); + for ( x= 0; x < cnt; x ++) + { + void *v=(void *)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETITEMDATA,x,0); + if (v) free(v); + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_SETITEMDATA,x,0); + } + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_RESETCONTENT,0,0); + + if (g_filehdr.metadata) + { + char *p=(char*)g_filehdr.metadata; + for (;;) + { + while (p && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++; + if (!p || !*p) break; + + char *this_name=p; + + // advance to next item + while (p && *p && *p != '=') p++; + char *end_name=p; + + if (!*p++) break; + if (!*p) break; + + char c=*p++; + char *begin_value=p; + while (p && *p && *p != c) p++; + char *end_value=p; + if (*p) p++; + + char *name=(char *)malloc(end_name-this_name + 1 + end_value-begin_value + 1); + char *tmp=name; + memcpy(tmp,this_name,end_name-this_name); tmp+=end_name-this_name; + *tmp++='='; + memcpy(tmp,begin_value,end_value-begin_value); tmp+=end_value-begin_value; + *tmp=0; + + if (strlen(name) < MAX_EDITABLE_METASTRING) + { + LRESULT a=SendDlgItemMessageA(hwndDlg,IDC_METADATA,LB_ADDSTRING,0,(LPARAM)name); + SendDlgItemMessageA(hwndDlg,IDC_METADATA,LB_SETITEMDATA,(WPARAM)a,(LPARAM)0); + free(name); + } + else + { + char buf[512] = {0}; + WASABI_API_LNGSTRING_BUF(IDS_LARGE_DATA,buf,512); + lstrcpynA(buf+strlen(buf),name,128); + strcpy(buf+strlen(buf),"..."); + LRESULT a=SendDlgItemMessageA(hwndDlg,IDC_METADATA,LB_ADDSTRING,0,(LPARAM)buf); + SendDlgItemMessageA(hwndDlg,IDC_METADATA,LB_SETITEMDATA,(WPARAM)a,(LPARAM)name); + } + } + } +} + +void openNsv(HWND hwndDlg) +{ + closeNsv(hwndDlg); + g_hFile = CreateFileA(g_lastfile,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + SetDlgItemTextA(hwndDlg,IDC_FN,g_lastfile); + + if (g_hFile == INVALID_HANDLE_VALUE) return; + enableControls(hwndDlg,1); + CheckDlgButton(hwndDlg,IDC_FASTUPD,BST_CHECKED); + // try to read existing tag. + nsv_InBS bs; + for (;;) + { + int ret=nsv_readheader(bs,&g_filehdr); + if (ret <= 0 || fillBs(g_hFile,bs,ret)) break; + } + nsv_Unpacketer unpacket; + char infobuf[256] = {0}; + WASABI_API_LNGSTRING_BUF(IDS_NO_VALID_NSV_BITSTREAM_FOUND,infobuf,256); + for (;;) + { + int ret=unpacket.unpacket(bs); + if (ret < 0) break; + if (ret > 0 && fillBs(g_hFile,bs,ret)) break; + if (!ret) + { + char vfmt[32] = {0}; + char afmt[5] = {0}; + + int fr=(int)(unpacket.getFrameRate()*100.0); + + if (unpacket.getVidFmt()!=NSV_MAKETYPE('V','L','B',' ')) nsv_type_to_string(unpacket.getVidFmt(),vfmt); + else strcpy(vfmt,"Dolby AAC"); + + nsv_type_to_string(unpacket.getAudFmt(),afmt); + + wsprintfA(infobuf,WASABI_API_LNGSTRING(IDS_VIDEO_X_AUDIO_X), + vfmt,unpacket.getWidth(), + unpacket.getHeight(), + fr/100,fr%100,afmt); + break; + } + } + SetDlgItemTextA(hwndDlg,IDC_BSINFO,infobuf); + + g_oldtag_size=g_filehdr.header_size; + populateInfo(hwndDlg); + populateMetaData(hwndDlg); +} + +static int g_metaitem_edit; + +INT_PTR CALLBACK EditProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + if (uMsg == WM_INITDIALOG) + { + if (g_metaitem_edit>=0) + { + HWND ctl=GetDlgItem(GetParent(hwndDlg),IDC_METADATA); + int x= (int)SendMessage(ctl,LB_GETTEXTLEN,g_metaitem_edit,0); + if (x != LB_ERR) + { + char *t=(char*)malloc(x+1); + if (SendMessage(ctl,LB_GETTEXT,g_metaitem_edit,(LPARAM)t) != LB_ERR) + { + SetDlgItemTextA(hwndDlg,IDC_EDIT1,t); + } + free(t); + } + } + } + if (uMsg == WM_CLOSE) EndDialog(hwndDlg,0); + if (uMsg == WM_COMMAND) + { + if (LOWORD(wParam) == IDCANCEL) EndDialog(hwndDlg,0); + if (LOWORD(wParam) == IDOK) + { + int x= (int)SendDlgItemMessage(hwndDlg,IDC_EDIT1,WM_GETTEXTLENGTH,0,0); + char *t=(char*)malloc(x+3); + GetDlgItemTextA(hwndDlg,IDC_EDIT1,t,x+2); + if (!strstr(t,"=")) + { + char title[32] = {0}; + free(t); + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_METADATA_STRING_MUST_CONTAIN_ONE_EQUAL_SIGN), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR,title,32),MB_OK|MB_ICONINFORMATION); + } + else + { + HWND ctl=GetDlgItem(GetParent(hwndDlg),IDC_METADATA); + LRESULT added; + if (g_metaitem_edit>=0) + { + SendMessage(ctl,LB_DELETESTRING,g_metaitem_edit,0); + added=SendMessage(ctl,LB_INSERTSTRING,g_metaitem_edit,(LPARAM)t); + } + else added=SendMessage(ctl,LB_ADDSTRING,0,(LPARAM)t); + SendMessage(ctl,LB_SETITEMDATA,(WPARAM)added,0); + free(t); + EndDialog(hwndDlg,1); + } + } + } + return 0; + +} + +int doTagWrite(HWND hwndDlg, int writeheader) +{ + nsv_OutBS bs; + if (writeheader) + { + g_filehdr.toc_alloc=0; + nsv_writeheader(bs,&g_filehdr,IsDlgButtonChecked(hwndDlg,IDC_FASTUPD)?g_oldtag_size:0); + } + + int hdrlen; + char *hdr=(char*)bs.get(&hdrlen); + + if (hdr && writeheader && hdrlen == (int)g_oldtag_size) // fast update of header + { + DWORD dw = 0; + SetFilePointer(g_hFile,0,NULL,SEEK_SET); + WriteFile(g_hFile,hdr,hdrlen,&dw,NULL); + } + else if (writeheader || g_oldtag_size) + { + if (hdr && writeheader && config_padtag>0) // enlarge header by config_padtag bytes =) + { + bs.clear(); + g_filehdr.toc_alloc=0; + nsv_writeheader(bs,&g_filehdr,config_padtag+g_filehdr.header_size); + hdr=(char*)bs.get(&hdrlen); // update + } + + char tmpfn[1024+8] = {0}; + char tmpfn2[1024+8] = {0}; + wsprintfA(tmpfn,"%s.new",g_lastfile); + wsprintfA(tmpfn2,"%s.old",g_lastfile); + + HANDLE hTempFile=CreateFileA(tmpfn,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); + if (hTempFile == INVALID_HANDLE_VALUE) + { + char title[64] = {0}; + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_CANNOT_CREATE_TEMPFILE_CANNOT_UPDATE_TAG), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_ICONSTOP|MB_OK); + return 1; + } + SetFilePointer(g_hFile,g_oldtag_size,NULL,SEEK_SET); + if (hdrlen) + { + DWORD dw = 0; + if (!WriteFile(hTempFile,hdr,hdrlen,&dw,NULL) || (int)dw != hdrlen) + { + char title[64] = {0}; + CloseHandle(hTempFile); + DeleteFileA(tmpfn); + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERROR_COPYING_SOURCE), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_ICONSTOP|MB_OK); + return 1; + } + } + + unsigned int bytes=0; + for (;;) + { + DWORD dw = 0; + char buf[8192] = {0}; + BOOL r1=ReadFile(g_hFile,buf,sizeof(buf),&dw,NULL); + if (r1 && !dw) break; + DWORD dwout = 0; + if (!r1 || !WriteFile(hTempFile,buf,dw,&dwout,NULL) || dwout < dw) + { + char title[64] = {0}; + CloseHandle(hTempFile); + DeleteFileA(tmpfn); + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERROR_COPYING_SOURCE), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_ICONSTOP|MB_OK); + return 1; + } + bytes+=dwout; + wsprintfA(buf,WASABI_API_LNGSTRING(IDS_COPYING_X_BYTES),bytes); + SetDlgItemTextA(hwndDlg,IDC_TAG_LEN,buf); + } + if (GetFileSize(g_hFile,NULL)-g_oldtag_size != GetFileSize(hTempFile,NULL)-hdrlen) + { + char title[64] = {0}; + CloseHandle(hTempFile); + DeleteFileA(tmpfn); + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERROR_SIZE_MISMATCH), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_ICONSTOP|MB_OK); + return 1; + } + CloseHandle(g_hFile); + CloseHandle(hTempFile); + stopPlayback(g_lastfile); + if (!MoveFileA(g_lastfile,tmpfn2)) + { + char title[64] = {0}; + DeleteFileA(tmpfn); + restartPlayback(); + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERROR_RENAMING_SOURCE), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_ICONSTOP|MB_OK); + return 1; + } + if (!MoveFileA(tmpfn,g_lastfile)) + { + char title[64] = {0}; + MoveFileA(tmpfn2,g_lastfile); + DeleteFileA(tmpfn); + restartPlayback(); + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERROR_RENAMING_NEW_FILE), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), + MB_ICONSTOP|MB_OK); + return 1; + } + g_hFile = CreateFileA(g_lastfile,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + + DeleteFileA(tmpfn2); + restartPlayback(); + } + return 0; +} + +void analyzeFile(HWND hwndDlg) +{ + unsigned int nframes=0; + nsv_Unpacketer unpack; + nsv_InBS bs; + GrowBuf framePos; + unsigned int lastPos=0; + SetFilePointer(g_hFile,g_oldtag_size,NULL,SEEK_SET); + for (;;) + { + int ret=unpack.unpacket(bs); + if (ret) + { + if (ret<0) break; + if (fillBs(g_hFile,bs,ret>0?ret:8)) unpack.setEof(); + } + else + { + if (unpack.isSynchFrame()) + { + framePos.add(&lastPos,4); + framePos.add(&nframes,4); + } + lastPos=SetFilePointer(g_hFile,0,NULL,SEEK_CUR) - (unsigned int)(bs.avail()+7)/8 - g_oldtag_size; + bs.compact(); + nframes++; + char buf[128] = {0}; + wsprintfA(buf,WASABI_API_LNGSTRING(IDS_READING_X_FRAMES),nframes); + SetDlgItemTextA(hwndDlg,IDC_TAG_LEN,buf); + } + } + if (unpack.isValid() && nframes) + { + g_filehdr.file_lenbytes=lastPos; + g_filehdr.file_lenms = (int) (nframes * 1000.0 / unpack.getFrameRate()); + if (IsDlgButtonChecked(hwndDlg,IDC_TOC)) + { + BOOL t; + DWORD d=GetDlgItemInt(hwndDlg,IDC_SETTOCSIZE,&t,FALSE); + if (d && t) + { + g_filehdr.toc_size=d; + g_filehdr.toc_alloc=0; + free(g_filehdr.toc); + + unsigned int x; + unsigned int *in=(unsigned int *)framePos.get(); + unsigned int tf=(unsigned int)framePos.getlen()/8; + g_filehdr.toc=(unsigned int *)malloc(g_filehdr.toc_size * sizeof(unsigned int) * 2); + g_filehdr.toc_ex=g_filehdr.toc + g_filehdr.toc_size; + + if (tf < g_filehdr.toc_size) // we can store all keyframes without dropping any + { + g_filehdr.toc_size=tf; + for (x = 0; x < tf; x ++) + { + g_filehdr.toc[x]=in[x*2]; + g_filehdr.toc_ex[x]=in[x*2+1]; + } + } + else // drop keyframes to fit + { + double pos=0.0; + double dpos = (double) tf / (double) g_filehdr.toc_size; + for (x = 0; x < g_filehdr.toc_size; x ++) + { + unsigned int ipos=(unsigned int)pos; + if (ipos >= tf) + { + g_filehdr.toc_size=x; + break; + } + g_filehdr.toc[x]=in[ipos*2]; + g_filehdr.toc_ex[x]=in[ipos*2+1]; + pos+=dpos; + } + } + } + } + } + else + { + char title[64] = {0}; + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_NSV_ANALYSIS_FAILED), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR_ERROR,title,64), MB_OK); + } +} + +INT_PTR CALLBACK StreamProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + extern int g_streaminfobuf_used; + switch (uMsg) + { + case WM_INITDIALOG: + SetDlgItemTextA(hwndDlg,IDC_FN,g_lastfile); + g_streaminfobuf_used=1; + SetTimer(hwndDlg,1,1000,NULL); + SendMessage(hwndDlg,WM_TIMER,1,0); + return TRUE; + + case WM_CLOSE: + g_streaminfobuf_used=0; + KillTimer(hwndDlg,1); + EndDialog(hwndDlg,1); + return 0; + + case WM_TIMER: + if (wParam == 1) + { + extern char lastfn[]; + extern char g_streaminfobuf[]; + extern CRITICAL_SECTION g_decoder_cs; + if (!lstrcmpiA(g_lastfile,lastfn) && g_streaminfobuf[0]) + { + int start = -1, end = 0; + EnterCriticalSection(&g_decoder_cs); + SendDlgItemMessage(hwndDlg, IDC_INFO, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + SetDlgItemTextA(hwndDlg,IDC_INFO,g_streaminfobuf); + SendDlgItemMessage(hwndDlg, IDC_INFO, EM_SETSEL, start, end); + LeaveCriticalSection(&g_decoder_cs); + EnableWindow(GetDlgItem(hwndDlg,IDC_INFO),1); + EnableWindow(GetDlgItem(hwndDlg,IDC_INFOBORDER),1); + } + else + { + SetDlgItemTextA(hwndDlg,IDC_INFO,""); + EnableWindow(GetDlgItem(hwndDlg,IDC_INFO),0); + EnableWindow(GetDlgItem(hwndDlg,IDC_INFOBORDER),0); + } + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + g_streaminfobuf_used=0; + KillTimer(hwndDlg,1); + EndDialog(hwndDlg,1); + return 0; + } + return 0; + } + return 0; +} + +INT_PTR CALLBACK MainProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + openNsv(hwndDlg); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDCANCEL: + closeNsv(hwndDlg); + EndDialog(hwndDlg,1); + return 0; + + case IDOK: + case IDC_REMTAG: + if (!doTagWrite(hwndDlg,LOWORD(wParam) == IDOK)) + { + closeNsv(hwndDlg); + lastextfn[0]=0; + EndDialog(hwndDlg,0); + } + else lastextfn[0]=0; + return 0; + + case IDC_ANALYZE: + analyzeFile(hwndDlg); + populateInfo(hwndDlg); + makeNewHeaderInfo(hwndDlg); + return 0; + + case IDC_ADD: + g_metaitem_edit=-1; + if (WASABI_API_DIALOGBOXW(IDD_DIALOG2,hwndDlg,EditProc)) + { + updateMetaData(hwndDlg); + populateMetaData(hwndDlg); + makeNewHeaderInfo(hwndDlg); + } + return 0; + + case IDC_METADATA: + if (HIWORD(wParam) != LBN_DBLCLK) return 0; + + case IDC_EDIT: + { + DWORD res=(DWORD)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETCURSEL,0,0); + if (res != LB_ERR) + { + int ptr= (int)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETITEMDATA,res,0); + if (ptr) + { + char title[32] = {0}; + MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_METADATA_ITEM_CONTAINS_LARGE_AMOUNT_DATA), + WASABI_API_LNGSTRING_BUF(IDS_NSV_TAG_EDITOR,title,32), MB_OK); + } + else + { + g_metaitem_edit=res; + if (WASABI_API_DIALOGBOXW(IDD_DIALOG2,hwndDlg,EditProc)) + { + updateMetaData(hwndDlg); + populateMetaData(hwndDlg); + makeNewHeaderInfo(hwndDlg); + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_SETCURSEL,(WPARAM)res,0); + } + } + } + } + return 0; + + case IDC_REM: + { + DWORD res=(DWORD)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETCURSEL,0,0); + if (res != LB_ERR) + { + void *ptr=(void *)SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_GETITEMDATA,res,0); + if (ptr) free(ptr); + SendDlgItemMessage(hwndDlg,IDC_METADATA,LB_DELETESTRING,res,0); + updateMetaData(hwndDlg); + populateMetaData(hwndDlg); + makeNewHeaderInfo(hwndDlg); + } + } + return 0; + + case IDC_TOC: + if (HIWORD(wParam) == BN_CLICKED) + { + int ch=!!IsDlgButtonChecked(hwndDlg,IDC_TOC); + if (ch) + { + if (g_toc_save) + { + g_filehdr.toc=g_toc_save; + g_filehdr.toc_ex=g_toc_save_ex; + g_filehdr.toc_size=g_toc_savesize; + g_toc_save=0; + g_toc_save_ex=0; + g_toc_savesize=0; + makeNewHeaderInfo(hwndDlg); + } + } + else + { + if (!g_toc_save) + { + g_toc_save=g_filehdr.toc; + g_toc_save_ex=g_filehdr.toc_ex; + g_toc_savesize=g_filehdr.toc_size; + g_filehdr.toc=0; + g_filehdr.toc_size=0; + g_filehdr.toc_ex=0; + makeNewHeaderInfo(hwndDlg); + } + } + } + return 0; + } + return 0; + + case WM_CLOSE: + closeNsv(hwndDlg); + EndDialog(hwndDlg,1); + return 0; + } + return 0; +} + +int infoDlg(const char *fn, HWND hwnd) +{ + g_lastfile=fn; + if (strstr(fn,"://")) return (int)WASABI_API_DIALOGBOXW(IDD_DIALOG4,hwnd,StreamProc); + else return (int)WASABI_API_DIALOGBOXW(IDD_DIALOG3,hwnd,MainProc); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/nsv_logo.bmp b/Src/Plugins/Input/in_nsv/nsv_logo.bmp Binary files differnew file mode 100644 index 00000000..bcdeaf9d --- /dev/null +++ b/Src/Plugins/Input/in_nsv/nsv_logo.bmp diff --git a/Src/Plugins/Input/in_nsv/proxydt.h b/Src/Plugins/Input/in_nsv/proxydt.h new file mode 100644 index 00000000..8802075d --- /dev/null +++ b/Src/Plugins/Input/in_nsv/proxydt.h @@ -0,0 +1,16 @@ +// proxydt.h +#ifndef PROXYDT_H +#define PROXYDT_H + +#include <string> +#include <stdio.h> +#include <atlbase.h> + +char* detectBrowserProxy(); + +char* DetectIEProxy(); + +char* DetectNS4Proxy(); +char* DetectNS6Proxy(); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_nsv/resource.h b/Src/Plugins/Input/in_nsv/resource.h new file mode 100644 index 00000000..108d7bbc --- /dev/null +++ b/Src/Plugins/Input/in_nsv/resource.h @@ -0,0 +1,86 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by res.rc +// +#define IDS_TOTAL_TAG_SIZE 1 +#define IDS_NO_METADATA 2 +#define IDS_TOTAL_TAG_SIZE_X_BYTES 3 +#define IDS_NO_TAG 4 +#define IDS_ERROR_WRITING_STRING_TO_TAG 5 +#define IDS_NSV_TAG_EDITOR_ERROR 6 +#define IDS_LARGE_DATA 7 +#define IDS_NO_VALID_NSV_BITSTREAM_FOUND 8 +#define IDS_VIDEO_X_AUDIO_X 9 +#define IDS_METADATA_STRING_MUST_CONTAIN_ONE_EQUAL_SIGN 10 +#define IDS_NSV_TAG_EDITOR 11 +#define IDS_CANNOT_CREATE_TEMPFILE_CANNOT_UPDATE_TAG 12 +#define IDS_ERROR_COPYING_SOURCE 13 +#define IDS_COPYING_X_BYTES 14 +#define IDS_ERROR_SIZE_MISMATCH 15 +#define IDS_ERROR_RENAMING_SOURCE 16 +#define IDS_ERROR_RENAMING_NEW_FILE 17 +#define IDS_READING_X_FRAMES 18 +#define IDS_NSV_ANALYSIS_FAILED 19 +#define IDS_METADATA_ITEM_CONTAINS_LARGE_AMOUNT_DATA 20 +#define IDS_CONNECTING 21 +#define IDS_OPENING 22 +#define IDS_BUFFER_X 23 +#define IDS_SERVER 24 +#define IDS_CONTENT_TYPE 25 +#define IDS_CONTENT_LENGTH 26 +#define IDS_STREAM_NAME 27 +#define IDS_NSA_NSV_FILE 28 +#define IDS_KBPS 29 +#define IDS_FPS 31 +#define IDS_FAMILY_STRING_NSV 32 +#define IDS_FAMILY_STRING_NSA 33 +#define IDD_DIALOG1 101 +#define IDB_BITMAP1 102 +#define IDD_DIALOG2 103 +#define IDD_DIALOG3 104 +#define IDD_DIALOG4 105 +#define IDD_ABOUT 106 +#define IDC_ANALYZE 1000 +#define IDC_VERSION 1000 +#define IDC_BUF1 1001 +#define IDC_LENBYTES 1001 +#define IDC_BUF2 1002 +#define IDC_LENMS 1002 +#define IDC_BUF3 1003 +#define IDC_TOC 1003 +#define IDC_OFFS 1004 +#define IDC_TOCSIZE 1004 +#define IDC_SETTOCSIZE 1005 +#define IDC_TAGPAD 1005 +#define IDC_METADATA_LEN 1006 +#define IDC_BUF4 1006 +#define IDC_TAG_LEN 1007 +#define IDC_BUF5 1007 +#define IDC_METADATA 1008 +#define IDC_BUF6 1008 +#define IDC_ADD 1009 +#define IDC_REM 1010 +#define IDC_EDIT 1011 +#define IDC_REMTAG 1012 +#define IDC_FASTUPD 1013 +#define IDC_EDIT1 1014 +#define IDC_AVGBITRATE 1014 +#define IDC_FN 1015 +#define IDC_INFO 1016 +#define IDC_BSINFO 1016 +#define IDC_INFOBORDER 1017 +#define IDC_CHECK1 1018 +#define IDC_CHECK3 1019 +#define IDC_CHECK2 1020 +#define IDS_NULLSOFT_NSV_DECODER 65534 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1019 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Plugins/Input/in_nsv/version.rc2 b/Src/Plugins/Input/in_nsv/version.rc2 new file mode 100644 index 00000000..51e28c40 --- /dev/null +++ b/Src/Plugins/Input/in_nsv/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,76,0,0 + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp Input Plug-in" + VALUE "FileVersion", "1,76,0,0" + VALUE "InternalName", "Nullsoft NSV Decoder" + VALUE "LegalCopyright", "Copyright © 2003-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "in_nsv.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END |