@@ -77,6 +77,8 @@ RCParser::ParseType RCParser::parseSingleResource() {
77
77
Result = parseHTMLResource ();
78
78
else if (TypeToken->equalsLower (" MENU" ))
79
79
Result = parseMenuResource ();
80
+ else if (TypeToken->equalsLower (" VERSIONINFO" ))
81
+ Result = parseVersionInfoResource ();
80
82
else
81
83
return getExpectedError (" resource type" , /* IsAlreadyRead = */ true );
82
84
@@ -322,6 +324,13 @@ RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
322
324
return std::move (Dialog);
323
325
}
324
326
327
+ RCParser::ParseType RCParser::parseVersionInfoResource () {
328
+ ASSIGN_OR_RETURN (FixedResult, parseVersionInfoFixed ());
329
+ ASSIGN_OR_RETURN (BlockResult, parseVersionInfoBlockContents (StringRef ()));
330
+ return make_unique<VersionInfoResource>(std::move (**BlockResult),
331
+ std::move (*FixedResult));
332
+ }
333
+
325
334
Expected<Control> RCParser::parseControl () {
326
335
// Each control definition (except CONTROL) follows one of the schemes below
327
336
// depending on the control class:
@@ -446,6 +455,72 @@ RCParser::ParseType RCParser::parseStringTableResource() {
446
455
return std::move (Table);
447
456
}
448
457
458
+ Expected<std::unique_ptr<VersionInfoBlock>>
459
+ RCParser::parseVersionInfoBlockContents (StringRef BlockName) {
460
+ RETURN_IF_ERROR (consumeType (Kind::BlockBegin));
461
+
462
+ auto Contents = make_unique<VersionInfoBlock>(BlockName);
463
+
464
+ while (!isNextTokenKind (Kind::BlockEnd)) {
465
+ ASSIGN_OR_RETURN (Stmt, parseVersionInfoStmt ());
466
+ Contents->addStmt (std::move (*Stmt));
467
+ }
468
+
469
+ consume (); // Consume BlockEnd.
470
+
471
+ return std::move (Contents);
472
+ }
473
+
474
+ Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt () {
475
+ // Expect either BLOCK or VALUE, then a name or a key (a string).
476
+ ASSIGN_OR_RETURN (TypeResult, readIdentifier ());
477
+
478
+ if (TypeResult->equals_lower (" BLOCK" )) {
479
+ ASSIGN_OR_RETURN (NameResult, readString ());
480
+ return parseVersionInfoBlockContents (*NameResult);
481
+ }
482
+
483
+ if (TypeResult->equals_lower (" VALUE" )) {
484
+ ASSIGN_OR_RETURN (KeyResult, readString ());
485
+ // Read a (possibly empty) list of strings and/or ints, each preceded by
486
+ // a comma.
487
+ std::vector<IntOrString> Values;
488
+
489
+ while (consumeOptionalType (Kind::Comma)) {
490
+ ASSIGN_OR_RETURN (ValueResult, readIntOrString ());
491
+ Values.push_back (*ValueResult);
492
+ }
493
+ return make_unique<VersionInfoValue>(*KeyResult, std::move (Values));
494
+ }
495
+
496
+ return getExpectedError (" BLOCK or VALUE" , true );
497
+ }
498
+
499
+ Expected<VersionInfoResource::VersionInfoFixed>
500
+ RCParser::parseVersionInfoFixed () {
501
+ using RetType = VersionInfoResource::VersionInfoFixed;
502
+ RetType Result;
503
+
504
+ // Read until the beginning of the block.
505
+ while (!isNextTokenKind (Kind::BlockBegin)) {
506
+ ASSIGN_OR_RETURN (TypeResult, readIdentifier ());
507
+ auto FixedType = RetType::getFixedType (*TypeResult);
508
+
509
+ if (!RetType::isTypeSupported (FixedType))
510
+ return getExpectedError (" fixed VERSIONINFO statement type" , true );
511
+ if (Result.IsTypePresent [FixedType])
512
+ return getExpectedError (" yet unread fixed VERSIONINFO statement type" ,
513
+ true );
514
+
515
+ // VERSION variations take multiple integers.
516
+ size_t NumInts = RetType::isVersionType (FixedType) ? 4 : 1 ;
517
+ ASSIGN_OR_RETURN (ArgsResult, readIntsWithCommas (NumInts, NumInts));
518
+ Result.setValue (FixedType, *ArgsResult);
519
+ }
520
+
521
+ return Result;
522
+ }
523
+
449
524
RCParser::ParseOptionType RCParser::parseLanguageStmt () {
450
525
ASSIGN_OR_RETURN (Args, readIntsWithCommas (/* min = */ 2 , /* max = */ 2 ));
451
526
return make_unique<LanguageResource>((*Args)[0 ], (*Args)[1 ]);
0 commit comments