Skip to content

Commit 6f41510

Browse files
authored
[llvm-rc] Accept filenames provided as multiple string literals (#68881)
GNU windres supports this, while MS rc.exe doesn't. MS rc.exe only supports treating consecutive string literals as if they were fused into one in a few fixed locations (most of which are already supported), while GNU windres supports this essentially anywhere in any string. See b989fcb for one recent change that extended support for this in one specific resource. A reasonable use case for multiple concatenated string literals that GNU windres accepts is `1 ICON DIR "/name.ico"`, where the directory is provided via the preprocessor, expanding to another string literal; this is #51286. Extend the parser to try to consume all consecutive string tokens, whenever reading a filename. Adjust the handling of user data resources read from a file to use the readFilename() helper. While this probably doesn't cover every single case where GNU windres might accept concatenated string literals, this is the primary missing case that has been reported so far.
1 parent 4bf10f3 commit 6f41510

File tree

4 files changed

+35
-4
lines changed

4 files changed

+35
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
100 ICON "subdir" "/icon-new.ico"
2+
101 24 "subdir" "/empty.manifest"
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
; RUN: rm -rf %t
2+
; RUN: mkdir %t
3+
; RUN: cd %t
4+
; RUN: mkdir subdir
5+
; RUN: cp %p/Inputs/icon-new.ico subdir
6+
; RUN: touch subdir/empty.manifest
7+
; RUN: llvm-windres --no-preprocess %p/Inputs/split-path.rc %t/split-path.res

llvm/tools/llvm-rc/ResourceScriptParser.cpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,24 @@ Expected<StringRef> RCParser::readString() {
238238
Expected<StringRef> RCParser::readFilename() {
239239
if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
240240
return getExpectedError("string");
241-
return read().value();
241+
const RCToken &Token = read();
242+
StringRef Str = Token.value();
243+
if (Token.kind() != Kind::String)
244+
return Str;
245+
while (isNextTokenKind(Kind::String)) {
246+
const RCToken &NextToken = read();
247+
StringRef Next = NextToken.value();
248+
bool IsWide = Str.consume_front_insensitive("L");
249+
Next.consume_front_insensitive("L");
250+
bool StrUnquoted = Str.consume_front("\"") && Str.consume_back("\"");
251+
bool NextUnquoted = Next.consume_front("\"") && Next.consume_back("\"");
252+
assert(StrUnquoted && NextUnquoted);
253+
(void)StrUnquoted;
254+
(void)NextUnquoted;
255+
256+
Str = Saver.save(Twine(IsWide ? "L" : "") + "\"" + Str + Next + "\"");
257+
}
258+
return Str;
242259
}
243260

244261
Expected<StringRef> RCParser::readIdentifier() {
@@ -499,9 +516,10 @@ RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
499516
// Check if this is a file resource.
500517
switch (look().kind()) {
501518
case Kind::String:
502-
case Kind::Identifier:
503-
return std::make_unique<UserDefinedResource>(Type, read().value(),
504-
MemoryFlags);
519+
case Kind::Identifier: {
520+
ASSIGN_OR_RETURN(Filename, readFilename());
521+
return std::make_unique<UserDefinedResource>(Type, *Filename, MemoryFlags);
522+
}
505523
default:
506524
break;
507525
}

llvm/tools/llvm-rc/ResourceScriptParser.h

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "ResourceScriptToken.h"
1919

2020
#include "llvm/Support/Compiler.h"
21+
#include "llvm/Support/StringSaver.h"
2122
#include "llvm/Support/raw_ostream.h"
2223

2324
#include <system_error>
@@ -185,6 +186,9 @@ class RCParser {
185186
std::vector<RCToken> Tokens;
186187
LocIter CurLoc;
187188
const LocIter End;
189+
190+
BumpPtrAllocator Alloc;
191+
StringSaver Saver{Alloc};
188192
};
189193

190194
} // namespace rc

0 commit comments

Comments
 (0)