#include "./imageLoader.h" #include "./common.h" #include "../api.h" #include #include template 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; }