Skip to content

[llvm-rc] Concatenate consecutive string tokens in windres mode #68685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/test/tools/llvm-rc/Inputs/split-path.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
100 ICON "subdir" "/icon-new.ico"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"narrow" L"wide"
3 changes: 3 additions & 0 deletions llvm/test/tools/llvm-rc/Inputs/tokens-windres.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
L"wide" " also wide",
"narrow" " also narrow",
L"wide" L" more wide",
6 changes: 6 additions & 0 deletions llvm/test/tools/llvm-rc/split-path.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
; RUN: rm -rf %t
; RUN: mkdir %t
; RUN: cd %t
; RUN: mkdir subdir
; RUN: cp %p/Inputs/icon-new.ico subdir
; RUN: llvm-windres --no-preprocess %p/Inputs/split-path.rc %t/split-path.res
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-rc/windres-format.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
; from file suffixes.

; RUN: rm -f %t.res
; RUN: llvm-windres --no-preprocess %p/Inputs/tag-stringtable-basic.rc %t.res
; RUN: llvm-windres --no-preprocess %p/Inputs/tag-versioninfo.rc %t.res
; RUN: llvm-readobj %t.res | FileCheck %s --check-prefix=CHECK-RES

; RUN: rm -f %t.o
; RUN: llvm-windres --no-preprocess -F pe-x86-64 %p/Inputs/tag-stringtable-basic.rc %t.o
; RUN: llvm-windres --no-preprocess -F pe-x86-64 %p/Inputs/tag-versioninfo.rc %t.o
; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefix=CHECK-OBJ

; RUN: rm -f %t.obj
Expand All @@ -16,7 +16,7 @@
; Check that we can specify the input/output file types explicitly.
; Also check options for specifying the input/output file names.

; RUN: cat %p/Inputs/tag-stringtable-basic.rc > %t-anonymous
; RUN: cat %p/Inputs/tag-versioninfo.rc > %t-anonymous
; RUN: rm -f %t-anonymous2
; RUN: llvm-windres --no-preprocess -O res -J rc -o %t-anonymous2 -i %t-anonymous
; RUN: llvm-readobj %t-anonymous2 | FileCheck %s --check-prefix=CHECK-RES
Expand All @@ -25,7 +25,7 @@
; RUN: llvm-windres -F pe-x86-64 -J res -O coff -i%t-anonymous2 -o%t-anonymous3
; RUN: llvm-readobj --coff-resources %t-anonymous3 | FileCheck %s --check-prefix=CHECK-OBJ

; CHECK-RES: Resource type (int): STRINGTABLE
; CHECK-RES: Resource type (int):

; CHECK-OBJ: Format: COFF-x86-64
; CHECK-OBJ: Resources [
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-rc/windres-prefix.test
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

; Check that the triple prefix also affects the output object file type.

; RUN: %t/aarch64-w64-mingw32-windres --no-preprocess %p/Inputs/tag-stringtable-basic.rc %t.o
; RUN: %t/aarch64-w64-mingw32-windres --no-preprocess %p/Inputs/tag-versioninfo.rc %t.o
; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefix=CHECK-OBJ

; CHECK-OBJ: Format: COFF-ARM64
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-rc/windres-target.test
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

; Check the actual written object types.

; RUN: llvm-windres --no-preprocess -F i686-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o
; RUN: llvm-windres --no-preprocess -F i686-w64-mingw32 %p/Inputs/tag-versioninfo.rc %t.o
; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-I686
; RUN: llvm-windres --no-preprocess -F x86_64-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o
; RUN: llvm-windres --no-preprocess -F x86_64-w64-mingw32 %p/Inputs/tag-versioninfo.rc %t.o
; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-X86-64
; RUN: llvm-windres --no-preprocess -F armv7-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o
; RUN: llvm-windres --no-preprocess -F armv7-w64-mingw32 %p/Inputs/tag-versioninfo.rc %t.o
; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-ARMV7
; RUN: llvm-windres --no-preprocess -F aarch64-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o
; RUN: llvm-windres --no-preprocess -F aarch64-w64-mingw32 %p/Inputs/tag-versioninfo.rc %t.o
; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-AARCH64

; CHECK-OBJ-I686: Format: COFF-i386
Expand Down
13 changes: 13 additions & 0 deletions llvm/test/tools/llvm-rc/windres-tokenizer.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
; RUN: not llvm-windres --no-preprocess --verbose %p/Inputs/tokens-windres.rc %t.res | FileCheck %s
; llvm-windres fails on this sample because it is an invalid resource file
; script. We silence the error message and just analyze the output.

; CHECK: String: L"wide also wide"
; CHECK-NEXT: Comma: ,
; CHECK-NEXT: String: "narrow also narrow"
; CHECK-NEXT: Comma: ,
; CHECK-NEXT: String: L"wide more wide"

; RUN: not llvm-windres --no-preprocess --verbose %p/Inputs/tokens-windres-invalid-concat.rc %t.res 2>&1 | FileCheck %s --check-prefix=CONCAT-ERROR

; CONCAT-ERROR: Error parsing file: Cannot concatenate a wide string L"wide" after a narrow one "narrow"
55 changes: 52 additions & 3 deletions llvm/tools/llvm-rc/ResourceScriptToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ namespace {

class Tokenizer {
public:
Tokenizer(StringRef Input) : Data(Input), DataLength(Input.size()), Pos(0) {}
Tokenizer(StringRef Input, StringSaver &Saver, bool IsWindres)
: Data(Input), DataLength(Input.size()), Pos(0), Saver(Saver),
IsWindres(IsWindres) {}

Expected<std::vector<RCToken>> run();

Expand Down Expand Up @@ -141,8 +143,14 @@ class Tokenizer {
// an identifier describing a block start or end.
void processIdentifier(RCToken &token) const;

Expected<RCToken> mergeStringTokens(const RCToken &FirstToken,
const RCToken &SecondToken);

StringRef Data;
size_t DataLength, Pos;

StringSaver &Saver;
bool IsWindres;
};

void Tokenizer::skipCurrentLine() {
Expand Down Expand Up @@ -188,6 +196,16 @@ Expected<std::vector<RCToken>> Tokenizer::run() {
return getStringError("Integer invalid or too large: " +
Token.value().str());
}
} else if (TokenKind == Kind::String && !Result.empty() && IsWindres) {
RCToken &Prev = Result.back();
if (Prev.kind() == Kind::String) {
Expected<RCToken> MergedToken = mergeStringTokens(Prev, Token);
if (!MergedToken)
return MergedToken.takeError();
// Remove the old token and replace the new one with the merged token.
Result.pop_back();
Token = *MergedToken;
}
}

Result.push_back(Token);
Expand Down Expand Up @@ -356,12 +374,43 @@ void Tokenizer::processIdentifier(RCToken &Token) const {
Token = RCToken(Kind::BlockEnd, Name);
}

Expected<RCToken> Tokenizer::mergeStringTokens(const RCToken &FirstToken,
const RCToken &SecondToken) {
assert(FirstToken.kind() == Kind::String &&
SecondToken.kind() == Kind::String);
StringRef First = FirstToken.value();
StringRef Second = SecondToken.value();
bool IsFirstLong = First.starts_with_insensitive("L");
bool IsSecondLong = Second.starts_with_insensitive("L");
// "aaa" "bbb" = "aaabbb"
// L"aaa" L"bbb" = L"aaabbb"
// L"aaa" "bbb" = L"aaabbb"
// "aaa" L"bbb" = <error>
if (IsSecondLong && !IsFirstLong)
return getStringError("Cannot concatenate a wide string " + Twine(Second) +
" after a narrow one " + Twine(First));
if (IsFirstLong)
First = First.drop_front();
if (IsSecondLong)
Second = Second.drop_front();
bool FirstUnquoted = First.consume_front("\"") && First.consume_back("\"");
bool SecondUnquoted = Second.consume_front("\"") && Second.consume_back("\"");
assert(FirstUnquoted && SecondUnquoted);
(void)FirstUnquoted;
(void)SecondUnquoted;

StringRef MergedString =
Saver.save(Twine(IsFirstLong ? "L" : "") + "\"" + First + Second + "\"");
return RCToken(Kind::String, MergedString);
}

} // anonymous namespace

namespace llvm {

Expected<std::vector<RCToken>> tokenizeRC(StringRef Input) {
return Tokenizer(Input).run();
Expected<std::vector<RCToken>> tokenizeRC(StringRef Input, StringSaver &Saver,
bool IsWindres) {
return Tokenizer(Input, Saver, IsWindres).run();
}

} // namespace llvm
4 changes: 3 additions & 1 deletion llvm/tools/llvm-rc/ResourceScriptToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/StringSaver.h"

#include <cstdint>
#include <map>
Expand Down Expand Up @@ -74,7 +75,8 @@ class RCToken {
// Tokens returned by this function hold only references to the parts
// of the Input. Memory buffer containing Input cannot be freed,
// modified or reallocated.
Expected<std::vector<RCToken>> tokenizeRC(StringRef Input);
Expected<std::vector<RCToken>> tokenizeRC(StringRef Input, StringSaver &Saver,
bool IsWindres);

} // namespace llvm

Expand Down
6 changes: 5 additions & 1 deletion llvm/tools/llvm-rc/llvm-rc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,11 @@ void doRc(std::string Src, std::string Dest, RcOptions &Opts,
StringRef Contents = FileContents->getBuffer();

std::string FilteredContents = filterCppOutput(Contents);
std::vector<RCToken> Tokens = ExitOnErr(tokenizeRC(FilteredContents));

BumpPtrAllocator Alloc;
StringSaver Saver(Alloc);
std::vector<RCToken> Tokens =
ExitOnErr(tokenizeRC(FilteredContents, Saver, Opts.IsWindres));

if (Opts.BeVerbose) {
const Twine TokenNames[] = {
Expand Down