mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-12-18 13:35:53 +01:00
360 lines
8.6 KiB
C++
360 lines
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 |