private List <LogInfo> ValidateUISection(ScriptSection section) { // Force parsing of code, bypassing caching by section.GetUICtrls() List <string> lines = section.GetLines(); SectionAddress addr = new SectionAddress(p, section); List <UIControl> uiCtrls = UIParser.ParseRawLines(lines, addr, out List <LogInfo> logs); foreach (UIControl uiCmd in uiCtrls) { switch (uiCmd.Type) { case UIControlType.CheckBox: { Debug.Assert(uiCmd.Info.GetType() == typeof(UIInfo_CheckBox)); UIInfo_CheckBox info = uiCmd.Info as UIInfo_CheckBox; if (info.SectionName != null) { if (p.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(ValidateCodeSection(p.Sections[info.SectionName])); } } } break; case UIControlType.Button: { Debug.Assert(uiCmd.Info.GetType() == typeof(UIInfo_Button)); UIInfo_Button info = uiCmd.Info as UIInfo_Button; if (info.SectionName != null) { if (p.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(ValidateCodeSection(p.Sections[info.SectionName])); } } } break; case UIControlType.RadioButton: { Debug.Assert(uiCmd.Info.GetType() == typeof(UIInfo_RadioButton)); UIInfo_RadioButton info = uiCmd.Info as UIInfo_RadioButton; if (info.SectionName != null) { if (p.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(ValidateCodeSection(p.Sections[info.SectionName])); } } } break; } } return(logs); }
public static UICommand ParseUICommand(List <string> rawLines, SectionAddress addr, ref int idx) { UIType type = UIType.None; string rawLine = rawLines[idx].Trim(); // Check if rawCode is Empty if (rawLine.Equals(string.Empty)) { return(new UICommand(rawLine, addr, string.Empty)); } // Comment Format : starts with '//' or '#', ';' if (rawLine.StartsWith("//") || rawLine.StartsWith("#") || rawLine.StartsWith(";")) { return(new UICommand(rawLine, addr, string.Empty)); } // Find key of interface control string key = string.Empty; string rawValue = string.Empty; int equalIdx = rawLine.IndexOf('='); if (equalIdx != -1) { key = rawLine.Substring(0, equalIdx); rawValue = rawLine.Substring(equalIdx + 1); } else { throw new InvalidCommandException($"Interface control [{rawValue}] does not have name", rawLine); } // Parse Arguments List <string> args = new List <string>(); try { string remainder = rawValue; while (remainder != null) { Tuple <string, string> tuple = CodeParser.GetNextArgument(remainder); args.Add(tuple.Item1); remainder = tuple.Item2; } } catch (InvalidCommandException e) { throw new InvalidCommandException(e.Message, rawLine); } // Check doublequote's occurence - must be 2n if (StringHelper.CountOccurrences(rawValue, "\"") % 2 == 1) { throw new InvalidCommandException($"Interface control [{rawValue}]'s doublequotes mismatch", rawLine); } // Check if last operand is \ - MultiLine check - only if one or more operands exists if (0 < args.Count) { while (args.Last().Equals(@"\", StringComparison.OrdinalIgnoreCase)) { // Split next line and append to List<string> operands if (rawLines.Count <= idx) // Section ended with \, invalid grammar! { throw new InvalidCommandException($@"Last interface control [{rawValue}] cannot end with '\' ", rawLine); } idx++; args.AddRange(rawLines[idx].Trim().Split(',')); } } // UICommand should have at least 7 operands // Text, Visibility, Type, X, Y, width, height, [Optional] if (args.Count < 7) { throw new InvalidCommandException($"Interface control [{rawValue}] must have at least 7 arguments", rawLine); } // Parse opcode try { type = UIParser.ParseControlType(args[2]); } catch (InvalidCommandException e) { throw new InvalidCommandException(e.Message, rawLine); } // Remove UIControlType from operands // Leftover : Text, Visibility, X, Y, width, height, [Optional] args.RemoveAt(2); // Forge UICommand string text = StringEscaper.Unescape(args[0]); bool visibility = string.Equals(args[1], "1", StringComparison.Ordinal); NumberHelper.ParseInt32(args[2], out int x); NumberHelper.ParseInt32(args[3], out int y); NumberHelper.ParseInt32(args[4], out int width); NumberHelper.ParseInt32(args[5], out int height); Rect rect = new Rect(x, y, width, height); UIInfo info; try { info = ParseUICommandInfo(type, args); } catch (InvalidCommandException e) { throw new InvalidCommandException(e.Message, rawLine); } return(new UICommand(rawLine, addr, key, text, visibility, type, rect, info)); }
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); }
public static UIControl ParseUIControl(IList <string> rawLines, ScriptSection section, ref int idx) { // UICommand's line number in physical file int lineIdx = section.LineIdx + 1 + idx; // Get rawLine string rawLine = rawLines[idx].Trim(); // Check if rawLine is empty if (rawLine.Length == 0) { return(null); } // Line Comment Identifier : '//', '#', ';' if (rawLine.StartsWith("//", StringComparison.Ordinal) || rawLine[0] == '#' || rawLine[0] == ';') { return(null); } // Find key of interface control string key; string rawValue = string.Empty; int equalIdx = rawLine.IndexOf('='); if (equalIdx != -1 && equalIdx != 0) { key = rawLine.Substring(0, equalIdx); rawValue = rawLine.Substring(equalIdx + 1); } else { throw new InvalidCommandException($"Interface control [{rawValue}] must have a key", rawLine); } // Parse Arguments List <string> args = new List <string>(); try { string remainder = rawValue; while (remainder != null) { string next; (next, remainder) = CodeParser.GetNextArgument(remainder); args.Add(next); } } catch (InvalidCommandException e) { throw new InvalidCommandException(e.Message, rawLine); } // Check double-quote's occurence - must be 2n if (StringHelper.CountSubStr(rawValue, "\"") % 2 == 1) { throw new InvalidCommandException("Double-quote's number should be even", rawLine); } // Check if last operand is \ - MultiLine check - only if one or more operands exists if (0 < args.Count) { while (args.Last().Equals(@"\", StringComparison.OrdinalIgnoreCase)) { // Split next line and append to List<string> operands if (rawLines.Count <= idx) // Section ended with \, invalid grammar! { throw new InvalidCommandException(@"Last interface control cannot end with '\'", rawLine); } idx++; args.AddRange(rawLines[idx].Trim().Split(',')); } } // UIControl should have at least 7 operands // Text, Visibility, Type, X, Y, width, height, [Optional] if (args.Count < 7) { throw new InvalidCommandException($"Interface control [{rawValue}] must have at least 7 arguments", rawLine); } // Parse UIControlType UIControlType type; try { type = UIParser.ParseControlTypeVal(args[2]); } catch (InvalidCommandException e) { throw new InvalidCommandException(e.Message, rawLine); } // Remove UIControlType from operands // Leftover : Text, Visibility, X, Y, width, height, [Optional] args.RemoveAt(2); // Forge UIControl string text = args[0]; string visibilityStr = args[1]; bool visibility; if (visibilityStr.Equals("1", StringComparison.Ordinal) || visibilityStr.Equals("True", StringComparison.OrdinalIgnoreCase)) { visibility = true; } else if (visibilityStr.Equals("0", StringComparison.Ordinal) || visibilityStr.Equals("False", StringComparison.OrdinalIgnoreCase)) { visibility = false; } else { throw new InvalidCommandException($"Invalid value in [{visibilityStr}]", rawLine); } bool intParse = true; intParse &= NumberHelper.ParseInt32(args[2], out int x); intParse &= NumberHelper.ParseInt32(args[3], out int y); intParse &= NumberHelper.ParseInt32(args[4], out int width); intParse &= NumberHelper.ParseInt32(args[5], out int height); if (!intParse) { throw new InvalidCommandException($"Invalid integers in [{rawValue}]", rawLine); } UIInfo info; try { info = ParseUIControlInfo(type, args); } catch (InvalidCommandException e) { throw new InvalidCommandException(e.Message, rawLine); } return(new UIControl(rawLine, section, key, text, visibility, type, x, y, width, height, info, lineIdx)); }
private List <LogInfo> ValidateInterfaceSection(ScriptSection section, string rawLine = null, int lineIdx = 0) { // 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(ValidateCodeSection(_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.Image: if (!uiCtrl.Text.Equals(UIInfo_Image.NoResource, StringComparison.OrdinalIgnoreCase) && !EncodedFile.ContainsInterface(_sc, uiCtrl.Text)) { logs.Add(new LogInfo(LogState.Warning, $"Image resource [{uiCtrl.Text}] does not exist", uiCtrl)); } break; case UIControlType.TextFile: if (!uiCtrl.Text.Equals(UIInfo_TextFile.NoResource, StringComparison.OrdinalIgnoreCase) && !EncodedFile.ContainsInterface(_sc, uiCtrl.Text)) { logs.Add(new LogInfo(LogState.Warning, $"Text resource [{uiCtrl.Text}] does not exist", uiCtrl)); } break; case UIControlType.Button: { UIInfo_Button info = uiCtrl.Info.Cast <UIInfo_Button>(); if (info.Picture != null && !info.Picture.Equals(UIInfo_Button.NoPicture, StringComparison.OrdinalIgnoreCase) && !EncodedFile.ContainsInterface(_sc, info.Picture)) { logs.Add(new LogInfo(LogState.Warning, $"Image resource [{info.Picture}] does not exist", uiCtrl)); } if (info.SectionName != null) { if (_sc.Sections.ContainsKey(info.SectionName)) // Only if section exists { logs.AddRange(ValidateCodeSection(_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.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(ValidateCodeSection(_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.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(ValidateCodeSection(_sc.Sections[info.SectionName], uiCtrl.RawLine, uiCtrl.LineIdx)); } else { logs.Add(new LogInfo(LogState.Error, $"Section [{info.SectionName}] does not exist", uiCtrl)); } } } break; } } return(logs); }