1 /*
2 * PROJECT: ReactOS System Control Panel Applet
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/sysdm/smbios.c
5 * PURPOSE: Retrieve device or motherboard name identifier from DMI/SMBIOS
6 * COPYRIGHT: Copyright 2018-2020 Stanislav Motylkov <x86corez@gmail.com>
7 *
8 */
9
10 #include "precomp.h"
11
12 #include <udmihelp.h>
13
14 typedef struct GENERIC_NAME
15 {
16 PCWSTR pwName;
17 BOOL bCaseSensitive;
18 BOOL bRemove;
19 } GENERIC_NAME;
20
21 typedef struct VENDOR_LONG_NAME
22 {
23 PCWSTR pwLongName;
24 PCWSTR pwShortName;
25 } VENDOR_LONG_NAME;
26
27 typedef struct REDUNDANT_WORD
28 {
29 PCWSTR pwStr;
30 BOOL bReplaceFirstWord;
31 } REDUNDANT_WORD;
32
33 static
34 BOOL
IsPunctuation(_In_ WCHAR chr)35 IsPunctuation(
36 _In_ WCHAR chr)
37 {
38 return (chr <= L' ' || chr == L'.' || chr == L',');
39 }
40
41 static
IsDigitStrA(PCHAR DmiString)42 BOOL IsDigitStrA(PCHAR DmiString)
43 {
44 PCHAR c = DmiString;
45 if (!c)
46 {
47 return FALSE;
48 }
49 while (*c)
50 {
51 if (*c >= '0' && *c <= '9')
52 {
53 c++;
54 }
55 else
56 {
57 return FALSE;
58 }
59 }
60 return TRUE;
61 }
62
63 /*
64 * Trim redundant characters
65 */
66 static
67 VOID
TrimPunctuation(_Inout_ PWSTR pStr)68 TrimPunctuation(
69 _Inout_ PWSTR pStr)
70 {
71 SIZE_T Length;
72 UINT i = 0;
73
74 if (!pStr)
75 return;
76
77 Length = wcslen(pStr);
78 if (Length == 0)
79 return;
80
81 /* Trim leading characters */
82 while (i < Length && IsPunctuation(pStr[i]))
83 {
84 i++;
85 }
86
87 if (i > 0)
88 {
89 Length -= i;
90 memmove(pStr, pStr + i, (Length + 1) * sizeof(WCHAR));
91 }
92
93 /* Trim trailing characters */
94 while (Length && IsPunctuation(pStr[Length-1]))
95 {
96 pStr[Length-1] = L'\0';
97 --Length;
98 }
99 }
100
101 /*
102 * Case insensitive variant of wcsstr
103 */
104 static
wcsistr(const wchar_t * s,const wchar_t * b)105 wchar_t * wcsistr(const wchar_t *s, const wchar_t *b)
106 {
107 wchar_t *x;
108 wchar_t *y;
109 wchar_t *c;
110 x = (wchar_t *)s;
111 while (*x)
112 {
113 if (towlower(*x) == towlower(*b))
114 {
115 y = x;
116 c = (wchar_t *)b;
117 while (*y && *c && towlower(*y) == towlower(*c))
118 {
119 c++;
120 y++;
121 }
122 if (!*c)
123 return x;
124 }
125 x++;
126 }
127 return NULL;
128 }
129
130 static
wcsistr_plus(const wchar_t * s,wchar_t * b)131 wchar_t * wcsistr_plus(const wchar_t *s, wchar_t *b)
132 {
133 wchar_t * result = wcsistr(s, b);
134 UINT len = wcslen(b);
135 // workarounds
136 if (!result && b[len - 1] == L' ' && wcschr(s, L',') != NULL)
137 {
138 b[len - 1] = L',';
139 result = wcsistr(s, b);
140 b[len - 1] = L' ';
141 if (!result)
142 {
143 b[0] = L',';
144 result = wcsistr(s, b);
145 b[0] = L' ';
146 }
147 }
148 if (!result && b[len - 1] == L' ' && wcschr(s, L'(') != NULL)
149 {
150 b[len - 1] = L'(';
151 result = wcsistr(s, b);
152 b[len - 1] = L' ';
153 }
154 if (!result && b[len - 1] == L' ' && wcschr(s, L'_') != NULL)
155 {
156 b[0] = L'_';
157 result = wcsistr(s, b);
158 b[0] = L' ';
159 }
160 if (!result && b[0] == L' ' && b[len - 1] == L' ' && wcschr(s, L')') != NULL)
161 {
162 b[0] = L')';
163 result = wcsistr(s, b);
164 if (!result && wcschr(s, L'.'))
165 {
166 b[len - 1] = L'.';
167 result = wcsistr(s, b);
168 b[len - 1] = L' ';
169 }
170 b[0] = L' ';
171 }
172 return result;
173 }
174
175 /*
176 * Replaces full word with another shorter word
177 */
178 static
wcsrep(_Inout_ PWSTR pwStr,_In_ PCWSTR pwFind,_In_ PCWSTR pwReplace,_In_ BOOL bReplaceFirstWord)179 VOID wcsrep(
180 _Inout_ PWSTR pwStr,
181 _In_ PCWSTR pwFind,
182 _In_ PCWSTR pwReplace,
183 _In_ BOOL bReplaceFirstWord)
184 {
185 PWSTR pwsStr, pwsFind, pwsReplace, pwsBuf = NULL;
186 SIZE_T lenStr;
187 SIZE_T lenFind;
188 SIZE_T lenReplace;
189
190 if (!pwStr || !pwFind || !pwReplace ||
191 wcslen(pwStr) == 0 ||
192 wcslen(pwFind) == 0 ||
193 wcslen(pwFind) < wcslen(pwReplace))
194 {
195 return;
196 }
197 lenStr = wcslen(pwStr) + 2 + 1;
198 lenFind = wcslen(pwFind) + 2 + 1;
199 lenReplace = wcslen(pwReplace) + 2 + 1;
200
201 pwsStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR));
202 if (!pwsStr)
203 {
204 return;
205 }
206 StringCchCopyW(pwsStr, lenStr, L" ");
207 StringCchCatW(pwsStr, lenStr, pwStr);
208 StringCchCatW(pwsStr, lenStr, L" ");
209
210 pwsFind = HeapAlloc(GetProcessHeap(), 0, lenFind * sizeof(WCHAR));
211 if (!pwsFind)
212 {
213 goto freeStr;
214 }
215 StringCchCopyW(pwsFind, lenFind, L" ");
216 StringCchCatW(pwsFind, lenFind, pwFind);
217 StringCchCatW(pwsFind, lenFind, L" ");
218
219 if (!(pwsBuf = wcsistr_plus(pwsStr, pwsFind)))
220 {
221 goto freeFind;
222 }
223 if (!bReplaceFirstWord && pwsBuf - pwsStr < 2)
224 {
225 goto freeFind;
226 }
227
228 pwsReplace = HeapAlloc(GetProcessHeap(), 0, lenReplace * sizeof(WCHAR));
229 if (!pwsReplace)
230 {
231 goto freeFind;
232 }
233 StringCchCopyW(pwsReplace, lenReplace, L" ");
234 StringCchCatW(pwsReplace, lenReplace, pwReplace);
235 StringCchCatW(pwsReplace, lenReplace, L" ");
236
237 do
238 {
239 // replace substring
240 memmove(pwsBuf, pwsReplace, (lenReplace - 1) * sizeof(WCHAR));
241 // shift characters
242 memmove(pwsBuf + lenReplace - (wcslen(pwReplace) > 0 ? 1 : 2), pwsBuf + lenFind - 1, (lenStr - lenFind - (pwsBuf - pwsStr) + 1) * sizeof(WCHAR));
243 }
244 while ((pwsBuf = wcsistr_plus(pwsStr, pwsFind)) != NULL);
245
246 TrimDmiStringW(pwsStr);
247 StringCchCopyW(pwStr, wcslen(pwStr), pwsStr);
248
249 HeapFree(GetProcessHeap(), 0, pwsReplace);
250 freeFind:
251 HeapFree(GetProcessHeap(), 0, pwsFind);
252 freeStr:
253 HeapFree(GetProcessHeap(), 0, pwsStr);
254 }
255
256 static
IsGenericSystemName(PCWSTR ven,PCWSTR dev,BOOL * bRemove)257 BOOL IsGenericSystemName(PCWSTR ven, PCWSTR dev, BOOL * bRemove)
258 {
259 static const GENERIC_NAME Vendors[] =
260 {
261 // some ASUS boards
262 { L"To Be Filled By O.E.M.", FALSE, TRUE },
263 { L"To Be Filled By O.E.M", FALSE, TRUE },
264 { L"System manufacturer", FALSE, TRUE },
265 // some Gigabyte boards
266 { L"Default string", TRUE, TRUE },
267 { L"LTD Delovoy Office", TRUE, FALSE },
268 { L"Motherboard by ZOTAC", TRUE, FALSE },
269 // various boards
270 { L"Type2 - Board Manufacturer", TRUE, TRUE },
271 { L"Type2 - Board Vendor Name1", TRUE, TRUE },
272 { L"BASE_BOARD_MANUFACTURER", TRUE, TRUE },
273 { L"$(DEFAULT_STRING)", TRUE, TRUE },
274 { L"DEPO Computers", TRUE, FALSE },
275 { L"-", TRUE, TRUE },
276 { L"N/A", TRUE, TRUE },
277 { L"OEM", TRUE, TRUE },
278 { L"O.E.M", TRUE, TRUE },
279 { L"empty", TRUE, TRUE },
280 { L"insyde", TRUE, FALSE },
281 { L"Unknow", TRUE, TRUE },
282 { L"Not Applicable", TRUE, TRUE },
283 // distinguish between Oracle and older VirtualBox releases (Sun, etc.)
284 { L"innotek GmbH", TRUE, FALSE },
285 };
286 static const GENERIC_NAME Devices[] =
287 {
288 // some ASUS boards
289 { L"To Be Filled By O.E.M.", FALSE, TRUE },
290 { L"To Be Filled By O.E.M", FALSE, TRUE },
291 { L"All Series", TRUE, TRUE },
292 { L"System Product Name", TRUE, TRUE },
293 { L"System Name", TRUE, TRUE },
294 // some Gigabyte boards
295 { L"Default string", TRUE, TRUE },
296 // some MSI boards
297 { L"Please change product name", TRUE, TRUE },
298 // some Intel boards
299 { L"Computer", TRUE, TRUE },
300 { L"ChiefRiver Platform", TRUE, FALSE },
301 { L"OakTrail Platform", TRUE, FALSE },
302 { L"SharkBay Platform", TRUE, FALSE },
303 { L"HuronRiver Platform", TRUE, FALSE },
304 { L"SandyBridge Platform", TRUE, FALSE },
305 { L"Broadwell Platform", TRUE, FALSE },
306 { L"Kabylake Platform", TRUE, FALSE },
307 { L"Sabine Platform", TRUE, FALSE },
308 // various boards
309 { L"Base Board Product Name", TRUE, TRUE },
310 { L"Base Board Version", TRUE, TRUE },
311 { L"Type2 - Board Product Name1", TRUE, TRUE },
312 { L"Type2 - Board Product Name", TRUE, TRUE },
313 { L"Type2 - Board Version", TRUE, TRUE },
314 { L"MODEL_NAME", TRUE, TRUE },
315 { L"$(DEFAULT_STRING)", TRUE, TRUE },
316 { L"*", TRUE, TRUE },
317 { L"T", TRUE, TRUE },
318 { L"GEG", TRUE, TRUE },
319 { L"N/A", TRUE, TRUE },
320 { L"---", TRUE, TRUE },
321 { L"OEM", TRUE, TRUE },
322 { L"INVA", TRUE, TRUE },
323 { L"O.E.M", TRUE, TRUE },
324 { L"empty", TRUE, TRUE },
325 { L"DNSNB", TRUE, FALSE },
326 { L"12345", TRUE, FALSE },
327 { L"``````", TRUE, TRUE },
328 { L"Uknown", TRUE, TRUE },
329 { L"Desktop", FALSE, TRUE },
330 { L"Invalid", FALSE, TRUE },
331 { L"Reserved", TRUE, TRUE },
332 { L"Not Applicable", TRUE, TRUE },
333 { L"HaierComputer", TRUE, FALSE },
334 { L"DEPO Computers", TRUE, FALSE },
335 { L"InsydeH2O EFI BIOS", TRUE, TRUE },
336 { L"HP All-in-One", TRUE, FALSE },
337 { L"MP Server", TRUE, FALSE },
338 { L"0000000000", TRUE, TRUE },
339 // some Foxconn boards
340 { L"Aquarius Pro, Std, Elt Series", TRUE, FALSE },
341 // some ASUS server boards
342 { L"Aquarius Server", TRUE, FALSE },
343 { L"Aquarius Server G2", TRUE, FALSE },
344 // some Supermicro server boards
345 { L"Super Server", TRUE, FALSE },
346 // some Positivo devices
347 { L"POSITIVO MOBILE", FALSE, FALSE },
348 };
349 BOOL bMatch;
350 UINT i;
351
352 if (bRemove)
353 {
354 *bRemove = FALSE;
355 }
356 for (i = 0; i < _countof(Vendors); i++)
357 {
358 if (!ven)
359 {
360 break;
361 }
362 if (Vendors[i].bCaseSensitive)
363 {
364 bMatch = !wcscmp(ven, Vendors[i].pwName);
365 }
366 else
367 {
368 bMatch = !_wcsicmp(ven, Vendors[i].pwName);
369 }
370 if (bMatch)
371 {
372 if (bRemove)
373 {
374 *bRemove = Vendors[i].bRemove;
375 }
376 return TRUE;
377 }
378 }
379
380 for (i = 0; i < _countof(Devices); i++)
381 {
382 if (!dev)
383 {
384 break;
385 }
386 if (Devices[i].bCaseSensitive)
387 {
388 bMatch = !wcscmp(dev, Devices[i].pwName);
389 }
390 else
391 {
392 bMatch = !_wcsicmp(dev, Devices[i].pwName);
393 }
394 if (bMatch)
395 {
396 if (bRemove)
397 {
398 *bRemove = Devices[i].bRemove;
399 }
400 return TRUE;
401 }
402 }
403 return FALSE;
404 }
405
406 static
AppendSystemFamily(PWSTR pBuf,SIZE_T cchBuf,PCHAR * DmiStrings,PWSTR dev)407 void AppendSystemFamily(PWSTR pBuf, SIZE_T cchBuf, PCHAR * DmiStrings, PWSTR dev)
408 {
409 static const PCSTR KnownFamilies[] =
410 {
411 "Eee PC", // ASUS
412 "ThinkPad", // Lenovo
413 "IdeaPad", // Lenovo
414 "IdeaCentre", // Lenovo
415 };
416 static const PCWSTR Aliases[] =
417 {
418 NULL,
419 NULL,
420 NULL,
421 L"IdeaCenter",
422 };
423 UINT i;
424 WCHAR wideStr[128];
425
426 for (i = 0; i < _countof(KnownFamilies); i++)
427 {
428 StringCchPrintfW(wideStr, _countof(wideStr), L"%S", KnownFamilies[i]);
429
430 if (wcsistr(dev, wideStr) == NULL &&
431 (!Aliases[i] || wcsistr(dev, Aliases[i]) == NULL) &&
432 DmiStrings[SYS_FAMILY] != NULL &&
433 !_stricmp(DmiStrings[SYS_FAMILY], KnownFamilies[i]))
434 {
435 if (wcslen(pBuf) > 0 && wcslen(dev) > 0)
436 {
437 StringCchCatW(pBuf, cchBuf, L" ");
438 }
439 StringCchCatW(pBuf, cchBuf, wideStr);
440 }
441 }
442 }
443
444 static
TrimNonPrintable(PCHAR DmiString)445 BOOL TrimNonPrintable(PCHAR DmiString)
446 {
447 PCHAR c = DmiString;
448 if (!c)
449 {
450 return FALSE;
451 }
452 while (*c)
453 {
454 if (*c >= 0x20 && *c <= 0x7e)
455 {
456 c++;
457 }
458 else
459 {
460 *c = 0;
461 return TRUE;
462 }
463 }
464 return FALSE;
465 }
466
467 /* TrimNonPrintable function wrapper. It does special preprocessing
468 * so the function returns FALSE in some corner cases, making the parser
469 * use system strings anyway (instead of board strings). */
470 static
TrimNonPrintableProd(PCHAR DmiString)471 BOOL TrimNonPrintableProd(PCHAR DmiString)
472 {
473 PCHAR c;
474
475 if (!DmiString)
476 {
477 return FALSE;
478 }
479
480 /* Special handling for HP with broken revision */
481 c = strstr(DmiString, "(\xFF\xFF");
482 if (c > DmiString)
483 {
484 *c = 0;
485 }
486
487 return TrimNonPrintable(DmiString);
488 }
489
GetSystemName(PWSTR pBuf,SIZE_T cchBuf)490 BOOL GetSystemName(PWSTR pBuf, SIZE_T cchBuf)
491 {
492 static const VENDOR_LONG_NAME LongNames[] =
493 {
494 { L"ASUSTeK", L"ASUS" },
495 { L"First International Computer", L"FIC" },
496 { L"Hewlett-Packard", L"HP" },
497 { L"MICRO-STAR", L"MSI" },
498 { L"SGI.COM", L"SGI" },
499 { L"Silicon Graphics International", L"SGI" },
500 { L"Intel(R) Client Systems", L"Intel" },
501 { L"InformationComputerSystems", L"ICS" },
502 { L"Bernecker + Rainer Industrie-Elektronik", L"Bernecker & Rainer" },
503 { L"CHUWI INNOVATION AND TECHNOLOGY", L"CHUWI" },
504 { L"CHUWI INNOVATION LIMITED", L"CHUWI" },
505 { L"CHUWI INNOVATION LIMITED", L"CHUWI" },
506 { L"http://www.abit.com.tw/", L"ABIT" },
507 { L"http:\\\\www.abit.com.tw", L"ABIT" },
508 { L"www.abit.com.tw", L"ABIT" },
509 { L"CASPER BILGISAYAR SISTEMLERI A.S", L"Casper" },
510 { L"Colorful Technology And Development", L"Colorful" },
511 { L"Colorful Yu Gong Technology And Development", L"Colorful Yu Gong" },
512 { L"HaierComputer", L"Haier" },
513 { L"Haier Information Technology (Shen Zhen)", L"Haier" },
514 { L"HASEECOMPUTERS", L"Hasee" },
515 { L"HELIOS BUSINESS COMPUTER", L"HELIOS" },
516 { L"Shanghai Zongzhi InfoTech", L"Zongzhi" },
517 { L"TSING HUA TONGFANG CO.,LTD", L"TSINGHUA TONGFANG" },
518 { L"Yeston Digital Technology Co.,LTD", L"Yeston" },
519 };
520 static const REDUNDANT_WORD RedundantWords[] =
521 {
522 { L"Corporation", FALSE },
523 { L"Communication", FALSE },
524 { L"Computer", FALSE },
525 { L"Computers", FALSE },
526 { L"Group", FALSE },
527 { L"Cloud", FALSE },
528 { L"Center", FALSE },
529 { L"Systems", FALSE },
530 { L"Microsystems", FALSE },
531 { L"Infosystems", FALSE },
532 { L"Digital", FALSE },
533 { L"Electronics", FALSE },
534 { L"Electric", FALSE },
535 { L"Elektronik", FALSE },
536 { L"Software", FALSE },
537 { L"Foundation", FALSE },
538 { L"International", FALSE },
539 { L"Interantonal", FALSE }, // on purpose (some MSI boards)
540 { L"INTERANTIONAL", FALSE }, // on purpose (some MSI boards)
541 { L"Industrial", FALSE },
542 { L"Industrie", FALSE },
543 { L"Information", FALSE },
544 { L"Informatica", FALSE },
545 { L"Produkte", FALSE },
546 { L"Technology", FALSE },
547 { L"Tecohnology", FALSE }, // on purpose (some Gigabyte boards)
548 { L"Technologies", FALSE },
549 { L"Tecnologia", FALSE },
550 { L"Limited", FALSE },
551 { L"Int", FALSE },
552 { L"Inc", FALSE },
553 { L"Co", FALSE },
554 { L"Corp", FALSE },
555 { L"Crop", FALSE },
556 { L"LLC", FALSE },
557 { L"Ltd", FALSE },
558 { L"LTDA", FALSE },
559 { L"GmbH", FALSE },
560 { L"S.p.A", FALSE },
561 { L"A.S.", FALSE },
562 { L"S.A", FALSE },
563 { L"S.A.S", FALSE },
564 { L"S/A", FALSE },
565 { L"SA", FALSE },
566 { L"SAS", FALSE },
567 { L"BV", FALSE },
568 { L"AG", FALSE },
569 { L"OOO", TRUE },
570 { L"CJSC", FALSE },
571 { L"INT'L", FALSE },
572 { L"INTL", FALSE },
573 { L"plc", FALSE },
574 };
575 PVOID SMBiosBuf;
576 PCHAR DmiStrings[ID_STRINGS_MAX] = { 0 };
577 WCHAR ven[512], dev[512];
578 CHAR tmpstr[512];
579 BOOL bTrimProduct, bTrimFamily, bGenericName, bRemove;
580 UINT i;
581 PWCHAR j;
582
583 SMBiosBuf = LoadSMBiosData(DmiStrings);
584 if (!SMBiosBuf)
585 {
586 return FALSE;
587 }
588
589 TrimNonPrintable(DmiStrings[SYS_VENDOR]);
590 bTrimProduct = TrimNonPrintableProd(DmiStrings[SYS_PRODUCT]);
591 TrimNonPrintable(DmiStrings[SYS_VERSION]);
592 bTrimFamily = TrimNonPrintable(DmiStrings[SYS_FAMILY]);
593 TrimNonPrintable(DmiStrings[BOARD_VENDOR]);
594 TrimNonPrintable(DmiStrings[BOARD_NAME]);
595 TrimNonPrintable(DmiStrings[BOARD_VERSION]);
596
597 if (bTrimProduct)
598 {
599 if (DmiStrings[SYS_FAMILY] && !bTrimFamily)
600 {
601 DmiStrings[SYS_PRODUCT] = DmiStrings[SYS_FAMILY];
602 bTrimProduct = FALSE;
603 }
604 }
605
606 GetSMBiosStringW(DmiStrings[SYS_VENDOR], ven, _countof(ven), TRUE);
607 GetSMBiosStringW(DmiStrings[SYS_PRODUCT], dev, _countof(dev), TRUE);
608 bGenericName = IsGenericSystemName(ven, dev, NULL) || bTrimProduct;
609
610 if (wcslen(dev) == 0 ||
611 !wcscmp(dev, ven) ||
612 bGenericName)
613 {
614 BOOL bGenericVen = FALSE, bRemoveVen = FALSE, bGenericDev = (wcslen(dev) == 0 || !wcscmp(dev, ven) || bTrimProduct);
615
616 if (bGenericName && IsGenericSystemName(ven, NULL, &bRemove))
617 {
618 if (bRemove)
619 {
620 *ven = 0;
621 }
622 bGenericVen = TRUE;
623 bRemoveVen = bRemove;
624 }
625 if (bGenericName && IsGenericSystemName(NULL, dev, &bRemove))
626 {
627 if (bRemove)
628 {
629 *dev = 0;
630 }
631 bGenericDev = TRUE;
632 }
633 // system strings are unusable, use board strings
634 if (DmiStrings[BOARD_VENDOR] != NULL || !bGenericName)
635 {
636 if ((DmiStrings[BOARD_VENDOR] &&
637 strlen(DmiStrings[BOARD_VENDOR]) >= 2 &&
638 strstr(DmiStrings[BOARD_VENDOR], " ") != DmiStrings[BOARD_VENDOR]) ||
639 bGenericVen)
640 {
641 GetSMBiosStringW(DmiStrings[BOARD_VENDOR], ven, _countof(ven), TRUE);
642 }
643 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE);
644
645 if (IsGenericSystemName(ven, NULL, &bRemove) && bRemove)
646 {
647 *ven = 0;
648
649 if (bGenericVen && !bRemoveVen)
650 {
651 GetSMBiosStringW(DmiStrings[SYS_VENDOR], ven, _countof(ven), TRUE);
652 }
653 }
654 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove)
655 {
656 *dev = 0;
657
658 if (!bGenericDev)
659 {
660 GetSMBiosStringW(DmiStrings[SYS_PRODUCT], dev, _countof(dev), TRUE);
661 }
662 }
663 if (wcslen(dev) == 0 &&
664 DmiStrings[SYS_VERSION] != NULL)
665 {
666 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE);
667
668 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove)
669 {
670 *dev = 0;
671 }
672 }
673 if (wcslen(dev) == 0 &&
674 DmiStrings[BOARD_VERSION] != NULL)
675 {
676 GetSMBiosStringW(DmiStrings[BOARD_VERSION], dev, _countof(dev), TRUE);
677
678 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove)
679 {
680 *dev = 0;
681 }
682 }
683 }
684 else if (DmiStrings[BOARD_NAME] != NULL)
685 {
686 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE);
687
688 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove)
689 {
690 *dev = 0;
691 }
692 }
693
694 if (wcslen(ven) == 0 && wcslen(dev) == 0)
695 {
696 // board strings are empty, use BIOS vendor string
697 GetSMBiosStringW(DmiStrings[BIOS_VENDOR], ven, _countof(ven), TRUE);
698 }
699 }
700 else
701 {
702 if (wcslen(ven) < 2)
703 {
704 GetSMBiosStringW(DmiStrings[BOARD_VENDOR], ven, _countof(ven), TRUE);
705
706 if (IsGenericSystemName(ven, NULL, &bRemove) && bRemove)
707 {
708 *ven = 0;
709 }
710 }
711 }
712
713 // workaround for LORD ELECTRONICS
714 if (((j = wcsstr(ven, L" ")) != NULL) && (j - ven > 2))
715 {
716 i = j - ven;
717 if (!wcsncmp(ven + wcslen(ven) - i, ven, i))
718 {
719 ven[wcslen(ven) - i] = L'\0';
720 }
721 }
722
723 // make vendor strings shorter
724 for (i = 0; i < _countof(LongNames); i++)
725 {
726 if (wcsstr(dev, LongNames[i].pwLongName) == dev)
727 {
728 // swap ven and dev
729 StringCchCopyW(pBuf, cchBuf, ven);
730 StringCchCopyW(ven, _countof(ven), dev);
731 StringCchCopyW(dev, _countof(dev), pBuf);
732 }
733 wcsrep(ven, LongNames[i].pwLongName, LongNames[i].pwShortName, TRUE);
734 }
735
736 // remove redundant words
737 for (i = 0; i < _countof(RedundantWords); i++)
738 {
739 wcsrep(ven, RedundantWords[i].pwStr, L"", RedundantWords[i].bReplaceFirstWord);
740 }
741 for (i = 0; i < _countof(RedundantWords); i++)
742 {
743 StringCchCopyW(pBuf, cchBuf, RedundantWords[i].pwStr);
744 StringCchCatW(pBuf, cchBuf, L".");
745 wcsrep(ven, pBuf, L"", RedundantWords[i].bReplaceFirstWord);
746 }
747
748 // workaround for LENOVO notebooks
749 if (!_wcsicmp(ven, L"LENOVO"))
750 {
751 StringCchCopyW(ven, _countof(ven), L"Lenovo");
752
753 if (DmiStrings[SYS_VERSION] != NULL)
754 {
755 if (!strncmp(DmiStrings[SYS_VERSION], "ThinkPad ", 11))
756 {
757 DmiStrings[SYS_VERSION][8] = L'\0';
758 }
759 if (wcslen(dev) > 0 &&
760 (!strcmp(DmiStrings[SYS_VERSION], "IdeaCentre") ||
761 !strcmp(DmiStrings[SYS_VERSION], "ThinkPad")))
762 {
763 DmiStrings[SYS_FAMILY] = DmiStrings[SYS_VERSION];
764 DmiStrings[SYS_VERSION] = NULL;
765 }
766 else
767 {
768 StringCchCopyA(tmpstr, _countof(tmpstr), DmiStrings[SYS_VERSION]);
769 _strupr(tmpstr);
770 }
771 }
772
773 if (DmiStrings[SYS_VERSION] != NULL &&
774 strcmp(tmpstr, " ") &&
775 strcmp(tmpstr, "LENOVO") &&
776 strstr(tmpstr, "LENOVO ") == NULL &&
777 strstr(tmpstr, "LENOVO PRODUCT") == NULL &&
778 strstr(tmpstr, "LENOVOPRODUCT") == NULL &&
779 strstr(tmpstr, "INVALID") == NULL &&
780 strncmp(tmpstr, " ", 3) &&
781 (strlen(tmpstr) >= 3 || !IsDigitStrA(tmpstr)) &&
782 strstr(DmiStrings[SYS_VERSION], "Rev ") == NULL &&
783 strstr(DmiStrings[SYS_VERSION], "1.") == NULL &&
784 wcsistr(dev, L"System ") == NULL && // includes System x and ThinkSystem
785 wcsistr(dev, L"IdeaPad ") == NULL &&
786 wcsistr(dev, L"ThinkServer ") == NULL)
787 {
788 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE);
789 }
790
791 if (wcsstr(dev, L"Lenovo-") == dev)
792 {
793 // replace "-" with space
794 dev[6] = L' ';
795 }
796
797 if (!wcscmp(dev, L"Lenovo"))
798 {
799 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE);
800 }
801 }
802 if (!wcscmp(ven, L"IBM") &&
803 DmiStrings[SYS_VERSION] != NULL &&
804 (strstr(DmiStrings[SYS_VERSION], "ThinkPad ") != NULL ||
805 strstr(DmiStrings[SYS_VERSION], "ThinkCentre ") != NULL))
806 {
807 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE);
808 }
809
810 // workaround for DEXP
811 if (!wcscmp(ven, L"DEXP"))
812 {
813 if (DmiStrings[SYS_PRODUCT] != NULL &&
814 DmiStrings[SYS_VERSION] != NULL &&
815 (!_stricmp(DmiStrings[SYS_PRODUCT], "Tablet PC") ||
816 !_stricmp(DmiStrings[SYS_PRODUCT], "Notebook") ||
817 !_stricmp(DmiStrings[SYS_PRODUCT], "Decktop")))
818 {
819 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE);
820 }
821 }
822
823 // workaround for Razer Blade
824 if (!wcscmp(ven, L"Razer") && !wcscmp(dev, L"Blade"))
825 {
826 if (DmiStrings[SYS_VERSION] != NULL)
827 {
828 StringCchCopyW(ven, _countof(ven), L"Razer Blade");
829 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE);
830 }
831 }
832
833 // workaround for MSI motherboards
834 if (!wcscmp(ven, L"MSI") &&
835 wcsstr(dev, L"MS-") != NULL &&
836 DmiStrings[BOARD_NAME] != NULL &&
837 strstr(DmiStrings[BOARD_NAME], "(MS-") != NULL)
838 {
839 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE);
840 }
841 if (wcslen(ven) == 0 &&
842 wcsstr(dev, L"MS-") == dev)
843 {
844 StringCchCopyW(ven, _countof(ven), L"MSI");
845 }
846
847 // trim redundant characters
848 TrimPunctuation(ven);
849 TrimPunctuation(dev);
850
851 if (wcsistr(dev, ven) == dev ||
852 (!wcscmp(ven, L"ASUS") && wcsstr(dev, L"ASUS") != NULL) ||
853 (!wcscmp(ven, L"HP") && wcsstr(dev, L" by HP") != NULL) ||
854 (!wcscmp(ven, L"INTEL") && wcsstr(dev, L" INTEL") != NULL))
855 {
856 // device string contains vendor string, use second only
857 StringCchCopyW(pBuf, cchBuf, dev);
858 }
859 else
860 {
861 if (wcslen(ven) > 0 && wcslen(dev) > 0 && (j = wcschr(dev, L' ')))
862 {
863 // check if vendor string ends with first word of device string
864 i = j - dev;
865 if (wcslen(ven) > i && !_wcsnicmp(ven + wcslen(ven) - i, dev, i))
866 {
867 ven[wcslen(ven) - i] = L'\0';
868 TrimPunctuation(ven);
869 }
870 }
871 StringCchCopyW(pBuf, cchBuf, ven);
872 AppendSystemFamily(pBuf, cchBuf, DmiStrings, dev);
873 if (wcslen(pBuf) > 0 && wcslen(dev) > 0)
874 {
875 StringCchCatW(pBuf, cchBuf, L" ");
876 }
877 StringCchCatW(pBuf, cchBuf, dev);
878 }
879
880 FreeSMBiosData(SMBiosBuf);
881
882 return (wcslen(pBuf) > 0);
883 }
884