ResourceScriptParser.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. //===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===---------------------------------------------------------------------===//
  8. //
  9. // This implements the parser defined in ResourceScriptParser.h.
  10. //
  11. //===---------------------------------------------------------------------===//
  12. #include "ResourceScriptParser.h"
  13. #include "llvm/Option/ArgList.h"
  14. #include "llvm/Support/FileSystem.h"
  15. #include "llvm/Support/Path.h"
  16. #include "llvm/Support/Process.h"
  17. // Take an expression returning llvm::Error and forward the error if it exists.
  18. #define RETURN_IF_ERROR(Expr) \
  19. if (auto Err = (Expr)) \
  20. return std::move(Err);
  21. // Take an expression returning llvm::Expected<T> and assign it to Var or
  22. // forward the error out of the function.
  23. #define ASSIGN_OR_RETURN(Var, Expr) \
  24. auto Var = (Expr); \
  25. if (!Var) \
  26. return Var.takeError();
  27. namespace llvm {
  28. namespace rc {
  29. RCParser::ParserError::ParserError(const Twine &Expected, const LocIter CurLoc,
  30. const LocIter End)
  31. : ErrorLoc(CurLoc), FileEnd(End) {
  32. CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
  33. (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
  34. }
  35. char RCParser::ParserError::ID = 0;
  36. RCParser::RCParser(std::vector<RCToken> TokenList)
  37. : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
  38. bool RCParser::isEof() const { return CurLoc == End; }
  39. RCParser::ParseType RCParser::parseSingleResource() {
  40. // The first thing we read is usually a resource's name. However, in some
  41. // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
  42. // and the first token to be read is the type.
  43. ASSIGN_OR_RETURN(NameToken, readTypeOrName());
  44. if (NameToken->equalsLower("LANGUAGE"))
  45. return parseLanguageResource();
  46. else if (NameToken->equalsLower("STRINGTABLE"))
  47. return parseStringTableResource();
  48. // If it's not an unnamed resource, what we've just read is a name. Now,
  49. // read resource type;
  50. ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
  51. ParseType Result = std::unique_ptr<RCResource>();
  52. (void)!Result;
  53. if (TypeToken->equalsLower("ACCELERATORS"))
  54. Result = parseAcceleratorsResource();
  55. else if (TypeToken->equalsLower("BITMAP"))
  56. Result = parseBitmapResource();
  57. else if (TypeToken->equalsLower("CURSOR"))
  58. Result = parseCursorResource();
  59. else if (TypeToken->equalsLower("DIALOG"))
  60. Result = parseDialogResource(false);
  61. else if (TypeToken->equalsLower("DIALOGEX"))
  62. Result = parseDialogResource(true);
  63. else if (TypeToken->equalsLower("HTML"))
  64. Result = parseHTMLResource();
  65. else if (TypeToken->equalsLower("ICON"))
  66. Result = parseIconResource();
  67. else if (TypeToken->equalsLower("MENU"))
  68. Result = parseMenuResource();
  69. else if (TypeToken->equalsLower("RCDATA"))
  70. Result = parseUserDefinedResource(RkRcData);
  71. else if (TypeToken->equalsLower("VERSIONINFO"))
  72. Result = parseVersionInfoResource();
  73. else
  74. Result = parseUserDefinedResource(*TypeToken);
  75. if (Result)
  76. (*Result)->setName(*NameToken);
  77. return Result;
  78. }
  79. bool RCParser::isNextTokenKind(Kind TokenKind) const {
  80. return !isEof() && look().kind() == TokenKind;
  81. }
  82. const RCToken &RCParser::look() const {
  83. assert(!isEof());
  84. return *CurLoc;
  85. }
  86. const RCToken &RCParser::read() {
  87. assert(!isEof());
  88. return *CurLoc++;
  89. }
  90. void RCParser::consume() {
  91. assert(!isEof());
  92. CurLoc++;
  93. }
  94. // An integer description might consist of a single integer or
  95. // an arithmetic expression evaluating to the integer. The expressions
  96. // can contain the following tokens: <int> ( ) + - | & ~ not. Their meaning
  97. // is the same as in C++ except for 'not' expression.
  98. // The operators in the original RC implementation have the following
  99. // precedence:
  100. // 1) Unary operators (- ~ not),
  101. // 2) Binary operators (+ - & |), with no precedence.
  102. //
  103. // 'not' expression is mostly useful for style values. It evaluates to 0,
  104. // but value given to the operator is stored separately from integer value.
  105. // It's mostly useful for control style expressions and causes bits from
  106. // default control style to be excluded from generated style. For binary
  107. // operators the mask from the right operand is applied to the left operand
  108. // and masks from both operands are combined in operator result.
  109. //
  110. // The following grammar is used to parse the expressions Exp1:
  111. // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
  112. // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
  113. // (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
  114. // separated by binary operators.)
  115. //
  116. // Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
  117. // is read by parseIntExpr2().
  118. //
  119. // The original Microsoft tool handles multiple unary operators incorrectly.
  120. // For example, in 16-bit little-endian integers:
  121. // 1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
  122. // 1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
  123. // Our implementation differs from the original one and handles these
  124. // operators correctly:
  125. // 1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
  126. // 1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
  127. Expected<RCInt> RCParser::readInt() {
  128. ASSIGN_OR_RETURN(Value, parseIntExpr1());
  129. return (*Value).getValue();
  130. }
  131. Expected<IntWithNotMask> RCParser::parseIntExpr1() {
  132. // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
  133. ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
  134. IntWithNotMask Result = *FirstResult;
  135. while (!isEof() && look().isBinaryOp()) {
  136. auto OpToken = read();
  137. ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
  138. switch (OpToken.kind()) {
  139. case Kind::Plus:
  140. Result += *NextResult;
  141. break;
  142. case Kind::Minus:
  143. Result -= *NextResult;
  144. break;
  145. case Kind::Pipe:
  146. Result |= *NextResult;
  147. break;
  148. case Kind::Amp:
  149. Result &= *NextResult;
  150. break;
  151. default:
  152. llvm_unreachable("Already processed all binary ops.");
  153. }
  154. }
  155. return Result;
  156. }
  157. Expected<IntWithNotMask> RCParser::parseIntExpr2() {
  158. // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
  159. static const char ErrorMsg[] = "'-', '~', integer or '('";
  160. if (isEof())
  161. return getExpectedError(ErrorMsg);
  162. switch (look().kind()) {
  163. case Kind::Minus: {
  164. consume();
  165. ASSIGN_OR_RETURN(Result, parseIntExpr2());
  166. return -(*Result);
  167. }
  168. case Kind::Tilde: {
  169. consume();
  170. ASSIGN_OR_RETURN(Result, parseIntExpr2());
  171. return ~(*Result);
  172. }
  173. case Kind::Int:
  174. return RCInt(read());
  175. case Kind::LeftParen: {
  176. consume();
  177. ASSIGN_OR_RETURN(Result, parseIntExpr1());
  178. RETURN_IF_ERROR(consumeType(Kind::RightParen));
  179. return *Result;
  180. }
  181. case Kind::Identifier: {
  182. if (!read().value().equals_insensitive("not"))
  183. return getExpectedError(ErrorMsg, true);
  184. ASSIGN_OR_RETURN(Result, parseIntExpr2());
  185. return IntWithNotMask(0, (*Result).getValue());
  186. }
  187. default:
  188. return getExpectedError(ErrorMsg);
  189. }
  190. }
  191. Expected<StringRef> RCParser::readString() {
  192. if (!isNextTokenKind(Kind::String))
  193. return getExpectedError("string");
  194. return read().value();
  195. }
  196. Expected<StringRef> RCParser::readFilename() {
  197. if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
  198. return getExpectedError("string");
  199. return read().value();
  200. }
  201. Expected<StringRef> RCParser::readIdentifier() {
  202. if (!isNextTokenKind(Kind::Identifier))
  203. return getExpectedError("identifier");
  204. return read().value();
  205. }
  206. Expected<IntOrString> RCParser::readIntOrString() {
  207. if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String))
  208. return getExpectedError("int or string");
  209. return IntOrString(read());
  210. }
  211. Expected<IntOrString> RCParser::readTypeOrName() {
  212. // We suggest that the correct resource name or type should be either an
  213. // identifier or an integer. The original RC tool is much more liberal.
  214. if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
  215. return getExpectedError("int or identifier");
  216. return IntOrString(read());
  217. }
  218. Error RCParser::consumeType(Kind TokenKind) {
  219. if (isNextTokenKind(TokenKind)) {
  220. consume();
  221. return Error::success();
  222. }
  223. switch (TokenKind) {
  224. #define TOKEN(TokenName) \
  225. case Kind::TokenName: \
  226. return getExpectedError(#TokenName);
  227. #define SHORT_TOKEN(TokenName, TokenCh) \
  228. case Kind::TokenName: \
  229. return getExpectedError(#TokenCh);
  230. #include "ResourceScriptTokenList.def"
  231. }
  232. llvm_unreachable("All case options exhausted.");
  233. }
  234. bool RCParser::consumeOptionalType(Kind TokenKind) {
  235. if (isNextTokenKind(TokenKind)) {
  236. consume();
  237. return true;
  238. }
  239. return false;
  240. }
  241. Expected<SmallVector<RCInt, 8>> RCParser::readIntsWithCommas(size_t MinCount,
  242. size_t MaxCount) {
  243. assert(MinCount <= MaxCount);
  244. SmallVector<RCInt, 8> Result;
  245. auto FailureHandler =
  246. [&](llvm::Error Err) -> Expected<SmallVector<RCInt, 8>> {
  247. if (Result.size() < MinCount)
  248. return std::move(Err);
  249. consumeError(std::move(Err));
  250. return Result;
  251. };
  252. for (size_t i = 0; i < MaxCount; ++i) {
  253. // Try to read a comma unless we read the first token.
  254. // Sometimes RC tool requires them and sometimes not. We decide to
  255. // always require them.
  256. if (i >= 1) {
  257. if (auto CommaError = consumeType(Kind::Comma))
  258. return FailureHandler(std::move(CommaError));
  259. }
  260. if (auto IntResult = readInt())
  261. Result.push_back(*IntResult);
  262. else
  263. return FailureHandler(IntResult.takeError());
  264. }
  265. return std::move(Result);
  266. }
  267. Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc,
  268. ArrayRef<uint32_t> FlagValues) {
  269. assert(!FlagDesc.empty());
  270. assert(FlagDesc.size() == FlagValues.size());
  271. uint32_t Result = 0;
  272. while (isNextTokenKind(Kind::Comma)) {
  273. consume();
  274. ASSIGN_OR_RETURN(FlagResult, readIdentifier());
  275. bool FoundFlag = false;
  276. for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) {
  277. if (!FlagResult->equals_insensitive(FlagDesc[FlagId]))
  278. continue;
  279. Result |= FlagValues[FlagId];
  280. FoundFlag = true;
  281. break;
  282. }
  283. if (!FoundFlag)
  284. return getExpectedError(join(FlagDesc, "/"), true);
  285. }
  286. return Result;
  287. }
  288. uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
  289. while (!isEof()) {
  290. const RCToken &Token = look();
  291. if (Token.kind() != Kind::Identifier)
  292. return Flags;
  293. const StringRef Ident = Token.value();
  294. if (Ident.equals_insensitive("PRELOAD"))
  295. Flags |= MfPreload;
  296. else if (Ident.equals_insensitive("LOADONCALL"))
  297. Flags &= ~MfPreload;
  298. else if (Ident.equals_insensitive("FIXED"))
  299. Flags &= ~(MfMoveable | MfDiscardable);
  300. else if (Ident.equals_insensitive("MOVEABLE"))
  301. Flags |= MfMoveable;
  302. else if (Ident.equals_insensitive("DISCARDABLE"))
  303. Flags |= MfDiscardable | MfMoveable | MfPure;
  304. else if (Ident.equals_insensitive("PURE"))
  305. Flags |= MfPure;
  306. else if (Ident.equals_insensitive("IMPURE"))
  307. Flags &= ~(MfPure | MfDiscardable);
  308. else if (Ident.equals_insensitive("SHARED"))
  309. Flags |= MfPure;
  310. else if (Ident.equals_insensitive("NONSHARED"))
  311. Flags &= ~(MfPure | MfDiscardable);
  312. else
  313. return Flags;
  314. consume();
  315. }
  316. return Flags;
  317. }
  318. Expected<OptionalStmtList>
  319. RCParser::parseOptionalStatements(OptStmtType StmtsType) {
  320. OptionalStmtList Result;
  321. // The last statement is always followed by the start of the block.
  322. while (!isNextTokenKind(Kind::BlockBegin)) {
  323. ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(StmtsType));
  324. Result.addStmt(std::move(*SingleParse));
  325. }
  326. return std::move(Result);
  327. }
  328. Expected<std::unique_ptr<OptionalStmt>>
  329. RCParser::parseSingleOptionalStatement(OptStmtType StmtsType) {
  330. ASSIGN_OR_RETURN(TypeToken, readIdentifier());
  331. if (TypeToken->equals_insensitive("CHARACTERISTICS"))
  332. return parseCharacteristicsStmt();
  333. if (TypeToken->equals_insensitive("LANGUAGE"))
  334. return parseLanguageStmt();
  335. if (TypeToken->equals_insensitive("VERSION"))
  336. return parseVersionStmt();
  337. if (StmtsType != OptStmtType::BasicStmt) {
  338. if (TypeToken->equals_insensitive("CAPTION"))
  339. return parseCaptionStmt();
  340. if (TypeToken->equals_insensitive("CLASS"))
  341. return parseClassStmt();
  342. if (TypeToken->equals_insensitive("EXSTYLE"))
  343. return parseExStyleStmt();
  344. if (TypeToken->equals_insensitive("FONT"))
  345. return parseFontStmt(StmtsType);
  346. if (TypeToken->equals_insensitive("STYLE"))
  347. return parseStyleStmt();
  348. }
  349. return getExpectedError("optional statement type, BEGIN or '{'",
  350. /* IsAlreadyRead = */ true);
  351. }
  352. RCParser::ParseType RCParser::parseLanguageResource() {
  353. // Read LANGUAGE as an optional statement. If it's read correctly, we can
  354. // upcast it to RCResource.
  355. return parseLanguageStmt();
  356. }
  357. RCParser::ParseType RCParser::parseAcceleratorsResource() {
  358. uint16_t MemoryFlags =
  359. parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
  360. ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
  361. RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
  362. auto Accels = std::make_unique<AcceleratorsResource>(
  363. std::move(*OptStatements), MemoryFlags);
  364. while (!consumeOptionalType(Kind::BlockEnd)) {
  365. ASSIGN_OR_RETURN(EventResult, readIntOrString());
  366. RETURN_IF_ERROR(consumeType(Kind::Comma));
  367. ASSIGN_OR_RETURN(IDResult, readInt());
  368. ASSIGN_OR_RETURN(
  369. FlagsResult,
  370. parseFlags(AcceleratorsResource::Accelerator::OptionsStr,
  371. AcceleratorsResource::Accelerator::OptionsFlags));
  372. Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult);
  373. }
  374. return std::move(Accels);
  375. }
  376. RCParser::ParseType RCParser::parseCursorResource() {
  377. uint16_t MemoryFlags =
  378. parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
  379. ASSIGN_OR_RETURN(Arg, readFilename());
  380. return std::make_unique<CursorResource>(*Arg, MemoryFlags);
  381. }
  382. RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
  383. uint16_t MemoryFlags =
  384. parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
  385. // Dialog resources have the following format of the arguments:
  386. // DIALOG: x, y, width, height [opt stmts...] {controls...}
  387. // DIALOGEX: x, y, width, height [, helpID] [opt stmts...] {controls...}
  388. // These are very similar, so we parse them together.
  389. ASSIGN_OR_RETURN(LocResult, readIntsWithCommas(4, 4));
  390. uint32_t HelpID = 0; // When HelpID is unset, it's assumed to be 0.
  391. if (IsExtended && consumeOptionalType(Kind::Comma)) {
  392. ASSIGN_OR_RETURN(HelpIDResult, readInt());
  393. HelpID = *HelpIDResult;
  394. }
  395. ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements(
  396. IsExtended ? OptStmtType::DialogExStmt
  397. : OptStmtType::DialogStmt));
  398. assert(isNextTokenKind(Kind::BlockBegin) &&
  399. "parseOptionalStatements, when successful, halts on BlockBegin.");
  400. consume();
  401. auto Dialog = std::make_unique<DialogResource>(
  402. (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
  403. HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
  404. while (!consumeOptionalType(Kind::BlockEnd)) {
  405. ASSIGN_OR_RETURN(ControlDefResult, parseControl());
  406. Dialog->addControl(std::move(*ControlDefResult));
  407. }
  408. return std::move(Dialog);
  409. }
  410. RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
  411. uint16_t MemoryFlags =
  412. parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
  413. if (isEof())
  414. return getExpectedError("filename, '{' or BEGIN");
  415. // Check if this is a file resource.
  416. switch (look().kind()) {
  417. case Kind::String:
  418. case Kind::Identifier:
  419. return std::make_unique<UserDefinedResource>(Type, read().value(),
  420. MemoryFlags);
  421. default:
  422. break;
  423. }
  424. RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
  425. std::vector<IntOrString> Data;
  426. while (!consumeOptionalType(Kind::BlockEnd)) {
  427. ASSIGN_OR_RETURN(Item, readIntOrString());
  428. Data.push_back(*Item);
  429. // There can be zero or more commas after each token (but not before
  430. // the first one).
  431. while (consumeOptionalType(Kind::Comma)) {
  432. }
  433. }
  434. return std::make_unique<UserDefinedResource>(Type, std::move(Data),
  435. MemoryFlags);
  436. }
  437. RCParser::ParseType RCParser::parseVersionInfoResource() {
  438. uint16_t MemoryFlags =
  439. parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
  440. ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
  441. ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
  442. return std::make_unique<VersionInfoResource>(
  443. std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
  444. }
  445. Expected<Control> RCParser::parseControl() {
  446. // Each control definition (except CONTROL) follows one of the schemes below
  447. // depending on the control class:
  448. // [class] text, id, x, y, width, height [, style] [, exstyle] [, helpID]
  449. // [class] id, x, y, width, height [, style] [, exstyle] [, helpID]
  450. // Note that control ids must be integers.
  451. // Text might be either a string or an integer pointing to resource ID.
  452. ASSIGN_OR_RETURN(ClassResult, readIdentifier());
  453. std::string ClassUpper = ClassResult->upper();
  454. auto CtlInfo = Control::SupportedCtls.find(ClassUpper);
  455. if (CtlInfo == Control::SupportedCtls.end())
  456. return getExpectedError("control type, END or '}'", true);
  457. // Read caption if necessary.
  458. IntOrString Caption{StringRef()};
  459. if (CtlInfo->getValue().HasTitle) {
  460. ASSIGN_OR_RETURN(CaptionResult, readIntOrString());
  461. RETURN_IF_ERROR(consumeType(Kind::Comma));
  462. Caption = *CaptionResult;
  463. }
  464. ASSIGN_OR_RETURN(ID, readInt());
  465. RETURN_IF_ERROR(consumeType(Kind::Comma));
  466. IntOrString Class;
  467. Optional<IntWithNotMask> Style;
  468. if (ClassUpper == "CONTROL") {
  469. // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
  470. ASSIGN_OR_RETURN(ClassStr, readString());
  471. RETURN_IF_ERROR(consumeType(Kind::Comma));
  472. Class = *ClassStr;
  473. ASSIGN_OR_RETURN(StyleVal, parseIntExpr1());
  474. RETURN_IF_ERROR(consumeType(Kind::Comma));
  475. Style = *StyleVal;
  476. } else {
  477. Class = CtlInfo->getValue().CtlClass;
  478. }
  479. // x, y, width, height
  480. ASSIGN_OR_RETURN(Args, readIntsWithCommas(4, 4));
  481. if (ClassUpper != "CONTROL") {
  482. if (consumeOptionalType(Kind::Comma)) {
  483. ASSIGN_OR_RETURN(Val, parseIntExpr1());
  484. Style = *Val;
  485. }
  486. }
  487. Optional<uint32_t> ExStyle;
  488. if (consumeOptionalType(Kind::Comma)) {
  489. ASSIGN_OR_RETURN(Val, readInt());
  490. ExStyle = *Val;
  491. }
  492. Optional<uint32_t> HelpID;
  493. if (consumeOptionalType(Kind::Comma)) {
  494. ASSIGN_OR_RETURN(Val, readInt());
  495. HelpID = *Val;
  496. }
  497. return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
  498. (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
  499. }
  500. RCParser::ParseType RCParser::parseBitmapResource() {
  501. uint16_t MemoryFlags =
  502. parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
  503. ASSIGN_OR_RETURN(Arg, readFilename());
  504. return std::make_unique<BitmapResource>(*Arg, MemoryFlags);
  505. }
  506. RCParser::ParseType RCParser::parseIconResource() {
  507. uint16_t MemoryFlags =
  508. parseMemoryFlags(IconResource::getDefaultMemoryFlags());
  509. ASSIGN_OR_RETURN(Arg, readFilename());
  510. return std::make_unique<IconResource>(*Arg, MemoryFlags);
  511. }
  512. RCParser::ParseType RCParser::parseHTMLResource() {
  513. uint16_t MemoryFlags =
  514. parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
  515. ASSIGN_OR_RETURN(Arg, readFilename());
  516. return std::make_unique<HTMLResource>(*Arg, MemoryFlags);
  517. }
  518. RCParser::ParseType RCParser::parseMenuResource() {
  519. uint16_t MemoryFlags =
  520. parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
  521. ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
  522. ASSIGN_OR_RETURN(Items, parseMenuItemsList());
  523. return std::make_unique<MenuResource>(std::move(*OptStatements),
  524. std::move(*Items), MemoryFlags);
  525. }
  526. Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
  527. RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
  528. MenuDefinitionList List;
  529. // Read a set of items. Each item is of one of three kinds:
  530. // MENUITEM SEPARATOR
  531. // MENUITEM caption:String, result:Int [, menu flags]...
  532. // POPUP caption:String [, menu flags]... { items... }
  533. while (!consumeOptionalType(Kind::BlockEnd)) {
  534. ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
  535. bool IsMenuItem = ItemTypeResult->equals_insensitive("MENUITEM");
  536. bool IsPopup = ItemTypeResult->equals_insensitive("POPUP");
  537. if (!IsMenuItem && !IsPopup)
  538. return getExpectedError("MENUITEM, POPUP, END or '}'", true);
  539. if (IsMenuItem && isNextTokenKind(Kind::Identifier)) {
  540. // Now, expecting SEPARATOR.
  541. ASSIGN_OR_RETURN(SeparatorResult, readIdentifier());
  542. if (SeparatorResult->equals_insensitive("SEPARATOR")) {
  543. List.addDefinition(std::make_unique<MenuSeparator>());
  544. continue;
  545. }
  546. return getExpectedError("SEPARATOR or string", true);
  547. }
  548. // Not a separator. Read the caption.
  549. ASSIGN_OR_RETURN(CaptionResult, readString());
  550. // If MENUITEM, expect also a comma and an integer.
  551. uint32_t MenuResult = -1;
  552. if (IsMenuItem) {
  553. RETURN_IF_ERROR(consumeType(Kind::Comma));
  554. ASSIGN_OR_RETURN(IntResult, readInt());
  555. MenuResult = *IntResult;
  556. }
  557. ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr,
  558. MenuDefinition::OptionsFlags));
  559. if (IsPopup) {
  560. // If POPUP, read submenu items recursively.
  561. ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
  562. List.addDefinition(std::make_unique<PopupItem>(
  563. *CaptionResult, *FlagsResult, std::move(*SubMenuResult)));
  564. continue;
  565. }
  566. assert(IsMenuItem);
  567. List.addDefinition(
  568. std::make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
  569. }
  570. return std::move(List);
  571. }
  572. RCParser::ParseType RCParser::parseStringTableResource() {
  573. uint16_t MemoryFlags =
  574. parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
  575. ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
  576. RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
  577. auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
  578. MemoryFlags);
  579. // Read strings until we reach the end of the block.
  580. while (!consumeOptionalType(Kind::BlockEnd)) {
  581. // Each definition consists of string's ID (an integer) and a string.
  582. // Some examples in documentation suggest that there might be a comma in
  583. // between, however we strictly adhere to the single statement definition.
  584. ASSIGN_OR_RETURN(IDResult, readInt());
  585. consumeOptionalType(Kind::Comma);
  586. std::vector<StringRef> Strings;
  587. ASSIGN_OR_RETURN(StrResult, readString());
  588. Strings.push_back(*StrResult);
  589. while (isNextTokenKind(Kind::String))
  590. Strings.push_back(read().value());
  591. Table->addStrings(*IDResult, std::move(Strings));
  592. }
  593. return std::move(Table);
  594. }
  595. Expected<std::unique_ptr<VersionInfoBlock>>
  596. RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
  597. RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
  598. auto Contents = std::make_unique<VersionInfoBlock>(BlockName);
  599. while (!isNextTokenKind(Kind::BlockEnd)) {
  600. ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
  601. Contents->addStmt(std::move(*Stmt));
  602. }
  603. consume(); // Consume BlockEnd.
  604. return std::move(Contents);
  605. }
  606. Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
  607. // Expect either BLOCK or VALUE, then a name or a key (a string).
  608. ASSIGN_OR_RETURN(TypeResult, readIdentifier());
  609. if (TypeResult->equals_insensitive("BLOCK")) {
  610. ASSIGN_OR_RETURN(NameResult, readString());
  611. return parseVersionInfoBlockContents(*NameResult);
  612. }
  613. if (TypeResult->equals_insensitive("VALUE")) {
  614. ASSIGN_OR_RETURN(KeyResult, readString());
  615. // Read a non-empty list of strings and/or ints, each
  616. // possibly preceded by a comma. Unfortunately, the tool behavior depends
  617. // on them existing or not, so we need to memorize where we found them.
  618. std::vector<IntOrString> Values;
  619. BitVector PrecedingCommas;
  620. RETURN_IF_ERROR(consumeType(Kind::Comma));
  621. while (!isNextTokenKind(Kind::Identifier) &&
  622. !isNextTokenKind(Kind::BlockEnd)) {
  623. // Try to eat a comma if it's not the first statement.
  624. bool HadComma = Values.size() > 0 && consumeOptionalType(Kind::Comma);
  625. ASSIGN_OR_RETURN(ValueResult, readIntOrString());
  626. Values.push_back(*ValueResult);
  627. PrecedingCommas.push_back(HadComma);
  628. }
  629. return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
  630. std::move(PrecedingCommas));
  631. }
  632. return getExpectedError("BLOCK or VALUE", true);
  633. }
  634. Expected<VersionInfoResource::VersionInfoFixed>
  635. RCParser::parseVersionInfoFixed() {
  636. using RetType = VersionInfoResource::VersionInfoFixed;
  637. RetType Result;
  638. // Read until the beginning of the block.
  639. while (!isNextTokenKind(Kind::BlockBegin)) {
  640. ASSIGN_OR_RETURN(TypeResult, readIdentifier());
  641. auto FixedType = RetType::getFixedType(*TypeResult);
  642. if (!RetType::isTypeSupported(FixedType))
  643. return getExpectedError("fixed VERSIONINFO statement type", true);
  644. if (Result.IsTypePresent[FixedType])
  645. return getExpectedError("yet unread fixed VERSIONINFO statement type",
  646. true);
  647. // VERSION variations take multiple integers.
  648. size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
  649. ASSIGN_OR_RETURN(ArgsResult, readIntsWithCommas(1, NumInts));
  650. SmallVector<uint32_t, 4> ArgInts(ArgsResult->begin(), ArgsResult->end());
  651. while (ArgInts.size() < NumInts)
  652. ArgInts.push_back(0);
  653. Result.setValue(FixedType, ArgInts);
  654. }
  655. return Result;
  656. }
  657. RCParser::ParseOptionType RCParser::parseLanguageStmt() {
  658. ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
  659. return std::make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
  660. }
  661. RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
  662. ASSIGN_OR_RETURN(Arg, readInt());
  663. return std::make_unique<CharacteristicsStmt>(*Arg);
  664. }
  665. RCParser::ParseOptionType RCParser::parseVersionStmt() {
  666. ASSIGN_OR_RETURN(Arg, readInt());
  667. return std::make_unique<VersionStmt>(*Arg);
  668. }
  669. RCParser::ParseOptionType RCParser::parseCaptionStmt() {
  670. ASSIGN_OR_RETURN(Arg, readString());
  671. return std::make_unique<CaptionStmt>(*Arg);
  672. }
  673. RCParser::ParseOptionType RCParser::parseClassStmt() {
  674. ASSIGN_OR_RETURN(Arg, readIntOrString());
  675. return std::make_unique<ClassStmt>(*Arg);
  676. }
  677. RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
  678. assert(DialogType != OptStmtType::BasicStmt);
  679. ASSIGN_OR_RETURN(SizeResult, readInt());
  680. RETURN_IF_ERROR(consumeType(Kind::Comma));
  681. ASSIGN_OR_RETURN(NameResult, readString());
  682. // Default values for the optional arguments.
  683. uint32_t FontWeight = 0;
  684. bool FontItalic = false;
  685. uint32_t FontCharset = 1;
  686. if (DialogType == OptStmtType::DialogExStmt) {
  687. if (consumeOptionalType(Kind::Comma)) {
  688. ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 0, /* max = */ 3));
  689. if (Args->size() >= 1)
  690. FontWeight = (*Args)[0];
  691. if (Args->size() >= 2)
  692. FontItalic = (*Args)[1] != 0;
  693. if (Args->size() >= 3)
  694. FontCharset = (*Args)[2];
  695. }
  696. }
  697. return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
  698. FontItalic, FontCharset);
  699. }
  700. RCParser::ParseOptionType RCParser::parseStyleStmt() {
  701. ASSIGN_OR_RETURN(Arg, readInt());
  702. return std::make_unique<StyleStmt>(*Arg);
  703. }
  704. RCParser::ParseOptionType RCParser::parseExStyleStmt() {
  705. ASSIGN_OR_RETURN(Arg, readInt());
  706. return std::make_unique<ExStyleStmt>(*Arg);
  707. }
  708. Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
  709. return make_error<ParserError>(
  710. Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
  711. }
  712. } // namespace rc
  713. } // namespace llvm