| 1 |
/* |
| 2 |
* Copyright (C) 2020- TeraTerm Project |
| 3 |
* All rights reserved. |
| 4 |
* |
| 5 |
* Redistribution and use in source and binary forms, with or without |
| 6 |
* modification, are permitted provided that the following conditions |
| 7 |
* are met: |
| 8 |
* |
| 9 |
* 1. Redistributions of source code must retain the above copyright |
| 10 |
* notice, this list of conditions and the following disclaimer. |
| 11 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 12 |
* notice, this list of conditions and the following disclaimer in the |
| 13 |
* documentation and/or other materials provided with the distribution. |
| 14 |
* 3. The name of the author may not be used to endorse or promote products |
| 15 |
* derived from this software without specific prior written permission. |
| 16 |
* |
| 17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
| 18 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 19 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 20 |
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 21 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 22 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 26 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
*/ |
| 28 |
|
| 29 |
#include "libsusieplugin.h" |
| 30 |
|
| 31 |
#if defined(_M_X64) |
| 32 |
#define PLUGIN_EXT L".sph" |
| 33 |
#else |
| 34 |
#define PLUGIN_EXT L".spi" |
| 35 |
#endif |
| 36 |
|
| 37 |
/** |
| 38 |
* Susie �v���O�C�����g������������������ |
| 39 |
* |
| 40 |
* @param[in] nameSPI �v���O�C���t�@�C���� |
| 41 |
* @param[in] nameFile �����t�@�C����(�������������������������g������������������) |
| 42 |
* @param[in] bufFile �����f�[�^�����|�C���^ |
| 43 |
* @param[in] sizeFile �����f�[�^�T�C�Y |
| 44 |
* @param[out] pHBInfo BITMAPINFO LocalFree()�������� |
| 45 |
* @param[out] pHBm bitmap data LocalFree()�������� |
| 46 |
* |
| 47 |
* �v���O�C����Unicode�p�X�����������������[�h������ |
| 48 |
* �����t�@�C�������v���O�C�����������g�p�������� |
| 49 |
* �v���O�C�������t�@�C���������������� Unicode����ok���v������ |
| 50 |
*/ |
| 51 |
BOOL LoadPictureWithSPI(const wchar_t *nameSPI, const wchar_t *nameFile, unsigned char *bufFile, size_t sizeFile, HLOCAL *hbuf, |
| 52 |
HLOCAL *hbmi) |
| 53 |
{ |
| 54 |
// �����t�@�C�����t�@�C���������������o�� |
| 55 |
const wchar_t *image_base = wcsrchr(nameFile, L'\\'); |
| 56 |
if (image_base != NULL) { |
| 57 |
image_base++; |
| 58 |
} |
| 59 |
else { |
| 60 |
image_base = wcsrchr(nameFile, L'/'); |
| 61 |
if (image_base != NULL) { |
| 62 |
image_base++; |
| 63 |
} |
| 64 |
else { |
| 65 |
image_base = nameFile; |
| 66 |
} |
| 67 |
} |
| 68 |
|
| 69 |
char nameFileA[MAX_PATH]; |
| 70 |
WideCharToMultiByte(CP_ACP, 0, image_base, -1, nameFileA, _countof(nameFileA), NULL, NULL); |
| 71 |
|
| 72 |
HINSTANCE hSPI; |
| 73 |
char spiVersion[8]; |
| 74 |
int(__stdcall * SPI_IsSupported)(LPCSTR, void *); |
| 75 |
int(__stdcall * SPI_GetPicture)(LPCSTR buf, LONG_PTR len, unsigned int flag, HANDLE *pHBInfo, HANDLE *pHBm, FARPROC, |
| 76 |
LONG_PTR lData); |
| 77 |
int(__stdcall * SPI_GetPluginInfo)(int, LPSTR, int); |
| 78 |
int ret; |
| 79 |
|
| 80 |
ret = FALSE; |
| 81 |
hSPI = NULL; |
| 82 |
|
| 83 |
// SPI �����[�h |
| 84 |
hSPI = LoadLibraryW(nameSPI); |
| 85 |
if (!hSPI) { |
| 86 |
return FALSE; |
| 87 |
} |
| 88 |
|
| 89 |
FARPROC *p = (FARPROC *)&SPI_GetPluginInfo; |
| 90 |
*p = GetProcAddress(hSPI, "GetPluginInfo"); |
| 91 |
p = (FARPROC *)&SPI_IsSupported; |
| 92 |
*p = GetProcAddress(hSPI, "IsSupported"); |
| 93 |
p = (FARPROC *)&SPI_GetPicture; |
| 94 |
*p = GetProcAddress(hSPI, "GetPicture"); |
| 95 |
|
| 96 |
if (!SPI_GetPluginInfo || !SPI_IsSupported || !SPI_GetPicture) |
| 97 |
goto error; |
| 98 |
|
| 99 |
//�o�[�W�����`�F�b�N |
| 100 |
SPI_GetPluginInfo(0, spiVersion, 8); |
| 101 |
|
| 102 |
if (spiVersion[2] != 'I' || spiVersion[3] != 'N') |
| 103 |
goto error; |
| 104 |
|
| 105 |
if (!(SPI_IsSupported)(nameFileA, bufFile)) |
| 106 |
goto error; |
| 107 |
|
| 108 |
if ((SPI_GetPicture)((LPCSTR)bufFile, sizeFile, 1, hbmi, hbuf, NULL, 0)) |
| 109 |
goto error; |
| 110 |
|
| 111 |
ret = TRUE; |
| 112 |
|
| 113 |
error: |
| 114 |
|
| 115 |
if (hSPI) |
| 116 |
FreeLibrary(hSPI); |
| 117 |
|
| 118 |
return ret; |
| 119 |
} |
| 120 |
|
| 121 |
static unsigned char *LoadImageFile(const wchar_t *image_file, size_t *file_size) |
| 122 |
{ |
| 123 |
HANDLE hPictureFile = CreateFileW(image_file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| 124 |
if (hPictureFile == INVALID_HANDLE_VALUE) { |
| 125 |
*file_size = 0; |
| 126 |
return FALSE; |
| 127 |
} |
| 128 |
DWORD fileSize = GetFileSize(hPictureFile, 0); |
| 129 |
if (fileSize < 2 * 1024) { |
| 130 |
//���� 2kb ���m�� (Susie plugin ���d�l����) |
| 131 |
fileSize = 2 * 1024; |
| 132 |
} |
| 133 |
unsigned char *fileBuf = (unsigned char *)malloc(fileSize); |
| 134 |
memset(fileBuf, 0, 2*1024); //���� 2kb �� 0 �������� |
| 135 |
DWORD readByte; |
| 136 |
ReadFile(hPictureFile, fileBuf, fileSize, &readByte, 0); |
| 137 |
CloseHandle(hPictureFile); |
| 138 |
|
| 139 |
*file_size = fileSize; |
| 140 |
return fileBuf; |
| 141 |
} |
| 142 |
|
| 143 |
static wchar_t *NormalizePath(const wchar_t *path) |
| 144 |
{ |
| 145 |
size_t len = GetFullPathNameW(path, 0, NULL, NULL); // include L'\0' |
| 146 |
if (len == 0) { |
| 147 |
return NULL; |
| 148 |
} |
| 149 |
wchar_t *normalized_path = (wchar_t *)malloc(sizeof(wchar_t) * len); |
| 150 |
len = GetFullPathNameW(path, (DWORD)len, normalized_path, NULL); |
| 151 |
if (len == 0) { |
| 152 |
free(normalized_path); |
| 153 |
return NULL; |
| 154 |
} |
| 155 |
wchar_t *p = wcsrchr(normalized_path, L'\\'); |
| 156 |
if (p != NULL) { |
| 157 |
if (*(p + 1) == 0) { |
| 158 |
*p = 0; // delete last '\\' |
| 159 |
} |
| 160 |
} |
| 161 |
DWORD attr = GetFileAttributesW(normalized_path); |
| 162 |
if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { |
| 163 |
free(normalized_path); |
| 164 |
return NULL; |
| 165 |
} |
| 166 |
return normalized_path; |
| 167 |
} |
| 168 |
|
| 169 |
/** |
| 170 |
* Susie�v���O�C�����g���������t�@�C�������[�h���� |
| 171 |
* �w���t�H���_�����v���O�C�����g�������[�h�������� |
| 172 |
* |
| 173 |
* @param[in] image_file �����t�@�C�� |
| 174 |
* @param[in] spi_path "c:\\path\\to\\spi" |
| 175 |
* �����t�H���_�������v���O�C���t�@�C�������������[�h�������� |
| 176 |
* �p�X�������� "\\" ���������������������� |
| 177 |
* @param[out] pHBInfo BITMAPINFO LocalFree()�������� |
| 178 |
* @param[out] pHBm bitmap data LocalFree()�������� |
| 179 |
* @retval TRUE ���[�hok |
| 180 |
* @retval FALSE ���[�h������������ |
| 181 |
*/ |
| 182 |
BOOL SusieLoadPicture(const wchar_t *image_file, const wchar_t *spi_path, HANDLE *pHBInfo, HANDLE *pHBm) |
| 183 |
{ |
| 184 |
BOOL result = FALSE; |
| 185 |
*pHBInfo = NULL; |
| 186 |
*pHBm = NULL; |
| 187 |
|
| 188 |
size_t file_size; |
| 189 |
unsigned char *file_ptr = LoadImageFile(image_file, &file_size); |
| 190 |
if (file_ptr == NULL) { |
| 191 |
return FALSE; |
| 192 |
} |
| 193 |
|
| 194 |
// spi_path �������p�X������ |
| 195 |
wchar_t *spi_path_full = NormalizePath(spi_path); |
| 196 |
if (spi_path_full == NULL) { |
| 197 |
free(file_ptr); |
| 198 |
return FALSE; |
| 199 |
} |
| 200 |
const size_t spi_path_full_len = wcslen(spi_path_full); |
| 201 |
|
| 202 |
// mask���� |
| 203 |
const size_t spi_path_mask_len = spi_path_full_len + 4 + 1; |
| 204 |
wchar_t *spi_path_mask = (wchar_t *)malloc(spi_path_mask_len * sizeof(wchar_t)); |
| 205 |
wcsncpy_s(spi_path_mask, spi_path_mask_len, spi_path_full, _TRUNCATE); |
| 206 |
wcsncat_s(spi_path_mask, spi_path_mask_len, L"\\*.*", _TRUNCATE); |
| 207 |
|
| 208 |
//�v���O�C���������������� |
| 209 |
WIN32_FIND_DATAW fd; |
| 210 |
HANDLE hFind = FindFirstFileW(spi_path_mask, &fd); |
| 211 |
if (hFind != INVALID_HANDLE_VALUE) { |
| 212 |
const size_t spiFileNameLen = spi_path_full_len + 1 + _countof(fd.cFileName); |
| 213 |
wchar_t *spiFileName = (wchar_t *)malloc(spiFileNameLen * sizeof(wchar_t)); |
| 214 |
do { |
| 215 |
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
| 216 |
continue; |
| 217 |
const wchar_t *ext = wcsrchr(fd.cFileName, L'.'); |
| 218 |
if (ext == NULL) { |
| 219 |
// �g���q�������t�@�C��? |
| 220 |
continue; |
| 221 |
} |
| 222 |
if (wcscmp(ext, L".dll") != 0 && wcscmp(ext, PLUGIN_EXT) != 0) { |
| 223 |
// .dll or .spi(or sph) ���O���t�@�C�� |
| 224 |
continue; |
| 225 |
} |
| 226 |
|
| 227 |
wcsncpy_s(spiFileName, spiFileNameLen, spi_path_full, _TRUNCATE); |
| 228 |
wcsncat_s(spiFileName, spiFileNameLen, L"\\", _TRUNCATE); |
| 229 |
wcsncat_s(spiFileName, spiFileNameLen, fd.cFileName, _TRUNCATE); |
| 230 |
|
| 231 |
HLOCAL hbuf, hbmi; |
| 232 |
if (LoadPictureWithSPI(spiFileName, image_file, file_ptr, file_size, &hbuf, &hbmi)) { |
| 233 |
*pHBInfo = hbmi; |
| 234 |
*pHBm = hbuf; |
| 235 |
result = TRUE; |
| 236 |
break; |
| 237 |
} |
| 238 |
} while (FindNextFileW(hFind, &fd)); |
| 239 |
free(spiFileName); |
| 240 |
FindClose(hFind); |
| 241 |
} |
| 242 |
|
| 243 |
free(spi_path_full); |
| 244 |
free(spi_path_mask); |
| 245 |
free(file_ptr); |
| 246 |
return result; |
| 247 |
} |