Skip to content

Commit 0c0fb5d

Browse files
Fix generated .exe not working if the project name contains special characters (#5254)
1 parent 65a3358 commit 0c0fb5d

File tree

3 files changed

+49
-17
lines changed

3 files changed

+49
-17
lines changed

GDJS/GDJS/IDE/ExporterHelper.cpp

+45-13
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@ static void InsertUnique(std::vector<gd::String> &container, gd::String str) {
6969
container.push_back(str);
7070
}
7171

72+
static gd::String CleanProjectName(gd::String projectName) {
73+
gd::String partiallyCleanedProjectName = projectName;
74+
75+
static const gd::String forbiddenFileNameCharacters =
76+
"\\/:*?\"<>|"; // See
77+
// https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
78+
79+
for (size_t i = 0; i < partiallyCleanedProjectName.size();) {
80+
// Delete all characters that are not allowed in a filename
81+
if (forbiddenFileNameCharacters.find(partiallyCleanedProjectName[i]) !=
82+
gd::String::npos) {
83+
partiallyCleanedProjectName.erase(i, 1);
84+
} else {
85+
i++;
86+
}
87+
}
88+
89+
if (partiallyCleanedProjectName.empty())
90+
partiallyCleanedProjectName = "Project";
91+
92+
return partiallyCleanedProjectName;
93+
}
94+
7295
ExporterHelper::ExporterHelper(gd::AbstractFileSystem &fileSystem,
7396
gd::String gdjsRoot_,
7497
gd::String codeOutputDir_)
@@ -101,8 +124,9 @@ bool ExporterHelper::ExportProjectForPixiPreview(
101124
} else {
102125
// Most of the time, we skip the logo and minimum duration so that
103126
// the preview start as soon as possible.
104-
exportedProject.GetLoadingScreen().ShowGDevelopLogoDuringLoadingScreen(false).SetMinDuration(
105-
0);
127+
exportedProject.GetLoadingScreen()
128+
.ShowGDevelopLogoDuringLoadingScreen(false)
129+
.SetMinDuration(0);
106130
exportedProject.GetWatermark().ShowGDevelopWatermark(false);
107131
}
108132

@@ -308,16 +332,22 @@ bool ExporterHelper::ExportCordovaFiles(const gd::Project &project,
308332
}
309333

310334
// Splashscreen icon for Android 12+.
311-
gd::String splashScreenIconFilename = getIconFilename("android", "windowSplashScreenAnimatedIcon");
335+
gd::String splashScreenIconFilename =
336+
getIconFilename("android", "windowSplashScreenAnimatedIcon");
312337
if (!splashScreenIconFilename.empty())
313-
output += "<preference name=\"AndroidWindowSplashScreenAnimatedIcon\" value=\""
314-
+ splashScreenIconFilename + "\" />\n";
338+
output +=
339+
"<preference name=\"AndroidWindowSplashScreenAnimatedIcon\" "
340+
"value=\"" +
341+
splashScreenIconFilename + "\" />\n";
315342

316343
// Splashscreen "branding" image for Android 12+.
317-
gd::String splashScreenBrandingImageFilename = getIconFilename("android", "windowSplashScreenBrandingImage");
344+
gd::String splashScreenBrandingImageFilename =
345+
getIconFilename("android", "windowSplashScreenBrandingImage");
318346
if (!splashScreenBrandingImageFilename.empty())
319-
output += "<preference name=\"AndroidWindowSplashScreenBrandingImage\" value=\""
320-
+ splashScreenBrandingImageFilename + "\" />\n";
347+
output +=
348+
"<preference name=\"AndroidWindowSplashScreenBrandingImage\" "
349+
"value=\"" +
350+
splashScreenBrandingImageFilename + "\" />\n";
321351

322352
return output;
323353
};
@@ -458,11 +488,15 @@ bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
458488
->GetMangledSceneName(project.GetName())
459489
.LowerCase()
460490
.FindAndReplace(" ", "-")));
491+
// It's important to clean the project name from special characters,
492+
// otherwise Windows executable may be corrupted when electron builds it.
493+
gd::String jsonCleanedName = gd::Serializer::ToJSON(
494+
gd::SerializerElement(CleanProjectName(project.GetName())));
461495

462496
{
463497
gd::String str =
464498
fs.ReadFile(gdjsRoot + "/Runtime/Electron/package.json")
465-
.FindAndReplace("\"GDJS_GAME_NAME\"", jsonName)
499+
.FindAndReplace("\"GDJS_GAME_NAME\"", jsonCleanedName)
466500
.FindAndReplace("\"GDJS_GAME_PACKAGE_NAME\"", jsonPackageName)
467501
.FindAndReplace("\"GDJS_GAME_AUTHOR\"", jsonAuthor)
468502
.FindAndReplace("\"GDJS_GAME_VERSION\"", jsonVersion)
@@ -651,10 +685,8 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
651685
InsertUnique(includesFiles, "pixi-renderers/pixi-bitmapfont-manager.js");
652686
InsertUnique(includesFiles,
653687
"pixi-renderers/spriteruntimeobject-pixi-renderer.js");
654-
InsertUnique(includesFiles,
655-
"pixi-renderers/CustomObjectPixiRenderer.js");
656-
InsertUnique(includesFiles,
657-
"pixi-renderers/DebuggerPixiRenderer.js");
688+
InsertUnique(includesFiles, "pixi-renderers/CustomObjectPixiRenderer.js");
689+
InsertUnique(includesFiles, "pixi-renderers/DebuggerPixiRenderer.js");
658690
InsertUnique(includesFiles,
659691
"pixi-renderers/loadingscreen-pixi-renderer.js");
660692
InsertUnique(includesFiles, "pixi-renderers/pixi-effects-manager.js");

GDJS/GDJS/IDE/ExporterHelper.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ struct PreviewExportOptions {
152152
}
153153

154154
/**
155-
* Set the token to use by the game engine when requiring any resource stored on
156-
* GDevelop Cloud buckets. Note that this is only useful during previews.
155+
* Set the token to use by the game engine when requiring any resource stored
156+
* on GDevelop Cloud buckets. Note that this is only useful during previews.
157157
*/
158158
PreviewExportOptions &SetGDevelopResourceToken(
159159
const gd::String &gdevelopResourceToken_) {

newIDE/app/src/Export/ExportDialog/ExportLauncher.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export default class ExportLauncher extends Component<Props, State> {
263263
t`A game with this ID already exists and you are not the owner.`
264264
),
265265
i18n._(
266-
t`A test link will be created but the game will not be registered.`
266+
t`A link or file will be created but the game will not be registered.`
267267
),
268268
].join('\n\n'),
269269
rawError: registerError,
@@ -279,7 +279,7 @@ export default class ExportLauncher extends Component<Props, State> {
279279
t`You have reached the maximum number of games you can register! You can unregister games in your Games Dashboard.`
280280
),
281281
i18n._(
282-
t`A test link will be created but the game will not be registered.`
282+
t`A link or file will be created but the game will not be registered.`
283283
),
284284
].join('\n\n'),
285285
rawError: registerError,

0 commit comments

Comments
 (0)