LibreOffice Module vcl (master)  1
driverblocklist.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <driverblocklist.hxx>
11 
12 #include <algorithm>
13 #include <string_view>
14 
15 #include <sal/log.hxx>
16 
17 #ifdef _WIN32
18 #if !defined WIN32_LEAN_AND_MEAN
19 #define WIN32_LEAN_AND_MEAN
20 #endif
21 #include <windows.h>
22 #endif
23 
24 namespace DriverBlocklist
25 {
26 static OperatingSystem getOperatingSystem(std::string_view rString)
27 {
28  if (rString == "all")
29  return DRIVER_OS_ALL;
30  else if (rString == "7")
31  return DRIVER_OS_WINDOWS_7;
32  else if (rString == "8")
33  return DRIVER_OS_WINDOWS_8;
34  else if (rString == "8_1")
35  return DRIVER_OS_WINDOWS_8_1;
36  else if (rString == "10")
37  return DRIVER_OS_WINDOWS_10;
38  else if (rString == "windows")
39  return DRIVER_OS_WINDOWS_ALL;
40  else if (rString == "linux")
41  return DRIVER_OS_LINUX;
42  else if (rString == "osx_10_5")
43  return DRIVER_OS_OSX_10_5;
44  else if (rString == "osx_10_6")
45  return DRIVER_OS_OSX_10_6;
46  else if (rString == "osx_10_7")
47  return DRIVER_OS_OSX_10_7;
48  else if (rString == "osx_10_8")
49  return DRIVER_OS_OSX_10_8;
50  else if (rString == "osx")
51  return DRIVER_OS_OSX_ALL;
52  else if (rString == "android")
53  return DRIVER_OS_ANDROID;
54  return DRIVER_OS_UNKNOWN;
55 }
56 
57 static VersionComparisonOp getComparison(std::string_view rString)
58 {
59  if (rString == "less")
60  {
61  return DRIVER_LESS_THAN;
62  }
63  else if (rString == "less_equal")
64  {
66  }
67  else if (rString == "greater")
68  {
69  return DRIVER_GREATER_THAN;
70  }
71  else if (rString == "greater_equal")
72  {
74  }
75  else if (rString == "equal")
76  {
77  return DRIVER_EQUAL;
78  }
79  else if (rString == "not_equal")
80  {
81  return DRIVER_NOT_EQUAL;
82  }
83  else if (rString == "between_exclusive")
84  {
86  }
87  else if (rString == "between_inclusive")
88  {
90  }
91  else if (rString == "between_inclusive_start")
92  {
94  }
95 
96  throw InvalidFileException();
97 }
98 
99 static OUString GetVendorId(std::string_view rString)
100 {
101  if (rString == "all")
102  {
103  return "";
104  }
105  else if (rString == "intel")
106  {
107  return "0x8086";
108  }
109  else if (rString == "nvidia")
110  {
111  return "0x10de";
112  }
113  else if (rString == "amd")
114  {
115  return "0x1002";
116  }
117  else if (rString == "microsoft")
118  {
119  return "0x1414";
120  }
121  else
122  {
123  // Allow having simply the hex number as such there, too.
124  return OStringToOUString(rString, RTL_TEXTENCODING_UTF8);
125  }
126 }
127 
129 {
130  assert(id >= 0 && id < DeviceVendorMax);
131 
132  switch (id)
133  {
134  case VendorAll:
135  return "";
136  case VendorIntel:
137  return "0x8086";
138  case VendorNVIDIA:
139  return "0x10de";
140  case VendorAMD:
141  return "0x1002";
142  case VendorMicrosoft:
143  return "0x1414";
144  }
145  abort();
146 }
147 
149 {
150  switch (id)
151  {
152  case 0x8086:
153  return VendorIntel;
154  case 0x10de:
155  return VendorNVIDIA;
156  case 0x1002:
157  return VendorAMD;
158  case 0x1414:
159  return VendorMicrosoft;
160  default:
161  return VendorAll;
162  }
163 }
164 
165 std::string_view GetVendorNameFromId(uint32_t id)
166 {
167  switch (id)
168  {
169  case 0x8086:
170  return "Intel";
171  case 0x10de:
172  return "Nvidia";
173  case 0x1002:
174  return "AMD";
175  case 0x1414:
176  return "Microsoft";
177  default:
178  return "?";
179  }
180 }
181 
182 Parser::Parser(const OUString& rURL, std::vector<DriverInfo>& rDriverList, VersionType versionType)
183  : meBlockType(BlockType::UNKNOWN)
184  , mrDriverList(rDriverList)
185  , maURL(rURL)
186  , mVersionType(versionType)
187 {
188 }
189 
191 {
192  try
193  {
194  xmlreader::XmlReader aReader(maURL);
195  handleContent(aReader);
196  }
197  catch (...)
198  {
199  mrDriverList.clear();
200  return false;
201  }
202  return true;
203 }
204 
205 // This allows us to pad driver version 'substrings' with 0s, this
206 // effectively allows us to treat the version numbers as 'decimals'. This is
207 // a little strange but this method seems to do the right thing for all
208 // different vendor's driver strings. i.e. .98 will become 9800, which is
209 // larger than .978 which would become 9780.
210 static void PadDriverDecimal(char* aString)
211 {
212  for (int i = 0; i < 4; i++)
213  {
214  if (!aString[i])
215  {
216  for (int c = i; c < 4; c++)
217  {
218  aString[c] = '0';
219  }
220  break;
221  }
222  }
223  aString[4] = 0;
224 }
225 
226 // All destination string storage needs to have at least 5 bytes available.
227 static bool SplitDriverVersion(const char* aSource, char* aAStr, char* aBStr, char* aCStr,
228  char* aDStr, VersionType versionType)
229 {
230  // sscanf doesn't do what we want here to we parse this manually.
231  int len = strlen(aSource);
232  char* dest[4] = { aAStr, aBStr, aCStr, aDStr };
233  unsigned destIdx = 0;
234  unsigned destPos = 0;
235 
236  for (int i = 0; i < len; i++)
237  {
238  if (destIdx >= SAL_N_ELEMENTS(dest))
239  {
240  // Invalid format found. Ensure we don't access dest beyond bounds.
241  return false;
242  }
243 
244  if (aSource[i] == '.')
245  {
246  dest[destIdx++][destPos] = 0;
247  destPos = 0;
248  continue;
249  }
250 
251  if (destPos > 3)
252  {
253  // Ignore more than 4 chars. Ensure we never access dest[destIdx]
254  // beyond its bounds.
255  continue;
256  }
257 
258  dest[destIdx][destPos++] = aSource[i];
259  }
260 
261  // Add last terminator.
262  dest[destIdx][destPos] = 0;
263 
264  // Vulkan version numbers have only 3 fields.
265  if (versionType == VersionType::Vulkan && destIdx == SAL_N_ELEMENTS(dest) - 2)
266  dest[++destIdx][0] = '\0';
267  if (destIdx != SAL_N_ELEMENTS(dest) - 1)
268  {
269  return false;
270  }
271  return true;
272 }
273 
274 static bool ParseDriverVersion(std::u16string_view aVersion, uint64_t& rNumericVersion,
275  VersionType versionType)
276 {
277  rNumericVersion = 0;
278 
279  int a, b, c, d;
280  char aStr[8], bStr[8], cStr[8], dStr[8];
281  /* honestly, why do I even bother */
282  OString aOVersion = OUStringToOString(aVersion, RTL_TEXTENCODING_UTF8);
283  if (!SplitDriverVersion(aOVersion.getStr(), aStr, bStr, cStr, dStr, versionType))
284  return false;
285 
286  if (versionType == VersionType::OpenGL)
287  {
288  PadDriverDecimal(bStr);
289  PadDriverDecimal(cStr);
290  PadDriverDecimal(dStr);
291  }
292 
293  a = atoi(aStr);
294  b = atoi(bStr);
295  c = atoi(cStr);
296  d = atoi(dStr);
297 
298  if (versionType == VersionType::Vulkan)
299  assert(d == 0);
300 
301  if (a < 0 || a > 0xffff)
302  return false;
303  if (b < 0 || b > 0xffff)
304  return false;
305  if (c < 0 || c > 0xffff)
306  return false;
307  if (d < 0 || d > 0xffff)
308  return false;
309 
310  rNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
311  return true;
312 }
313 
314 uint64_t Parser::getVersion(std::string_view rString)
315 {
316  OUString aString = OStringToOUString(rString, RTL_TEXTENCODING_UTF8);
317  uint64_t nVersion;
318  bool bResult = ParseDriverVersion(aString, nVersion, mVersionType);
319 
320  if (!bResult)
321  {
322  throw InvalidFileException();
323  }
324 
325  return nVersion;
326 }
327 
329 {
330  int nLevel = 1;
331  bool bInMsg = false;
332 
333  while (true)
334  {
336  int nsId;
337 
339  = rReader.nextItem(xmlreader::XmlReader::Text::Normalized, &name, &nsId);
340 
342  {
343  ++nLevel;
344  if (nLevel > 2)
345  throw InvalidFileException();
346 
347  if (name == "msg")
348  {
349  bInMsg = true;
350  }
351  else if (name == "device")
352  {
353  int nsIdDeveice;
354  while (rReader.nextAttribute(&nsIdDeveice, &name))
355  {
356  if (name == "id")
357  {
358  name = rReader.getAttributeValue(false);
359  OString aDeviceId(name.begin, name.length);
360  rDriver.maDevices.push_back(
361  OStringToOUString(aDeviceId, RTL_TEXTENCODING_UTF8));
362  }
363  }
364  }
365  else
366  throw InvalidFileException();
367  }
368  else if (res == xmlreader::XmlReader::Result::End)
369  {
370  --nLevel;
371  bInMsg = false;
372  if (!nLevel)
373  break;
374  }
375  else if (res == xmlreader::XmlReader::Result::Text)
376  {
377  if (bInMsg)
378  {
379  OString sMsg(name.begin, name.length);
380  rDriver.maMsg = OStringToOUString(sMsg, RTL_TEXTENCODING_UTF8);
381  }
382  }
383  }
384 }
385 
387 {
389  {
390  rDriver.mbAllowlisted = true;
391  }
392  else if (meBlockType == BlockType::DENYLIST)
393  {
394  rDriver.mbAllowlisted = false;
395  }
396  else if (meBlockType == BlockType::UNKNOWN)
397  {
398  throw InvalidFileException();
399  }
400 
402  int nsId;
403 
404  while (rReader.nextAttribute(&nsId, &name))
405  {
406  if (name == "os")
407  {
408  name = rReader.getAttributeValue(false);
409  OString sOS(name.begin, name.length);
410  rDriver.meOperatingSystem = getOperatingSystem(sOS);
411  }
412  else if (name == "vendor")
413  {
414  name = rReader.getAttributeValue(false);
415  OString sVendor(name.begin, name.length);
416  rDriver.maAdapterVendor = GetVendorId(sVendor);
417  }
418  else if (name == "compare")
419  {
420  name = rReader.getAttributeValue(false);
421  OString sCompare(name.begin, name.length);
422  rDriver.meComparisonOp = getComparison(sCompare);
423  }
424  else if (name == "version")
425  {
426  name = rReader.getAttributeValue(false);
427  OString sVersion(name.begin, name.length);
428  rDriver.mnDriverVersion = getVersion(sVersion);
429  }
430  else if (name == "minVersion")
431  {
432  name = rReader.getAttributeValue(false);
433  OString sMinVersion(name.begin, name.length);
434  rDriver.mnDriverVersion = getVersion(sMinVersion);
435  }
436  else if (name == "maxVersion")
437  {
438  name = rReader.getAttributeValue(false);
439  OString sMaxVersion(name.begin, name.length);
440  rDriver.mnDriverVersionMax = getVersion(sMaxVersion);
441  }
442  else
443  {
444  OString aAttrName(name.begin, name.length);
445  SAL_WARN("vcl.driver", "unsupported attribute: " << aAttrName);
446  }
447  }
448 
449  handleDevices(rDriver, rReader);
450 }
451 
453 {
455  int nsId;
456 
457  while (true)
458  {
460  = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId);
461 
463  {
464  if (name == "entry")
465  {
466  DriverInfo aDriver;
467  handleEntry(aDriver, rReader);
468  mrDriverList.push_back(aDriver);
469  }
470  else if (name == "entryRange")
471  {
472  DriverInfo aDriver;
473  handleEntry(aDriver, rReader);
474  mrDriverList.push_back(aDriver);
475  }
476  else
477  {
478  throw InvalidFileException();
479  }
480  }
481  else if (res == xmlreader::XmlReader::Result::End)
482  {
483  break;
484  }
485  }
486 }
487 
489 {
490  while (true)
491  {
493  int nsId;
494 
496  = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId);
497 
499  {
500  if (name == "allowlist")
501  {
503  handleList(rReader);
504  }
505  else if (name == "denylist")
506  {
508  handleList(rReader);
509  }
510  else if (name == "root")
511  {
512  }
513  else
514  {
515  throw InvalidFileException();
516  }
517  }
518  else if (res == xmlreader::XmlReader::Result::End)
519  {
520  if (name == "allowlist" || name == "denylist")
521  {
523  }
524  }
525  else if (res == xmlreader::XmlReader::Result::Done)
526  {
527  break;
528  }
529  }
530 }
531 
533 {
534 #ifdef _WIN32
535  // OS version in 16.16 major/minor form
536  // based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
537  switch (DriverBlocklist::GetWindowsVersion())
538  {
539  case 0x00060001:
540  return DRIVER_OS_WINDOWS_7;
541  case 0x00060002:
542  return DRIVER_OS_WINDOWS_8;
543  case 0x00060003:
544  return DRIVER_OS_WINDOWS_8_1;
545  case 0x000A0000: // Major 10 Minor 0
546  return DRIVER_OS_WINDOWS_10;
547  default:
548  return DRIVER_OS_UNKNOWN;
549  }
550 #elif defined LINUX
551  return DRIVER_OS_LINUX;
552 #else
553  return DRIVER_OS_UNKNOWN;
554 #endif
555 }
556 
557 namespace
558 {
559 struct compareIgnoreAsciiCase
560 {
561  explicit compareIgnoreAsciiCase(const OUString& rString)
562  : maString(rString)
563  {
564  }
565 
566  bool operator()(std::u16string_view rCompare)
567  {
568  return maString.equalsIgnoreAsciiCase(rCompare);
569  }
570 
571 private:
572  OUString maString;
573 };
574 }
575 
576 const uint64_t allDriverVersions = ~(uint64_t(0));
577 
579  : meOperatingSystem(DRIVER_OS_UNKNOWN)
580  , maAdapterVendor(GetVendorId(VendorAll))
581  , mbAllowlisted(false)
582  , meComparisonOp(DRIVER_COMPARISON_IGNORED)
583  , mnDriverVersion(0)
584  , mnDriverVersionMax(0)
585 {
586 }
587 
589  uint64_t driverVersion, bool bAllowlisted,
590  const char* suggestedVersion /* = nullptr */)
591  : meOperatingSystem(os)
592  , maAdapterVendor(vendor)
593  , mbAllowlisted(bAllowlisted)
594  , meComparisonOp(op)
595  , mnDriverVersion(driverVersion)
596  , mnDriverVersionMax(0)
597 {
598  if (suggestedVersion)
600  = OStringToOUString(std::string_view(suggestedVersion), RTL_TEXTENCODING_UTF8);
601 }
602 
603 bool FindBlocklistedDeviceInList(std::vector<DriverInfo>& aDeviceInfos, VersionType versionType,
604  std::u16string_view sDriverVersion,
605  std::u16string_view sAdapterVendorID,
606  OUString const& sAdapterDeviceID, OperatingSystem system,
607  const OUString& blocklistURL)
608 {
609  uint64_t driverVersion;
610  ParseDriverVersion(sDriverVersion, driverVersion, versionType);
611 
612  bool match = false;
613  for (std::vector<DriverInfo>::size_type i = 0; i < aDeviceInfos.size(); i++)
614  {
615  bool osMatch = false;
616  if (aDeviceInfos[i].meOperatingSystem == DRIVER_OS_ALL)
617  osMatch = true;
618  else if (aDeviceInfos[i].meOperatingSystem == system)
619  osMatch = true;
620  else if (aDeviceInfos[i].meOperatingSystem == DRIVER_OS_WINDOWS_ALL
621  && system >= DRIVER_OS_WINDOWS_FIRST && system <= DRIVER_OS_WINDOWS_LAST)
622  osMatch = true;
623  else if (aDeviceInfos[i].meOperatingSystem == DRIVER_OS_OSX_ALL
624  && system >= DRIVER_OS_OSX_FIRST && system <= DRIVER_OS_OSX_LAST)
625  osMatch = true;
626  if (!osMatch)
627  {
628  continue;
629  }
630 
631  if (!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(GetVendorId(VendorAll))
632  && !aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(sAdapterVendorID))
633  {
634  continue;
635  }
636 
637  if (std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(),
638  compareIgnoreAsciiCase("all"))
639  && std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(),
640  compareIgnoreAsciiCase(sAdapterDeviceID)))
641  {
642  continue;
643  }
644 
645  switch (aDeviceInfos[i].meComparisonOp)
646  {
647  case DRIVER_LESS_THAN:
648  match = driverVersion < aDeviceInfos[i].mnDriverVersion;
649  break;
651  match = driverVersion <= aDeviceInfos[i].mnDriverVersion;
652  break;
653  case DRIVER_GREATER_THAN:
654  match = driverVersion > aDeviceInfos[i].mnDriverVersion;
655  break;
657  match = driverVersion >= aDeviceInfos[i].mnDriverVersion;
658  break;
659  case DRIVER_EQUAL:
660  match = driverVersion == aDeviceInfos[i].mnDriverVersion;
661  break;
662  case DRIVER_NOT_EQUAL:
663  match = driverVersion != aDeviceInfos[i].mnDriverVersion;
664  break;
666  match = driverVersion > aDeviceInfos[i].mnDriverVersion
667  && driverVersion < aDeviceInfos[i].mnDriverVersionMax;
668  break;
670  match = driverVersion >= aDeviceInfos[i].mnDriverVersion
671  && driverVersion <= aDeviceInfos[i].mnDriverVersionMax;
672  break;
674  match = driverVersion >= aDeviceInfos[i].mnDriverVersion
675  && driverVersion < aDeviceInfos[i].mnDriverVersionMax;
676  break;
678  // We don't have a comparison op, so we match everything.
679  match = true;
680  break;
681  default:
682  SAL_WARN("vcl.driver", "Bogus op in " << blocklistURL);
683  break;
684  }
685 
686  if (match || aDeviceInfos[i].mnDriverVersion == allDriverVersions)
687  {
688  // white listed drivers
689  if (aDeviceInfos[i].mbAllowlisted)
690  {
691  SAL_INFO("vcl.driver", "allowlisted driver");
692  return false;
693  }
694 
695  match = true;
696  if (!aDeviceInfos[i].maSuggestedVersion.isEmpty())
697  {
698  SAL_WARN("vcl.driver", "use : " << aDeviceInfos[i].maSuggestedVersion);
699  }
700  break;
701  }
702  }
703 
704  SAL_INFO("vcl.driver", (match ? "denylisted" : "not denylisted") << " in " << blocklistURL);
705  return match;
706 }
707 
708 bool IsDeviceBlocked(const OUString& blocklistURL, VersionType versionType,
709  std::u16string_view driverVersion, std::u16string_view vendorId,
710  const OUString& deviceId)
711 {
712  std::vector<DriverInfo> driverList;
713  Parser parser(blocklistURL, driverList, versionType);
714  if (!parser.parse())
715  {
716  SAL_WARN("vcl.driver", "error parsing denylist " << blocklistURL);
717  return false;
718  }
719  return FindBlocklistedDeviceInList(driverList, versionType, driverVersion, vendorId, deviceId,
720  getOperatingSystem(), blocklistURL);
721 }
722 
723 #ifdef _WIN32
724 int32_t GetWindowsVersion()
725 {
726  static int32_t winVersion = [&]() {
727  // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
728  // subject to manifest-based behavior since Windows 8.1, so give wrong results.
729  // Another approach would be to use NetWkstaGetInfo, but that has some small
730  // reported delays (some milliseconds), and might get slower in domains with
731  // poor network connections.
732  // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
733  HINSTANCE hLibrary = LoadLibraryW(L"kernel32.dll");
734  if (hLibrary != nullptr)
735  {
736  wchar_t szPath[MAX_PATH];
737  DWORD dwCount = GetModuleFileNameW(hLibrary, szPath, SAL_N_ELEMENTS(szPath));
738  FreeLibrary(hLibrary);
739  if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath))
740  {
741  dwCount = GetFileVersionInfoSizeW(szPath, nullptr);
742  if (dwCount != 0)
743  {
744  std::unique_ptr<char[]> ver(new char[dwCount]);
745  if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE)
746  {
747  void* pBlock = nullptr;
748  UINT dwBlockSz = 0;
749  if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE
750  && dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
751  {
752  VS_FIXEDFILEINFO* vinfo = static_cast<VS_FIXEDFILEINFO*>(pBlock);
753  return int32_t(vinfo->dwProductVersionMS);
754  }
755  }
756  }
757  }
758  }
759  return 0;
760  }();
761 
762  return winVersion;
763 }
764 #endif
765 
766 } // namespace
767 
768 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static OUString GetVendorId(std::string_view rString)
VersionComparisonOp meComparisonOp
std::vector< OUString > maDevices
static VersionComparisonOp getComparison(std::string_view rString)
tuple parser
bool FindBlocklistedDeviceInList(std::vector< DriverInfo > &aDeviceInfos, VersionType versionType, std::u16string_view sDriverVersion, std::u16string_view sAdapterVendorID, OUString const &sAdapterDeviceID, OperatingSystem system, const OUString &blocklistURL)
static void PadDriverDecimal(char *aString)
char const * begin
DeviceVendor GetVendorFromId(uint32_t id)
Returns vendor for the given vendor ID, or VendorAll if not known.
bool IsDeviceBlocked(const OUString &blocklistURL, VersionType versionType, std::u16string_view driverVersion, std::u16string_view vendorId, const OUString &deviceId)
bool match(const sal_Unicode *pWild, const sal_Unicode *pStr, const sal_Unicode cEscape)
OUString maString
std::string_view GetVendorNameFromId(uint32_t id)
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
#define GFX_DRIVER_VERSION(a, b, c, d)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Parser(const OUString &rURL, std::vector< DriverInfo > &rDriverList, VersionType versionType)
const uint64_t allDriverVersions
double d
UNKNOWN
const VersionType mVersionType
#define SAL_N_ELEMENTS(arr)
int i
void handleContent(xmlreader::XmlReader &rReader)
uno_Any a
static OperatingSystem getOperatingSystem(std::string_view rString)
uint64_t getVersion(std::string_view rString)
sal_Int16 nVersion
VCL_DLLPUBLIC uint32_t vendorId
const int DeviceVendorMax
sal_Int32 length
Span getAttributeValue(bool fullyNormalize)
#define SAL_INFO(area, stream)
static void handleDevices(DriverInfo &rDriver, xmlreader::XmlReader &rReader)
void handleEntry(DriverInfo &rDriver, xmlreader::XmlReader &rReader)
const char * name
#define MAX_PATH
void handleList(xmlreader::XmlReader &rReader)
bool nextAttribute(int *nsId, Span *localName)
#define SAL_WARN(area, stream)
Result nextItem(Text reportText, Span *data, int *nsId)
std::vector< DriverInfo > & mrDriverList
aStr
static bool SplitDriverVersion(const char *aSource, char *aAStr, char *aBStr, char *aCStr, char *aDStr, VersionType versionType)
static bool ParseDriverVersion(std::u16string_view aVersion, uint64_t &rNumericVersion, VersionType versionType)