winamp/Src/omBrowser/pngLoader.cpp
2024-09-24 14:54:57 +02:00

360 lines
No EOL
8.6 KiB
C++

#include "main.h"
#include "./pngLoader.h"
#include "./browserObject.h"
#include "./ifc_wasabihelper.h"
#include <shlwapi.h>
#include <strsafe.h>
#ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
#define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x000000020
#endif //LOAD_LIBRARY_AS_IMAGE_RESOURCE
PngLoader::PngLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply)
: ref(1), instance(hInstance), name(NULL), flags(0)
{
name = Plugin_DuplicateResString(pszName);
if (FALSE != fPremultiply)
flags |= flagPremultiply;
}
PngLoader::~PngLoader()
{
Plugin_FreeResString(name);
}
HRESULT PngLoader::CreateInstance(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader)
{
if (NULL == imageLoader) return E_POINTER;
*imageLoader = NULL;
if (NULL == pszName) return E_INVALIDARG;
*imageLoader = new PngLoader(hInstance, pszName, fPremultiply);
if (NULL == *imageLoader) return E_OUTOFMEMORY;
return S_OK;
}
size_t PngLoader::AddRef()
{
return InterlockedIncrement((LONG*)&ref);
}
size_t PngLoader::Release()
{
if (0 == ref)
return ref;
LONG r = InterlockedDecrement((LONG*)&ref);
if (0 == r)
delete(this);
return r;
}
int PngLoader::QueryInterface(GUID interface_guid, void **object)
{
return E_NOINTERFACE;
}
static HRESULT PngLoader_LoadResourceData(const void *data, unsigned int size, void **dataOut, int *cx, int *cy, BOOL fPremultiply)
{
if (NULL == data) return E_INVALIDARG;
svc_imageLoader *loader = NULL;
ifc_wasabihelper *wasabi = NULL;
if (FAILED(Plugin_GetWasabiHelper(&wasabi))) return E_UNEXPECTED;
HRESULT hr = wasabi->GetPngLoader(&loader);
wasabi->Release();
if (FAILED(hr)) return hr;
*dataOut = (FALSE == fPremultiply) ?
loader->loadImageData(data, size, cx, cy) :
loader->loadImage(data, size, cx, cy);
if (NULL == *dataOut)
hr = E_OUTOFMEMORY;
loader->Release();
return hr;
}
static HRESULT PngLoader_LoadFromResource(HINSTANCE hInstance, LPCWSTR pszName, LPCWSTR pszType, void **dataOut, int *cx, int *cy, BOOL fPremultiply)
{
UINT errorCode = 0;
HRSRC res = FindResourceW(hInstance, pszName, pszType);
if (NULL == res)
{
errorCode = GetLastError();
return HRESULT_FROM_WIN32(errorCode);
}
HRESULT hr;
HANDLE handle = LoadResource(hInstance, res);
if (NULL == handle)
{
errorCode = GetLastError();
hr = HRESULT_FROM_WIN32(errorCode);
}
else
{
UINT resourceSize = SizeofResource(hInstance, res);
if (0 == resourceSize)
{
errorCode = GetLastError();
hr = HRESULT_FROM_WIN32(errorCode);
}
else
{
void *resourceData = LockResource(handle);
if (NULL == resourceData)
hr = E_OUTOFMEMORY;
else
hr = PngLoader_LoadResourceData(resourceData, resourceSize, dataOut, cx, cy, fPremultiply);
}
FreeResource(handle);
}
return hr;
}
static HRESULT PngLoader_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 = 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 = 0;
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 HRESULT PngLoader_LoadFromFile(LPWSTR pszPath, void **dataOut, int *cx, int *cy, BOOL fPremultiply)
{
HINSTANCE resModule = NULL;
LPCWSTR resName = NULL, resType = NULL;
HRESULT hr = PngLoader_ParseResProtocol(pszPath, RT_RCDATA, &resModule, &resName, &resType);
if (S_OK == hr)
return PngLoader_LoadFromResource(resModule, resName, resType, dataOut, cx, cy, fPremultiply);
if (FAILED(hr))
return hr;
UINT errorCode = 0;
HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
errorCode = GetLastError();
return HRESULT_FROM_WIN32(errorCode);
}
UINT resourceSize = GetFileSize(hFile, NULL);
if (INVALID_FILE_SIZE == resourceSize)
{
errorCode = GetLastError();
hr = HRESULT_FROM_WIN32(errorCode);
}
else
{
void *resourceData = malloc(resourceSize);
if (NULL == resourceData)
hr = E_OUTOFMEMORY;
else
{
DWORD readed = 0;
if (0 == ReadFile(hFile, resourceData, resourceSize, &readed, NULL) || resourceSize != readed)
{
errorCode = GetLastError();
hr = HRESULT_FROM_WIN32(errorCode);
}
else
{
hr = PngLoader_LoadResourceData(resourceData, resourceSize, dataOut, cx, cy, fPremultiply);
}
free(resourceData);
}
}
CloseHandle(hFile);
return hr;
}
HRESULT PngLoader::LoadData(int *widthOut, int *heightOut, void** dataOut)
{
if (NULL == dataOut)
return E_POINTER;
*dataOut = NULL;
return (NULL == instance && !IS_INTRESOURCE(name))?
PngLoader_LoadFromFile(name, dataOut, widthOut, heightOut, (0 != (flagPremultiply & flags))) :
PngLoader_LoadFromResource(instance, name, RT_RCDATA, dataOut, widthOut, heightOut, (0 != (flagPremultiply & flags)));
}
HRESULT PngLoader::FreeData(void *data)
{
if (NULL == data)
return S_FALSE;
ifc_wasabihelper *wasabi = NULL;
HRESULT hr = Plugin_GetWasabiHelper(&wasabi);
if (SUCCEEDED(hr) && wasabi != NULL)
{
api_memmgr *memoryManager = NULL;
hr = wasabi->GetMemoryManager(&memoryManager);
if (SUCCEEDED(hr) && memoryManager != NULL)
{
memoryManager->sysFree(data);
memoryManager->Release();
}
wasabi->Release();
}
return hr;
}
HRESULT PngLoader::LoadBitmapEx(HBITMAP *bitmapOut, BITMAPINFOHEADER *headerInfo, void **dataOut)
{
INT imageCX, imageCY;
if(NULL == bitmapOut) return E_POINTER;
void *data = NULL;
HRESULT hr = LoadData(&imageCX, &imageCY, &data);
if (FAILED(hr)) return hr;
ZeroMemory(headerInfo, sizeof(BITMAPINFOHEADER));
headerInfo->biSize = sizeof(BITMAPINFOHEADER);
headerInfo->biCompression = BI_RGB;
headerInfo->biBitCount = 32;
headerInfo->biPlanes = 1;
headerInfo->biWidth = imageCX;
headerInfo->biHeight = -imageCY;
*bitmapOut = CreateDIBSection(NULL, (LPBITMAPINFO)headerInfo, DIB_RGB_COLORS, dataOut, NULL, 0);
if (NULL != (*bitmapOut))
{
CopyMemory((*dataOut), data, headerInfo->biWidth * abs(headerInfo->biHeight) * sizeof(DWORD));
}
else
{
*dataOut = NULL;
hr = E_FAIL;
}
FreeData(data);
return hr;
}
HRESULT PngLoader::LoadBitmap(HBITMAP *bitmapOut, int *widthOut, int *heightOut)
{
BITMAPINFOHEADER header = {0};
void *pixelData = NULL;
if(NULL == bitmapOut) return E_POINTER;
HRESULT hr = LoadBitmapEx(bitmapOut, &header, &pixelData);
if (SUCCEEDED(hr))
{
if (NULL != widthOut) *widthOut = header.biWidth;
if (NULL != heightOut) *heightOut = header.biHeight;
}
else
{
if (NULL != widthOut) *widthOut = 0;
if (NULL != heightOut) *heightOut = 0;
}
return hr;
}
#define CBCLASS PngLoader
START_DISPATCH;
CB(ADDREF, AddRef);
CB(RELEASE, Release);
CB(QUERYINTERFACE, QueryInterface);
CB(API_LOADDATA, LoadData);
CB(API_FREEDATA, FreeData);
CB(API_LOADBITMAP, LoadBitmap);
CB(API_LOADBITMAPEX, LoadBitmapEx);
END_DISPATCH;
#undef CBCLASS