public static IsFileFilterValid ( string filter ) : bool | ||
filter | string | File filter string to test |
return | bool |
private List <LogInfo> CheckInterfaceSection(ScriptSection section, string rawLine = null, int lineIdx = 0) { // If this section was already visited, return. if (_visitedSections.Contains(section.Name)) { return(new List <LogInfo>()); } _visitedSections.Add(section.Name); // Force parsing of code, bypassing caching by section.GetUICtrls() string[] lines = section.Lines; if (lines == null) { string msg = $"Section [{section.Name}] is not a valid interface section"; if (rawLine != null) { msg += $" ({rawLine})"; } if (0 < lineIdx) { msg += $" (Line {lineIdx})"; } return(new List <LogInfo> { new LogInfo(LogState.Error, msg) }); } (List <UIControl> uiCtrls, List <LogInfo> logs) = UIParser.ParseStatements(lines, section); foreach (UIControl uiCtrl in uiCtrls) { switch (uiCtrl.Type) { case UIControlType.CheckBox: { UIInfo_CheckBox info = uiCtrl.Info.Cast <UIInfo_CheckBox>(); if (info.SectionName != null) { if (_sc.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(CheckCodeSection(_sc.Sections[info.SectionName], uiCtrl.RawLine, uiCtrl.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{info.SectionName}] does not exist", uiCtrl)); } } } break; case UIControlType.ComboBox: { UIInfo_ComboBox info = uiCtrl.Info.Cast <UIInfo_ComboBox>(); // Practically, this means info.Index is -1 -> uiCtrl.Text not being one of info.Items if (info.Index < 0 || info.Items.Count <= info.Index) { logs.Add(new LogInfo(LogState.Warning, $"Incorrect selected value [{uiCtrl.Text}]", uiCtrl)); } } break; case UIControlType.Image: { // Check encoded image string imageSection = StringEscaper.Unescape(uiCtrl.Text); if (!imageSection.Equals(UIInfo_Image.NoResource, StringComparison.OrdinalIgnoreCase) && !EncodedFile.ContainsInterface(_sc, imageSection)) { logs.Add(new LogInfo(LogState.Warning, $"Image resource [{imageSection}] does not exist", uiCtrl)); } UIInfo_Image info = uiCtrl.Info.Cast <UIInfo_Image>(); // Check if image control have empty or invalid url. // Ex) Colors_Image=ThemeColors.jpg,1,5,11,228,260,80, if (info.Url != null) { string url = StringEscaper.Unescape(info.Url); if (!StringEscaper.IsUrlValid(url)) { if (url.IndexOf("://", StringComparison.Ordinal) != -1) { logs.Add(new LogInfo(LogState.Warning, $"Incorrect URL [{url}]", uiCtrl)); } else { logs.Add(new LogInfo(LogState.Warning, "URL does not have a scheme. Did you omit \"http(s)://\"?", uiCtrl)); } } } } break; case UIControlType.TextFile: { string textSection = StringEscaper.Unescape(uiCtrl.Text); if (!textSection.Equals(UIInfo_TextFile.NoResource, StringComparison.OrdinalIgnoreCase) && !EncodedFile.ContainsInterface(_sc, textSection)) { logs.Add(new LogInfo(LogState.Warning, $"Text resource [{textSection}] does not exist", uiCtrl)); } } break; case UIControlType.Button: { UIInfo_Button info = uiCtrl.Info.Cast <UIInfo_Button>(); string pictureSection = info.Picture; if (pictureSection != null && !pictureSection.Equals(UIInfo_Button.NoPicture, StringComparison.OrdinalIgnoreCase) && !EncodedFile.ContainsInterface(_sc, pictureSection)) { if (pictureSection.Length == 0) // Due to quirks of WinBuilder's editor, many buttons have '' instead of '0' in the place of <Picture>. { logs.Add(new LogInfo(LogState.Warning, "Image resource entry is empty. Use [0] to represent not having an image resource.", uiCtrl)); } else { logs.Add(new LogInfo(LogState.Warning, $"Image resource [{pictureSection}] does not exist", uiCtrl)); } } if (info.SectionName != null) { if (_sc.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(CheckCodeSection(_sc.Sections[info.SectionName], uiCtrl.RawLine, uiCtrl.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{info.SectionName}] does not exist", uiCtrl)); } } } break; case UIControlType.WebLabel: { UIInfo_WebLabel info = uiCtrl.Info.Cast <UIInfo_WebLabel>(); // Sometime developers forget to put proper scheme in WebLabel's url. // Ex) PStart_WebLabel="PStart Homepage",1,10,668,122,98,18,www.pegtop.de/start/ string url = StringEscaper.Unescape(info.Url); if (!StringEscaper.IsUrlValid(url)) { if (url.IndexOf("://", StringComparison.Ordinal) != -1) { logs.Add(new LogInfo(LogState.Warning, $"Incorrect URL [{url}]", uiCtrl)); } else { logs.Add(new LogInfo(LogState.Warning, "URL does not have scheme. Did you omit \"http(s)://\"?", uiCtrl)); } } } break; case UIControlType.RadioButton: { UIInfo_RadioButton info = uiCtrl.Info.Cast <UIInfo_RadioButton>(); if (info.SectionName != null) { if (_sc.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(CheckCodeSection(_sc.Sections[info.SectionName], uiCtrl.RawLine, uiCtrl.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{info.SectionName}] does not exist", uiCtrl)); } } } break; case UIControlType.FileBox: { UIInfo_FileBox info = uiCtrl.Info.Cast <UIInfo_FileBox>(); if (info.IsFile) { // Select File if (info.Filter != null) { string filter = StringEscaper.Unescape(info.Filter); if (StringEscaper.IsFileFilterValid(filter) == false) { logs.Add(new LogInfo(LogState.Warning, $"File filter pattern [{filter}] is invalid", uiCtrl)); } } } else { // Select Folder if (info.Filter != null) { logs.Add(new LogInfo(LogState.Warning, $"File filters cannot be used for folder selection", uiCtrl)); } } } break; case UIControlType.RadioGroup: { UIInfo_RadioGroup info = uiCtrl.Info.Cast <UIInfo_RadioGroup>(); if (info.SectionName != null) { if (_sc.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(CheckCodeSection(_sc.Sections[info.SectionName], uiCtrl.RawLine, uiCtrl.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{info.SectionName}] does not exist", uiCtrl)); } } // Practically, this means info.Index is -1 -> uiCtrl.Text not being one of info.Items if (info.Selected < 0 || info.Items.Count <= info.Selected) { logs.Add(new LogInfo(LogState.Warning, $"Incorrect selected index [{info.Selected}]", uiCtrl)); } } break; } } return(logs); }
private void RecursiveFindCodeSection(IReadOnlyList <CodeCommand> codes, List <LogInfo> logs) { string targetCodeSection = null; string targetInterfaceSection = null; foreach (CodeCommand cmd in codes) { switch (cmd.Type) { #region Check CodeSections case CodeType.If: { CodeInfo_If info = cmd.Info.Cast <CodeInfo_If>(); if (info.Condition.Type == BranchConditionType.ExistSection) { // For recursive section call // Ex) If,ExistSection,%ScriptFile%,DoWork,Run,%ScriptFile%,DoWork if (info.Condition.Arg1.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && info.Embed.Type == CodeType.Run || info.Embed.Type == CodeType.RunEx || info.Embed.Type == CodeType.Exec) { CodeInfo_RunExec subInfo = info.Embed.Info.Cast <CodeInfo_RunExec>(); if (subInfo.ScriptFile.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase)) { if (info.Condition.Arg2.Equals(subInfo.SectionName, StringComparison.OrdinalIgnoreCase)) { continue; } } } } RecursiveFindCodeSection(info.Link, logs); } break; case CodeType.Else: { CodeInfo_Else info = cmd.Info.Cast <CodeInfo_Else>(); RecursiveFindCodeSection(info.Link, logs); } break; case CodeType.Run: case CodeType.Exec: case CodeType.RunEx: { CodeInfo_RunExec info = cmd.Info.Cast <CodeInfo_RunExec>(); // CodeValidator does not have Variable information, so just check with predefined literal if (info.ScriptFile.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && !CodeParser.StringContainsVariable(info.SectionName)) { targetCodeSection = info.SectionName; } } break; case CodeType.Loop: case CodeType.LoopLetter: case CodeType.LoopEx: case CodeType.LoopLetterEx: { CodeInfo_Loop info = cmd.Info.Cast <CodeInfo_Loop>(); if (info.Break) { continue; } // CodeValidator does not have Variable information, so just check with predefined literal if (info.ScriptFile.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && !CodeParser.StringContainsVariable(info.SectionName)) { targetCodeSection = info.SectionName; } } break; case CodeType.UserInput: { CodeInfo_UserInput info = cmd.Info.Cast <CodeInfo_UserInput>(); UserInputType type = info.Type; switch (type) { case UserInputType.DirPath: case UserInputType.FilePath: { UserInputInfo_DirFile subInfo = info.SubInfo.Cast <UserInputInfo_DirFile>(); if (info.Type == UserInputType.FilePath) { // Select File if (subInfo.Filter != null) { string filter = StringEscaper.Unescape(subInfo.Filter); if (StringEscaper.IsFileFilterValid(filter) == false) { logs.Add(new LogInfo(LogState.Error, $"File filter pattern [{filter}] is invalid", cmd)); } } } else { // Select Folder if (subInfo.Filter != null) { logs.Add(new LogInfo(LogState.Warning, $"File filters cannot be used for folder selection", cmd)); } } } break; } } break; #endregion #region Check InterfaceSections case CodeType.AddInterface: { CodeInfo_AddInterface info = cmd.Info.Cast <CodeInfo_AddInterface>(); // CodeValidator does not have Variable information, so just check with predefined literal if (info.ScriptFile.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && !CodeParser.StringContainsVariable(info.Section)) { targetInterfaceSection = info.Section; } } break; case CodeType.ReadInterface: { CodeInfo_ReadInterface info = cmd.Info.Cast <CodeInfo_ReadInterface>(); // CodeValidator does not have Variable information, so just check with predefined literal if (info.ScriptFile.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && !CodeParser.StringContainsVariable(info.Section)) { targetInterfaceSection = info.Section; } } break; case CodeType.WriteInterface: { CodeInfo_WriteInterface info = cmd.Info.Cast <CodeInfo_WriteInterface>(); // CodeValidator does not have Variable information, so just check with predefined literal if (info.ScriptFile.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && !CodeParser.StringContainsVariable(info.Section)) { targetInterfaceSection = info.Section; } } break; case CodeType.IniWrite: { // To detect multi-interface without `InterfaceList=`, // Inspect pattern `IniWrite,%ScriptFile%,Main,Interface,<NewInterfaceSection>` CodeInfo_IniWrite info = cmd.Info.Cast <CodeInfo_IniWrite>(); // CodeValidator does not have Variable information, so just check with predefined literal if (info.FileName.Equals(Script.Const.ScriptFile, StringComparison.OrdinalIgnoreCase) && info.Section.Equals(ScriptSection.Names.Main, StringComparison.OrdinalIgnoreCase) && info.Key.Equals(ScriptSection.Names.Interface, StringComparison.OrdinalIgnoreCase) && !CodeParser.StringContainsVariable(info.Value)) { targetInterfaceSection = info.Value; } } break; #endregion } if (targetCodeSection != null) { if (_sc.Sections.ContainsKey(targetCodeSection)) { logs.AddRange(CheckCodeSection(_sc.Sections[targetCodeSection], cmd.RawCode, cmd.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{targetCodeSection}] does not exist", cmd)); } } if (targetInterfaceSection != null) { if (_sc.Sections.ContainsKey(targetInterfaceSection)) { logs.AddRange(CheckInterfaceSection(_sc.Sections[targetInterfaceSection], cmd.RawCode, cmd.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{targetInterfaceSection}] does not exist", cmd)); } } } }