From 42a7941db7af260a169341051e4db620f7d97190 Mon Sep 17 00:00:00 2001 From: LJ <23249107+LJNeon@users.noreply.github.com> Date: Sun, 16 Feb 2025 02:07:40 -0700 Subject: [PATCH] Fix invalid filenames upon loading save (#1147) --- src/Paths/Directory.ts | 6 ++--- src/utils/SaveDataMigrationUtils.ts | 38 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Paths/Directory.ts b/src/Paths/Directory.ts index 55e850ede..f1b6c519d 100644 --- a/src/Paths/Directory.ts +++ b/src/Paths/Directory.ts @@ -24,11 +24,11 @@ export const root = "" as Directory; * |: Invalid because it might have a use in the terminal in the future. * #: Invalid because it might have a use in the terminal in the future. * (quote marks): Invalid to avoid conflict with quote marks used in the terminal. - * (space): Invalid to avoid confusion with terminal command separator */ -const invalidCharacters = ["/", "*", "?", "[", "]", "!", "\\", "~", "|", "#", '"', "'", " "]; + * (whitespace): Invalid to avoid confusion with terminal command separator */ +const invalidCharacters = ["/", "*", "?", "[", "]", "!", "\\", "~", "|", "#", '"', "'"]; /** A valid character is any character that is not one of the invalid characters */ -export const oneValidCharacter = `[^${escapeRegExp(invalidCharacters.join(""))}]`; +export const oneValidCharacter = `[^${escapeRegExp(invalidCharacters.join(""))}\\s]`; /** Regex string for matching the directory part of a valid filepath */ export const directoryRegexString = `^(?(?:${oneValidCharacter}+\\/)*)`; diff --git a/src/utils/SaveDataMigrationUtils.ts b/src/utils/SaveDataMigrationUtils.ts index 196624d23..f67dc9076 100644 --- a/src/utils/SaveDataMigrationUtils.ts +++ b/src/utils/SaveDataMigrationUtils.ts @@ -24,6 +24,8 @@ import { safelyCreateUniqueServer } from "../Server/ServerHelpers"; import { v2APIBreak } from "./v2APIBreak"; import { Terminal } from "../Terminal"; import { getRecordValues } from "../Types/Record"; +import { ServerName } from "../Types/strings"; +import { ContentFilePath, ContentFile, ContentFileMap } from "../Paths/ContentFile"; import { exportMaterial } from "../Corporation/Actions"; import { getGoSave, loadGo } from "../Go/SaveLoad"; import { showAPIBreaks } from "./APIBreaks/APIBreak"; @@ -37,6 +39,25 @@ function convert(code: string, changes: [RegExp, string][]): string { return code; } +/** Function for removing whitespace from filenames. See 41 for usage */ +function removeWhitespace(hostname: ServerName, file: ContentFile, files: ContentFileMap): void { + let filename = file.filename.replace(/\s+/g, "-") as ContentFilePath; + // avoid filename conflicts + if (files.has(filename)) { + const idx = filename.lastIndexOf("."); + const path = filename.slice(0, idx); + const ext = filename.slice(idx); + let i = 1; + do { + filename = `${path}-${i++}${ext}` as ContentFilePath; + } while (files.has(filename)); + } + console.warn(`Renamed "${file.filename}" to "${filename}" on ${hostname}.`); + files.delete(file.filename); + file.filename = filename; + files.set(file.filename, file); +} + // Makes necessary changes to the loaded/imported data to ensure // the game stills works with new versions export function evaluateVersionCompatibility(ver: string | number): void { @@ -507,4 +528,21 @@ Error: ${e}`, if (ver < 39) { showAPIBreaks("2.6.1", ...breakInfos261); } + if (ver <= 41) { + // All whitespace except for spaces was allowed in filenames + let found = false; + for (const server of GetAllServers()) { + for (const script of server.scripts.values()) { + if (!/\s/.test(script.filename)) continue; + removeWhitespace(server.hostname, script, server.scripts); + found = true; + } + for (const textFile of server.textFiles.values()) { + if (!/\s/.test(textFile.filename)) continue; + removeWhitespace(server.hostname, textFile, server.textFiles); + found = true; + } + } + if (found) Terminal.error("Filenames with whitespace found and corrected, see console for details."); + } }