diff options
Diffstat (limited to 'Src/auth/Loginbox/imageLoader.cpp')
-rw-r--r-- | Src/auth/Loginbox/imageLoader.cpp | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/Src/auth/Loginbox/imageLoader.cpp b/Src/auth/Loginbox/imageLoader.cpp new file mode 100644 index 00000000..f82128a3 --- /dev/null +++ b/Src/auth/Loginbox/imageLoader.cpp @@ -0,0 +1,331 @@ +#include "./imageLoader.h" +#include "./common.h" +#include "../api.h" + +#include <api/service/waservicefactory.h> + +#include <shlwapi.h> + +template <class api_T> +void ImageLoader_ServiceBuild(api_T *&api_t, GUID factoryGUID_t) +{ + if (WASABI_API_SVC) + { + waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(factoryGUID_t); + if (factory) + api_t = (api_T *)factory->getInterface(); + } +} + +typedef BOOL (CALLBACK *IMAGEDATAPROCESSOR)(const void * /*data*/, size_t /*dataSize*/, ULONG_PTR /*param*/); + + +typedef struct __LOADDATAPARAM +{ + BOOL premultiply; + INT cx; + INT cy; + void *pixels; +} LOADDATAPARAM; + +typedef struct __GETDIMENSIONPARAM +{ + INT cx; + INT cy; +} GETDIMENSIONPARAM; + +static BOOL CALLBACK ImageLoader_LoadDataCallback(const void *data, size_t size, ULONG_PTR param) +{ + LOADDATAPARAM *loadParam = (LOADDATAPARAM*)param; + if (NULL == loadParam) return FALSE; + + if (NULL == WASABI_API_PNGLOADER) + { + ImageLoader_ServiceBuild(WASABI_API_PNGLOADER, pngLoaderGUID); + if (NULL == WASABI_API_PNGLOADER) + return FALSE; + } + + loadParam->pixels = (FALSE == loadParam->premultiply) ? + WASABI_API_PNGLOADER->loadImageData(data, (INT)size, &loadParam->cx, &loadParam->cy) : + WASABI_API_PNGLOADER->loadImage(data, (INT)size, &loadParam->cx, &loadParam->cy); + + return (NULL != loadParam->pixels); +} + +static BOOL CALLBACK ImageLoader_GetDimensionsCallback(const void *data, size_t size, ULONG_PTR param) +{ + GETDIMENSIONPARAM *dimensionParam = (GETDIMENSIONPARAM*)param; + if (NULL == dimensionParam) return FALSE; + + if (NULL == WASABI_API_PNGLOADER) + { + ImageLoader_ServiceBuild(WASABI_API_PNGLOADER, pngLoaderGUID); + if (NULL == WASABI_API_PNGLOADER) + return FALSE; + } + + return WASABI_API_PNGLOADER->getDimensions(data, (INT)size, &dimensionParam->cx, &dimensionParam->cy); +} + +static BOOL ImageLoader_ProcessResource(HINSTANCE hInstance, LPCWSTR pszName, LPCWSTR pszType, IMAGEDATAPROCESSOR processor, ULONG_PTR param) +{ + HRSRC res = FindResourceW(hInstance, pszName, pszType); + if (NULL == res) return FALSE; + + BOOL fSucceeded = FALSE; + HANDLE handle = LoadResource(hInstance, res); + if (NULL != handle) + { + UINT resourceSize = SizeofResource(hInstance, res); + if (0 != resourceSize) + { + void *resourceData = LockResource(handle); + if (NULL != resourceData) + fSucceeded = processor(resourceData, resourceSize, param); + } + FreeResource(handle); + } + return fSucceeded; +} + +static HRESULT ImageLoader_ParseResProtocol(LPWSTR pszAddress, LPCWSTR defaultType, HINSTANCE *module, LPCWSTR *resourceName, LPCWSTR *resourceType) +{ + if (NULL == module || NULL == resourceName || NULL == resourceType) + return E_POINTER; + + if (NULL == pszAddress || L'\0' == *pszAddress) + return E_INVALIDARG; + + INT cchAddress = lstrlenW(pszAddress); + const WCHAR szPrefix[] = L"res://"; + INT cchPrefix = ARRAYSIZE(szPrefix) - 1; + if (cchAddress <= cchPrefix) + return S_FALSE; + + if (CSTR_EQUAL != CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, pszAddress, cchPrefix, szPrefix, cchPrefix)) + return S_FALSE; + + pszAddress += cchPrefix; + cchAddress -= cchPrefix; + + LPWSTR resType = NULL; + LPWSTR resName = NULL; + + LPWSTR p = pszAddress + cchAddress; + while (p != pszAddress && L'/' != *p) p--; + if (p != pszAddress && p < (pszAddress + cchAddress)) + { + resName = p + 1; + *p = L'\0'; + p--; + } + + if (NULL == resName || L'\0' == *resName) + return E_FAIL; + + + while (p != pszAddress && L'/' != *p) p--; + if (p != pszAddress && p < resName) + { + resType = p + 1; + if (L'\0' == *resType) + { + resType = NULL; + } + else + { + resType = p + 1; + *p = L'\0'; + p--; + } + } + + HINSTANCE hModule; + hModule = LoadLibraryExW(pszAddress, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (NULL == hModule) + { + UINT errorCode = GetLastError(); + if (NULL != resType) + { + *(resType - 1) = L'/'; + resType = NULL; + hModule = LoadLibraryExW(pszAddress, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (NULL == hModule) errorCode = GetLastError(); + } + + if (ERROR_SUCCESS != errorCode) + return HRESULT_FROM_WIN32(errorCode); + } + + if (NULL == resType) + resType = (LPWSTR)defaultType; + + if (NULL != resType && FALSE == IS_INTRESOURCE(resType) && L'#' == *resType) + { + INT typeId; + if (FALSE != StrToIntExW(resType + 1, STIF_DEFAULT, &typeId)) + resType = MAKEINTRESOURCEW(typeId); + } + + if (NULL != resName && FALSE == IS_INTRESOURCE(resName) && L'#' == *resName) + { + INT nameId; + if (FALSE != StrToIntExW(resName + 1, STIF_DEFAULT, &nameId)) + resName = MAKEINTRESOURCEW(nameId); + } + + *module = hModule; + *resourceName = resName; + *resourceType = resType; + return S_OK; +} + +static BOOL ImageLoader_ProcessFile(LPCWSTR pszPath, IMAGEDATAPROCESSOR processor, ULONG_PTR param) +{ + HINSTANCE resModule; + LPCWSTR resName, resType; + + BOOL fSucceeded = FALSE; + + LPWSTR name = LoginBox_CopyString(pszPath); + HRESULT hr = ImageLoader_ParseResProtocol(name, RT_RCDATA, &resModule, &resName, &resType); + if (S_OK == hr) + { + fSucceeded = ImageLoader_ProcessResource(resModule, resName, resType, processor, param); + LoginBox_FreeString(name); + return fSucceeded; + } + + LoginBox_FreeString(name); + + if (FAILED(hr)) + return FALSE; + + HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (INVALID_HANDLE_VALUE == hFile) + return FALSE; + + UINT resourceSize = GetFileSize(hFile, NULL); + if (INVALID_FILE_SIZE != resourceSize) + { + void *resourceData = malloc(resourceSize); + if (NULL != resourceData) + { + DWORD readed = 0; + if (0 != ReadFile(hFile, resourceData, resourceSize, &readed, NULL) || resourceSize != readed) + fSucceeded = processor(resourceData, resourceSize, param); + free(resourceData); + } + } + CloseHandle(hFile); + + return fSucceeded; +} + +void *ImageLoader_LoadData(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, INT *widthOut, INT *heightOut) +{ + BOOL fSucceeded; + LOADDATAPARAM param; + param.premultiply = fPremultiply; + if (NULL == hInstance && !IS_INTRESOURCE(pszName)) + fSucceeded = ImageLoader_ProcessFile(pszName, ImageLoader_LoadDataCallback, (ULONG_PTR)¶m); + else + fSucceeded = ImageLoader_ProcessResource(hInstance, pszName, RT_RCDATA, ImageLoader_LoadDataCallback, (ULONG_PTR)¶m); + + if (FALSE == fSucceeded) + { + if (NULL != widthOut) *widthOut = 0; + if (NULL != heightOut) *heightOut = 0; + return NULL; + } + + if (NULL != widthOut) *widthOut = param.cx; + if (NULL != heightOut) *heightOut = param.cy; + + return param.pixels; +} + +void ImageLoader_FreeData(void *data) +{ + if (NULL == data) + return; + + if (NULL == WASABI_API_MEMMNGR) + { + ImageLoader_ServiceBuild(WASABI_API_MEMMNGR, memMgrApiServiceGuid); + if (NULL == WASABI_API_MEMMNGR) return; + } + + WASABI_API_MEMMNGR->sysFree(data); +} + +HBITMAP ImageLoader_LoadBitmapEx(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, BITMAPINFOHEADER *headerInfo, void **dataOut) +{ + INT imageCX, imageCY; + + void *data = ImageLoader_LoadData(hInstance, pszName, fPremultiply, &imageCX, &imageCY); + if (NULL == data) return NULL; + + ZeroMemory(headerInfo, sizeof(BITMAPINFOHEADER)); + headerInfo->biSize = sizeof(BITMAPINFOHEADER); + headerInfo->biCompression = BI_RGB; + headerInfo->biBitCount = 32; + headerInfo->biPlanes = 1; + headerInfo->biWidth = imageCX; + headerInfo->biHeight = -imageCY; + + void *pixelData; + HBITMAP bitmap = CreateDIBSection(NULL, (LPBITMAPINFO)headerInfo, DIB_RGB_COLORS, &pixelData, NULL, 0); + if (NULL != bitmap) + { + if (NULL != dataOut) *dataOut = pixelData; + CopyMemory(pixelData, data, headerInfo->biWidth * abs(headerInfo->biHeight) * sizeof(DWORD)); + } + else + { + if (NULL != dataOut) *dataOut = NULL; + } + + ImageLoader_FreeData(data); + return bitmap; +} + +HBITMAP ImageLoader_LoadBitmap(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, INT *widthOut, INT *heightOut) +{ + BITMAPINFOHEADER header; + HBITMAP bitmap = ImageLoader_LoadBitmapEx(hInstance, pszName, fPremultiply, &header, NULL); + if (NULL != bitmap) + { + if (NULL != widthOut) *widthOut = header.biWidth; + if (NULL != heightOut) *heightOut = header.biHeight; + } + else + { + if (NULL != widthOut) *widthOut = 0; + if (NULL != heightOut) *heightOut = 0; + } + return bitmap; +} + +BOOL ImageLoader_GetDimensions(HINSTANCE hInstance, LPCWSTR pszName, INT *widthOut, INT *heightOut) +{ + BOOL fSucceeded; + GETDIMENSIONPARAM param; + if (NULL == hInstance && !IS_INTRESOURCE(pszName)) + fSucceeded = ImageLoader_ProcessFile(pszName, ImageLoader_GetDimensionsCallback, (ULONG_PTR)¶m); + else + fSucceeded = ImageLoader_ProcessResource(hInstance, pszName, RT_RCDATA, ImageLoader_GetDimensionsCallback, (ULONG_PTR)¶m); + + if (FALSE == fSucceeded) + { + if (NULL != widthOut) *widthOut = 0; + if (NULL != heightOut) *heightOut = 0; + return FALSE; + } + + if (NULL != widthOut) *widthOut = param.cx; + if (NULL != heightOut) *heightOut = param.cy; + + return TRUE; +}
\ No newline at end of file |