1 #include <precomp.h> 2 3 /* LoadLPK global variables */ 4 HINSTANCE hLpk = NULL; 5 LPKETO LpkExtTextOut = NULL; 6 LPKGCP LpkGetCharacterPlacement = NULL; 7 8 /** 9 * @name CalculateColorTableSize 10 * 11 * Internal routine to calculate the number of color table entries. 12 * 13 * @param BitmapInfoHeader 14 * Input bitmap information header, can be any version of 15 * BITMAPINFOHEADER or BITMAPCOREHEADER. 16 * 17 * @param ColorSpec 18 * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS 19 * or DIB_RGB_COLORS). On successful return this value is normalized 20 * according to the bitmap info. 21 * 22 * @param ColorTableSize 23 * On successful return this variable is filled with number of 24 * entries in color table for the image with specified parameters. 25 * 26 * @return 27 * TRUE if the input values together form a valid image, FALSE otherwise. 28 */ 29 30 BOOL WINAPI 31 CalculateColorTableSize( 32 CONST BITMAPINFOHEADER *BitmapInfoHeader, 33 UINT *ColorSpec, 34 UINT *ColorTableSize) 35 { 36 WORD BitCount; 37 DWORD ClrUsed; 38 DWORD Compression; 39 40 /* 41 * At first get some basic parameters from the passed BitmapInfoHeader 42 * structure. It can have one of the following formats: 43 * - BITMAPCOREHEADER (the oldest one with totally different layout 44 * from the others) 45 * - BITMAPINFOHEADER (the standard and most common header) 46 * - BITMAPV4HEADER (extension of BITMAPINFOHEADER) 47 * - BITMAPV5HEADER (extension of BITMAPV4HEADER) 48 */ 49 50 if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER)) 51 { 52 BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount; 53 ClrUsed = 0; 54 Compression = BI_RGB; 55 } 56 else 57 { 58 BitCount = BitmapInfoHeader->biBitCount; 59 ClrUsed = BitmapInfoHeader->biClrUsed; 60 Compression = BitmapInfoHeader->biCompression; 61 } 62 63 switch (Compression) 64 { 65 case BI_BITFIELDS: 66 if (*ColorSpec == DIB_PAL_COLORS) 67 *ColorSpec = DIB_RGB_COLORS; 68 69 if (BitCount != 16 && BitCount != 32) 70 return FALSE; 71 72 /* 73 * For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in 74 * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask). 75 * For BITMAPINFOHEADER the color masks are stored in the palette. 76 */ 77 78 if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER)) 79 *ColorTableSize = 0; 80 else 81 *ColorTableSize = 3; 82 83 return TRUE; 84 85 case BI_RGB: 86 switch (BitCount) 87 { 88 case 1: 89 *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2; 90 return TRUE; 91 92 case 4: 93 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16; 94 return TRUE; 95 96 case 8: 97 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256; 98 return TRUE; 99 100 default: 101 if (*ColorSpec == DIB_PAL_COLORS) 102 *ColorSpec = DIB_RGB_COLORS; 103 if (BitCount != 16 && BitCount != 24 && BitCount != 32) 104 return FALSE; 105 *ColorTableSize = ClrUsed; 106 return TRUE; 107 } 108 109 case BI_RLE4: 110 if (BitCount == 4) 111 { 112 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16; 113 return TRUE; 114 } 115 return FALSE; 116 117 case BI_RLE8: 118 if (BitCount == 8) 119 { 120 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256; 121 return TRUE; 122 } 123 return FALSE; 124 125 case BI_JPEG: 126 case BI_PNG: 127 *ColorTableSize = ClrUsed; 128 return TRUE; 129 130 default: 131 return FALSE; 132 } 133 } 134 135 /** 136 * @name ConvertBitmapInfo 137 * 138 * Internal routine to convert a user-passed BITMAPINFO structure into 139 * unified BITMAPINFO structure. 140 * 141 * @param BitmapInfo 142 * Input bitmap info, can be any version of BITMAPINFO or 143 * BITMAPCOREINFO. 144 * @param ColorSpec 145 * Specifies whether the bmiColors member of the BITMAPINFO structure 146 * contains a valid color table and, if so, whether the entries in 147 * this color table contain explicit red, green, blue (DIB_RGB_COLORS) 148 * values or palette indexes (DIB_PAL_COLORS). 149 * @param BitmapInfoSize 150 * On successful return contains the size of the returned BITMAPINFO 151 * structure. If FollowedByData is TRUE the size includes the number 152 * of bytes occupied by the image data. 153 * @param FollowedByData 154 * Specifies if the BITMAPINFO header is immediately followed 155 * by the actual bitmap data (eg. as passed to CreateDIBPatternBrush). 156 * 157 * @return 158 * Either the original BitmapInfo or newly allocated structure is 159 * returned. For the later case the caller is responsible for freeing the 160 * memory using RtlFreeHeap with the current process heap. 161 * 162 * @example 163 * PBITMAPINFO NewBitmapInfo; 164 * UINT NewBitmapInfoSize; 165 * 166 * NewBitmapInfo = ConvertBitmapInfo(OldBitmapInfo, DIB_RGB_COLORS, 167 * &NewBitmapInfoSize, FALSE); 168 * if (NewBitmapInfo) 169 * { 170 * <do something with the bitmap info> 171 * if (NewBitmapInfo != OldBitmapInfo) 172 * RtlFreeHeap(RtlGetProcessHeap(), 0, NewBitmapInfo); 173 * } 174 */ 175 176 LPBITMAPINFO WINAPI 177 ConvertBitmapInfo( 178 CONST BITMAPINFO *BitmapInfo, 179 UINT ColorSpec, 180 UINT *BitmapInfoSize, 181 BOOL FollowedByData) 182 { 183 LPBITMAPINFO NewBitmapInfo = (LPBITMAPINFO)BitmapInfo; 184 LPBITMAPCOREINFO CoreBitmapInfo = (LPBITMAPCOREINFO)BitmapInfo; 185 DWORD Size = 0; 186 ULONG DataSize = 0; 187 UINT PaletteEntryCount = 0; 188 189 /* 190 * At first check if the passed BitmapInfo structure has valid size. It 191 * can have one of these headers: BITMAPCOREHEADER, BITMAPINFOHEADER, 192 * BITMAPV4HEADER or BITMAPV5HEADER (see CalculateColorTableSize for 193 * description). 194 */ 195 196 if ( !BitmapInfo || 197 (BitmapInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) && 198 (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) || 199 BitmapInfo->bmiHeader.biSize > sizeof(BITMAPV5HEADER)))) 200 { 201 return NULL; 202 } 203 204 /* 205 * Now calculate the color table size. Also if the bitmap info contains 206 * invalid color information it's rejected here. 207 */ 208 209 if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec, 210 &PaletteEntryCount)) 211 { 212 return NULL; 213 } 214 215 /* 216 * Calculate the size of image data if applicable. We must be careful 217 * to do proper aligning on line ends. 218 */ 219 220 if (FollowedByData) 221 { 222 DataSize = GdiGetBitmapBitsSize((PBITMAPINFO)BitmapInfo ); 223 } 224 225 /* 226 * If BitmapInfo was originally BITMAPCOREINFO then we need to convert 227 * it to the standard BITMAPINFO layout. 228 */ 229 230 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 231 { 232 Size = sizeof(BITMAPINFOHEADER); 233 if (ColorSpec == DIB_RGB_COLORS) 234 Size += PaletteEntryCount * sizeof(RGBQUAD); 235 else 236 Size += PaletteEntryCount * sizeof(USHORT); 237 Size += DataSize; 238 239 NewBitmapInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); 240 if (NewBitmapInfo == NULL) 241 { 242 return NULL; 243 } 244 245 NewBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 246 NewBitmapInfo->bmiHeader.biWidth = CoreBitmapInfo->bmciHeader.bcWidth; 247 NewBitmapInfo->bmiHeader.biHeight = CoreBitmapInfo->bmciHeader.bcHeight; 248 NewBitmapInfo->bmiHeader.biPlanes = CoreBitmapInfo->bmciHeader.bcPlanes; 249 NewBitmapInfo->bmiHeader.biBitCount = CoreBitmapInfo->bmciHeader.bcBitCount; 250 NewBitmapInfo->bmiHeader.biCompression = BI_RGB; 251 NewBitmapInfo->bmiHeader.biSizeImage = 0; 252 NewBitmapInfo->bmiHeader.biXPelsPerMeter = 0; 253 NewBitmapInfo->bmiHeader.biYPelsPerMeter = 0; 254 NewBitmapInfo->bmiHeader.biClrUsed = 0; 255 NewBitmapInfo->bmiHeader.biClrImportant = 0; 256 257 if (PaletteEntryCount != 0) 258 { 259 if (ColorSpec == DIB_RGB_COLORS) 260 { 261 ULONG Index; 262 263 for (Index = 0; Index < PaletteEntryCount; Index++) 264 { 265 NewBitmapInfo->bmiColors[Index].rgbRed = 266 CoreBitmapInfo->bmciColors[Index].rgbtRed; 267 NewBitmapInfo->bmiColors[Index].rgbGreen = 268 CoreBitmapInfo->bmciColors[Index].rgbtGreen; 269 NewBitmapInfo->bmiColors[Index].rgbBlue = 270 CoreBitmapInfo->bmciColors[Index].rgbtBlue; 271 NewBitmapInfo->bmiColors[Index].rgbReserved = 0; 272 } 273 } 274 else 275 { 276 RtlCopyMemory(NewBitmapInfo->bmiColors, 277 CoreBitmapInfo->bmciColors, 278 PaletteEntryCount * sizeof(USHORT)); 279 } 280 } 281 282 if (FollowedByData) 283 { 284 ULONG_PTR NewDataPtr, OldDataPtr; 285 286 if (ColorSpec == DIB_RGB_COLORS) 287 { 288 NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors + 289 PaletteEntryCount); 290 OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors + 291 PaletteEntryCount); 292 } 293 else 294 { 295 NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors) + 296 PaletteEntryCount * sizeof(USHORT); 297 OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors) + 298 PaletteEntryCount * sizeof(USHORT); 299 } 300 301 RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize); 302 } 303 } 304 else 305 { 306 /* Verify some data validity */ 307 switch (BitmapInfo->bmiHeader.biCompression) 308 { 309 case BI_RLE8: 310 if (BitmapInfo->bmiHeader.biBitCount != 8) 311 return NULL; 312 if (BitmapInfo->bmiHeader.biHeight < 0) 313 return NULL; 314 break; 315 case BI_RLE4: 316 if (BitmapInfo->bmiHeader.biBitCount != 4) 317 return NULL; 318 if (BitmapInfo->bmiHeader.biHeight < 0) 319 return NULL; 320 break; 321 default: 322 break; 323 } 324 325 /* Non "standard" formats must have a valid size set */ 326 if ((BitmapInfo->bmiHeader.biCompression != BI_RGB) && 327 (BitmapInfo->bmiHeader.biCompression != BI_BITFIELDS)) 328 { 329 if (BitmapInfo->bmiHeader.biSizeImage == 0) 330 return NULL; 331 } 332 } 333 334 Size = NewBitmapInfo->bmiHeader.biSize; 335 if (ColorSpec == DIB_RGB_COLORS) 336 Size += PaletteEntryCount * sizeof(RGBQUAD); 337 else 338 Size += PaletteEntryCount * sizeof(USHORT); 339 Size += DataSize; 340 *BitmapInfoSize = Size; 341 342 return NewBitmapInfo; 343 } 344 345 VOID 346 WINAPI 347 LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA) 348 { 349 #define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len ) 350 #define COPYN(f) pW->f = pA->f 351 352 COPYN(lfHeight); 353 COPYN(lfWidth); 354 COPYN(lfEscapement); 355 COPYN(lfOrientation); 356 COPYN(lfWeight); 357 COPYN(lfItalic); 358 COPYN(lfUnderline); 359 COPYN(lfStrikeOut); 360 COPYN(lfCharSet); 361 COPYN(lfOutPrecision); 362 COPYN(lfClipPrecision); 363 COPYN(lfQuality); 364 COPYN(lfPitchAndFamily); 365 COPYS(lfFaceName,LF_FACESIZE); 366 pW->lfFaceName[LF_FACESIZE - 1] = '\0'; 367 368 #undef COPYN 369 #undef COPYS 370 } 371 372 VOID 373 WINAPI 374 LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW) 375 { 376 #define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL ) 377 #define COPYN(f) pA->f = pW->f 378 379 COPYN(lfHeight); 380 COPYN(lfWidth); 381 COPYN(lfEscapement); 382 COPYN(lfOrientation); 383 COPYN(lfWeight); 384 COPYN(lfItalic); 385 COPYN(lfUnderline); 386 COPYN(lfStrikeOut); 387 COPYN(lfCharSet); 388 COPYN(lfOutPrecision); 389 COPYN(lfClipPrecision); 390 COPYN(lfQuality); 391 COPYN(lfPitchAndFamily); 392 COPYS(lfFaceName,LF_FACESIZE); 393 pA->lfFaceName[LF_FACESIZE - 1] = '\0'; 394 395 #undef COPYN 396 #undef COPYS 397 } 398 399 VOID 400 WINAPI 401 EnumLogFontExW2A( LPENUMLOGFONTEXA fontA, CONST ENUMLOGFONTEXW *fontW ) 402 { 403 LogFontW2A( (LPLOGFONTA)fontA, (CONST LOGFONTW *)fontW ); 404 405 WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfFullName, -1, 406 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL ); 407 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0'; 408 WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfStyle, -1, 409 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL ); 410 fontA->elfStyle[LF_FACESIZE-1] = '\0'; 411 WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfScript, -1, 412 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL ); 413 fontA->elfScript[LF_FACESIZE-1] = '\0'; 414 } 415 416 /* 417 * LPK.DLL loader function 418 * 419 * Returns TRUE if a valid parameter was passed and loading was successful, 420 * retruns FALSE otherwise. 421 */ 422 BOOL WINAPI LoadLPK(INT LpkFunctionID) 423 { 424 if(!hLpk) // Check if the DLL is already loaded 425 hLpk = LoadLibraryW(L"lpk.dll"); 426 427 if (hLpk) 428 { 429 switch (LpkFunctionID) 430 { 431 case LPK_INIT: 432 return TRUE; 433 434 case LPK_ETO: 435 if (!LpkExtTextOut) // Check if the function is already loaded 436 LpkExtTextOut = (LPKETO) GetProcAddress(hLpk, "LpkExtTextOut"); 437 438 if (!LpkExtTextOut) 439 { 440 FreeLibrary(hLpk); 441 return FALSE; 442 } 443 444 return TRUE; 445 446 case LPK_GCP: 447 if (!LpkGetCharacterPlacement) // Check if the function is already loaded 448 LpkGetCharacterPlacement = (LPKGCP) GetProcAddress(hLpk, "LpkGetCharacterPlacement"); 449 450 if (!LpkGetCharacterPlacement) 451 { 452 FreeLibrary(hLpk); 453 return FALSE; 454 } 455 456 return TRUE; 457 458 default: 459 FreeLibrary(hLpk); 460 return FALSE; 461 } 462 } 463 464 else 465 return FALSE; 466 } 467