• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ParadoxGameConverters / commonItems / 12846535547

18 Jan 2025 06:41PM UTC coverage: 75.846% (-1.7%) from 77.556%
12846535547

Pull #274

github

web-flow
Merge 8b9494010 into b007cb890
Pull Request #274: Eliminate warnings

279 of 358 new or added lines in 13 files covered. (77.93%)

38 existing lines in 2 files now uncovered.

1837 of 2422 relevant lines covered (75.85%)

240.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.05
/GameVersion.cpp
1
#include "GameVersion.h"
2

3
#include <filesystem>
4
#include <fstream>
5

6
#include "CommonRegexes.h"
7
#include "OSCompatibilityLayer.h"
8
#include "ParserHelpers.h"
9

10

11

12
using std::filesystem::path;
13
using std::filesystem::u8path;
14

15

16

17
GameVersion::GameVersion(std::string version)
117✔
18
{
19
        if (version.empty())
117✔
20
        {
21
                return;
4✔
22
        }
23

24
        auto dot = version.find_first_of('.');
113✔
25
        firstPart = std::stoi(version.substr(0, dot));
116✔
26
        if (dot == std::string::npos)
110✔
27
        {
28
                return;
9✔
29
        }
30

31
        version = version.substr(dot + 1, version.size());
101✔
32
        dot = version.find_first_of('.');
101✔
33
        secondPart = std::stoi(version.substr(0, dot));
101✔
34
        if (dot == std::string::npos)
101✔
35
        {
36
                return;
43✔
37
        }
38

39
        version = version.substr(dot + 1, version.size());
58✔
40
        dot = version.find_first_of('.');
58✔
41
        thirdPart = std::stoi(version.substr(0, dot));
58✔
42
        if (dot == std::string::npos)
58✔
43
        {
44
                return;
31✔
45
        }
46

47
        version = version.substr(dot + 1, version.size());
27✔
48
        dot = version.find_first_of('.');
27✔
49
        fourthPart = std::stoi(version.substr(0, dot));
27✔
50
}
3✔
51

52
GameVersion::GameVersion(std::istream& theStream)
1✔
53
{
54
        registerKeys();
1✔
55
        parseStream(theStream);
1✔
56
        clearRegisteredKeywords();
1✔
57
}
1✔
58

59
void GameVersion::registerKeys()
1✔
60
{
61
        registerKeyword("first", [this](std::istream& theStream) {
1✔
62
                firstPart = commonItems::getInt(theStream);
1✔
63
        });
1✔
64
        registerKeyword("second", [this](std::istream& theStream) {
1✔
65
                secondPart = commonItems::getInt(theStream);
1✔
66
        });
1✔
67
        registerKeyword("third", [this](std::istream& theStream) {
1✔
68
                thirdPart = commonItems::getInt(theStream);
1✔
69
        });
1✔
70
        registerKeyword("forth", [this](std::istream& theStream) {
1✔
71
                fourthPart = commonItems::getInt(theStream);
1✔
72
        });
1✔
73
        registerRegex(commonItems::catchallRegex, commonItems::ignoreItem);
1✔
74
}
1✔
75

76
bool GameVersion::operator>=(const GameVersion& rhs) const
2✔
77
{
78
        return *this > rhs || *this == rhs;
2✔
79
}
80

81
bool GameVersion::operator>(const GameVersion& rhs) const
6✔
82
{
83
        auto testL = 0;
6✔
84
        auto testR = 0;
6✔
85
        if (firstPart)
6✔
86
                testL = *firstPart;
6✔
87
        if (rhs.firstPart)
6✔
88
                testR = *rhs.firstPart;
6✔
89

90
        if (testL > testR)
6✔
91
                return true;
2✔
92
        if (testL < testR)
4✔
93
                return false;
×
94

95
        testL = 0;
4✔
96
        testR = 0;
4✔
97
        if (secondPart)
4✔
98
                testL = *secondPart;
4✔
99
        if (rhs.secondPart)
4✔
100
                testR = *rhs.secondPart;
4✔
101

102
        if (testL > testR)
4✔
103
                return true;
1✔
104
        if (testL < testR)
3✔
105
                return false;
×
106

107
        testL = 0;
3✔
108
        testR = 0;
3✔
109
        if (thirdPart)
3✔
110
                testL = *thirdPart;
3✔
111
        if (rhs.thirdPart)
3✔
112
                testR = *rhs.thirdPart;
3✔
113

114
        if (testL > testR)
3✔
115
                return true;
1✔
116
        if (testL < testR)
2✔
117
                return false;
×
118

119
        testL = 0;
2✔
120
        testR = 0;
2✔
121
        if (fourthPart)
2✔
122
                testL = *fourthPart;
2✔
123
        if (rhs.fourthPart)
2✔
124
                testR = *rhs.fourthPart;
2✔
125

126
        return testL > testR;
2✔
127
}
128

129
bool GameVersion::operator<(const GameVersion& rhs) const
6✔
130
{
131
        auto testL = 0;
6✔
132
        auto testR = 0;
6✔
133
        if (firstPart)
6✔
134
                testL = *firstPart;
6✔
135
        if (rhs.firstPart)
6✔
136
                testR = *rhs.firstPart;
6✔
137

138
        if (testL < testR)
6✔
139
                return true;
2✔
140
        if (testL > testR)
4✔
141
                return false;
×
142

143
        testL = 0;
4✔
144
        testR = 0;
4✔
145
        if (secondPart)
4✔
146
                testL = *secondPart;
4✔
147
        if (rhs.secondPart)
4✔
148
                testR = *rhs.secondPart;
4✔
149

150
        if (testL < testR)
4✔
151
                return true;
1✔
152
        if (testL > testR)
3✔
153
                return false;
×
154

155
        testL = 0;
3✔
156
        testR = 0;
3✔
157
        if (thirdPart)
3✔
158
                testL = *thirdPart;
3✔
159
        if (rhs.thirdPart)
3✔
160
                testR = *rhs.thirdPart;
3✔
161

162
        if (testL < testR)
3✔
163
                return true;
1✔
164
        if (testL > testR)
2✔
165
                return false;
×
166

167
        testL = 0;
2✔
168
        testR = 0;
2✔
169
        if (fourthPart)
2✔
170
                testL = *fourthPart;
2✔
171
        if (rhs.fourthPart)
2✔
172
                testR = *rhs.fourthPart;
2✔
173

174
        return testL < testR;
2✔
175
}
176

177
bool GameVersion::operator<=(const GameVersion& rhs) const
2✔
178
{
179
        return *this < rhs || *this == rhs;
2✔
180
}
181

182
bool GameVersion::operator==(const GameVersion& rhs) const
31✔
183
{
184
        auto testL = 0;
31✔
185
        auto testR = 0;
31✔
186
        if (firstPart)
31✔
187
                testL = *firstPart;
27✔
188
        if (rhs.firstPart)
31✔
189
                testR = *rhs.firstPart;
27✔
190

191
        if (testL != testR)
31✔
192
                return false;
1✔
193

194
        testL = 0;
30✔
195
        testR = 0;
30✔
196
        if (secondPart)
30✔
197
                testL = *secondPart;
26✔
198
        if (rhs.secondPart)
30✔
199
                testR = *rhs.secondPart;
26✔
200

201
        if (testL != testR)
30✔
202
                return false;
3✔
203

204
        testL = 0;
27✔
205
        testR = 0;
27✔
206
        if (thirdPart)
27✔
207
                testL = *thirdPart;
15✔
208
        if (rhs.thirdPart)
27✔
209
                testR = *rhs.thirdPart;
13✔
210

211
        if (testL != testR)
27✔
212
                return false;
3✔
213

214
        testL = 0;
24✔
215
        testR = 0;
24✔
216
        if (fourthPart)
24✔
217
                testL = *fourthPart;
6✔
218
        if (rhs.fourthPart)
24✔
219
                testR = *rhs.fourthPart;
5✔
220

221
        return testL == testR;
24✔
222
}
223

224
bool GameVersion::operator!=(const GameVersion& rhs) const
13✔
225
{
226
        return !(*this == rhs);
13✔
227
}
228

229
std::ostream& operator<<(std::ostream& out, const GameVersion& version)
9✔
230
{
231
        if (version.firstPart)
9✔
232
                out << *version.firstPart << '.';
7✔
233
        else
234
                out << "0.";
2✔
235
        if (version.secondPart)
9✔
236
                out << *version.secondPart << '.';
6✔
237
        else
238
                out << "0.";
3✔
239
        if (version.thirdPart)
9✔
240
                out << *version.thirdPart << '.';
5✔
241
        else
242
                out << "0.";
4✔
243
        if (version.fourthPart)
9✔
244
                out << *version.fourthPart;
4✔
245
        else
246
                out << "0";
5✔
247
        return out;
9✔
248
}
249

250
GameVersion::Factory::Factory()
1✔
251
{
252
        registerKeyword("first", [this](std::istream& theStream) {
1✔
253
                firstPart = commonItems::getInt(theStream);
1✔
254
        });
1✔
255
        registerKeyword("second", [this](std::istream& theStream) {
1✔
256
                secondPart = commonItems::getInt(theStream);
1✔
257
        });
1✔
258
        registerKeyword("third", [this](std::istream& theStream) {
1✔
259
                thirdPart = commonItems::getInt(theStream);
1✔
260
        });
1✔
261
        registerKeyword("forth", [this](std::istream& theStream) {
1✔
262
                fourthPart = commonItems::getInt(theStream);
1✔
263
        });
1✔
264
        registerRegex(commonItems::catchallRegex, commonItems::ignoreItem);
1✔
265
}
1✔
266

267
GameVersion GameVersion::Factory::getVersion(std::istream& theStream)
1✔
268
{
269
        firstPart.reset();
1✔
270
        secondPart.reset();
1✔
271
        thirdPart.reset();
1✔
272
        fourthPart.reset();
1✔
273

274
        parseStream(theStream);
1✔
275

276
        return GameVersion(firstPart, secondPart, thirdPart, fourthPart);
1✔
277
}
278

279
std::string GameVersion::toString() const
5✔
280
{
281
        std::string toReturn;
5✔
282
        if (firstPart)
5✔
283
                toReturn += std::to_string(*firstPart) + ".";
4✔
284
        else
285
                toReturn += "0.";
1✔
286
        if (secondPart)
5✔
287
                toReturn += std::to_string(*secondPart) + ".";
3✔
288
        else
289
                toReturn += "0.";
2✔
290
        if (thirdPart)
5✔
291
                toReturn += std::to_string(*thirdPart) + ".";
2✔
292
        else
293
                toReturn += "0.";
3✔
294
        if (fourthPart)
5✔
295
                toReturn += std::to_string(*fourthPart);
1✔
296
        else
297
                toReturn += "0";
4✔
298

299
        return toReturn;
5✔
300
}
×
301

302
std::string GameVersion::toShortString() const
17✔
303
{
304
        std::string nameString;
17✔
305
        if (fourthPart)
17✔
306
                nameString = "." + std::to_string(*fourthPart);
1✔
307

308
        if (thirdPart)
17✔
309
                nameString = "." + std::to_string(*thirdPart) + nameString;
4✔
310

311
        if (secondPart)
17✔
312
                nameString = "." + std::to_string(*secondPart) + nameString;
15✔
313

314
        if (firstPart)
17✔
315
                nameString = std::to_string(*firstPart) + nameString;
16✔
316

317
        return nameString;
17✔
318
}
×
319

320
std::string GameVersion::toWildCard() const
5✔
321
{
322
        std::string nameString;
5✔
323
        if (fourthPart)
5✔
324
                nameString = "." + std::to_string(*fourthPart);
1✔
325
        else if (thirdPart)
4✔
326
                nameString = ".*";
1✔
327

328
        if (thirdPart)
5✔
329
                nameString = "." + std::to_string(*thirdPart) + nameString;
2✔
330
        else if (secondPart)
3✔
331
                nameString = ".*";
1✔
332

333
        if (secondPart)
5✔
334
                nameString = "." + std::to_string(*secondPart) + nameString;
3✔
335
        else if (firstPart)
2✔
336
                nameString = ".*";
1✔
337

338
        if (firstPart)
5✔
339
                nameString = std::to_string(*firstPart) + nameString;
4✔
340
        else
341
                nameString = "*";
1✔
342

343
        return nameString;
5✔
344
}
×
345

346
bool GameVersion::isLargerishThan(const GameVersion& rhs) const
43✔
347
{
348
        // Largerish is intended for fuzzy comparisons like "converter works with up to 1.9",
349
        // so everything incoming on rhs from 0.0.0.0 to 1.9.x.y will match, (where x and y are >= 0),
350
        // thus overshooting the internal "1.9.0.0" setup. This works if ".0.0" are actually undefined.
351

352
        auto testDigit = 0;
43✔
353
        if (rhs.firstPart)
43✔
354
                testDigit = *rhs.firstPart;
43✔
355
        if (firstPart && testDigit > *firstPart)
43✔
356
                return false;
4✔
357
        if (firstPart && testDigit < *firstPart)
39✔
358
                return true;
9✔
359

360
        testDigit = 0;
30✔
361
        if (rhs.secondPart)
30✔
362
                testDigit = *rhs.secondPart;
30✔
363
        if (secondPart && testDigit > *secondPart)
30✔
364
                return false;
9✔
365
        if (secondPart && testDigit < *secondPart)
21✔
366
                return true;
2✔
367

368
        testDigit = 0;
19✔
369
        if (rhs.thirdPart)
19✔
370
                testDigit = *rhs.thirdPart;
15✔
371
        if (thirdPart && testDigit > *thirdPart)
19✔
372
                return false;
5✔
373
        if (thirdPart && testDigit < *thirdPart)
14✔
374
                return true;
3✔
375

376
        testDigit = 0;
11✔
377
        if (rhs.fourthPart)
11✔
378
                testDigit = *rhs.fourthPart;
6✔
379
        return !fourthPart || testDigit <= *fourthPart;
11✔
380
}
381

382
std::optional<GameVersion> GameVersion::extractVersionFromLauncher(const path& filePath)
8✔
383
{
384
        // use this for modern PDX games, point filePath to launcher-settings.json to get installation version.
385

386
        if (!commonItems::DoesFileExist(filePath))
8✔
387
        {
388
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " does not exist.";
1✔
389
                return std::nullopt;
1✔
390
        }
391

392
        auto result = extractVersionByStringFromLauncher("rawVersion", filePath);
7✔
393
        if (!result)
7✔
394
        {
395
                // imperator rome?
396
                result = extractVersionByStringFromLauncher("version", filePath);
4✔
397
        }
398
        if (!result)
7✔
399
        {
400
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " does not contain installation version!";
3✔
401
                return std::nullopt;
3✔
402
        }
403
        return result;
4✔
404
}
7✔
405

406
std::optional<GameVersion> GameVersion::extractVersionFromLauncher(const std::string& filePath)
8✔
407
{
408
#pragma warning(push)
409
#pragma warning(disable : 4996)
410
        return extractVersionFromLauncher(u8path(filePath));
16✔
411
#pragma warning(pop)
412
}
413

414

415
std::optional<GameVersion> GameVersion::extractVersionByStringFromLauncher(const std::string& versionString, const path& filePath)
11✔
416
{
417
        std::ifstream versionFile(filePath);
11✔
418
        if (!versionFile.is_open())
11✔
419
                return std::nullopt;
×
420

421
        while (!versionFile.eof())
125✔
422
        {
423
                std::string line;
122✔
424
                std::getline(versionFile, line);
122✔
425
                if (line.find(versionString) == std::string::npos)
122✔
426
                        continue;
114✔
427
                auto pos = line.find(':');
8✔
428
                if (pos == std::string::npos)
8✔
429
                {
430
                        versionFile.close();
1✔
431
                        return std::nullopt;
1✔
432
                }
433

434
                line = line.substr(pos + 1, line.length());
7✔
435
                pos = line.find_first_of('\"');
7✔
436
                if (pos == std::string::npos)
7✔
437
                {
438
                        versionFile.close();
×
439
                        return std::nullopt;
×
440
                }
441

442
                line = line.substr(pos + 1, line.length());
7✔
443
                pos = line.find_first_of('\"');
7✔
444
                if (pos == std::string::npos)
7✔
445
                {
446
                        versionFile.close();
×
447
                        return std::nullopt;
×
448
                }
449

450
                line = line.substr(0, pos);
7✔
451

452
                if (!line.empty() && line[0] == 'v')
7✔
453
                {
454
                        line = line.substr(1, line.length());
1✔
455
                }
456

457
                try
458
                {
459
                        return GameVersion(line);
10✔
460
                }
461
                catch (std::exception&)
3✔
462
                {
463
                        versionFile.close();
3✔
464
                        return std::nullopt;
3✔
465
                }
3✔
466
        }
122✔
467

468
        versionFile.close();
3✔
469
        return std::nullopt;
3✔
470
}
11✔
471

472

NEW
473
std::optional<GameVersion> GameVersion::extractVersionByStringFromLauncher(const std::string& versionString, const std::string& filePath)
×
474
{
475
#pragma warning(push)
476
#pragma warning(disable : 4996)
NEW
477
        return extractVersionByStringFromLauncher(versionString, u8path(filePath));
×
478
#pragma warning(pop)
479
}
480

481

482
std::optional<GameVersion> GameVersion::extractVersionFromReadMe(const path& filePath)
4✔
483
{
484
        // Use this for Vic2 ReadMe.txt/Readme.txt. Be sure to check both as name changes across versions, and it's not
485
        // internally consistent on windows. Steam update from one version to another can in fact *not* change the case on
486
        // the file, even if fresh reinstallation would!
487

488
        std::ifstream versionFile(filePath);
4✔
489
        if (!versionFile.is_open())
4✔
490
        {
491
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " cannot be opened.";
1✔
492
                return std::nullopt;
1✔
493
        }
494

495
        std::string line;
3✔
496
        std::getline(versionFile, line); // skip first line
3✔
497
        if (versionFile.eof())
3✔
498
        {
499
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " is broken.";
×
500
                return std::nullopt;
×
501
        }
502
        std::getline(versionFile, line);
3✔
503

504
        auto pos = line.find(" below");
3✔
505
        if (pos == std::string::npos)
3✔
506
        {
507
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " is broken.";
1✔
508
                return std::nullopt;
1✔
509
        }
510

511
        line = line.substr(0, pos);
2✔
512
        pos = line.find_last_of(' ');
2✔
513
        line = line.substr(pos + 1, line.length());
2✔
514

515
        if (!std::isdigit(*line.begin()))
2✔
516
        {
517
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " has broken version.";
1✔
518
                return std::nullopt;
1✔
519
        }
520

521
        try
522
        {
523
                return GameVersion(line);
1✔
524
        }
525
        catch (std::exception& e)
×
526
        {
527
                Log(LogLevel::Warning) << "Failure extracting version: " << line << " is broken: " << e.what();
×
528
                return std::nullopt;
×
529
        }
×
530
}
4✔
531

532

533
std::optional<GameVersion> GameVersion::extractVersionFromReadMe(const std::string& filePath)
4✔
534
{
535
#pragma warning(push)
536
#pragma warning(disable : 4996)
537
        return extractVersionFromReadMe(u8path(filePath));
8✔
538
#pragma warning(pop)
539
}
540

541

542
std::optional<GameVersion> GameVersion::extractVersionFromChangeLog(const path& filePath)
4✔
543
{
544
        // Use this to get CK2 installation version from CK2's ChangeLog.txt.
545

546
        if (!commonItems::DoesFileExist(filePath))
4✔
547
        {
548
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " does not exist.";
1✔
549
                return std::nullopt;
1✔
550
        }
551

552
        std::ifstream versionFile(filePath);
3✔
553
        if (!versionFile.is_open())
3✔
554
        {
555
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " cannot be opened.";
×
556
                return std::nullopt;
×
557
        }
558

559
        std::string line;
3✔
560
        std::getline(versionFile, line);
3✔
561
        std::getline(versionFile, line);
3✔
562
        if (versionFile.eof())
3✔
563
        {
564
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " is broken.";
×
565
                return std::nullopt;
×
566
        }
567
        std::getline(versionFile, line);
3✔
568

569
        auto pos = line.find_first_of(' ');
3✔
570
        if (pos == std::string::npos)
3✔
571
        {
572
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " has broken version.";
×
573
                return std::nullopt;
×
574
        }
575
        line = line.substr(pos + 1, line.length());
3✔
576
        pos = line.find_first_of(' ');
3✔
577
        if (pos == std::string::npos)
3✔
578
        {
579
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " has broken version.";
×
580
                return std::nullopt;
×
581
        }
582
        line = line.substr(0, pos);
3✔
583
        if (line.empty() || !std::isdigit(*line.begin()))
3✔
584
        {
585
                Log(LogLevel::Warning) << "Failure extracting version: " << filePath << " has broken version.";
2✔
586
                return std::nullopt;
2✔
587
        }
588
        try
589
        {
590
                return GameVersion(line);
1✔
591
        }
592
        catch (std::exception& e)
×
593
        {
594
                Log(LogLevel::Warning) << "Failure extracting version: " << line << " is broken: " << e.what();
×
595
                return std::nullopt;
×
596
        }
×
597
}
3✔
598

599

600
std::optional<GameVersion> GameVersion::extractVersionFromChangeLog(const std::string& filePath)
4✔
601
{
602
#pragma warning(push)
603
#pragma warning(disable : 4996)
604
        return extractVersionFromChangeLog(u8path(filePath));
8✔
605
#pragma warning(pop)
606
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc