From 7f75af7119cbe21fb08a854867400608994aaa39 Mon Sep 17 00:00:00 2001 From: mschill Date: Thu, 25 Jun 2026 15:46:25 -0400 Subject: [PATCH] B2026-052 - Issue when parens inside a Hardspaced Multi-RO Return Values. PROMS crashes when doing an update ROFst. --- .../Config/ROFSTLookup.cs | 255 ++++++++++-------- 1 file changed, 142 insertions(+), 113 deletions(-) diff --git a/PROMS/VEPROMS.CSLA.Library/Config/ROFSTLookup.cs b/PROMS/VEPROMS.CSLA.Library/Config/ROFSTLookup.cs index 72eb066c..fe72f0f8 100644 --- a/PROMS/VEPROMS.CSLA.Library/Config/ROFSTLookup.cs +++ b/PROMS/VEPROMS.CSLA.Library/Config/ROFSTLookup.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; -using static System.Net.Mime.MediaTypeNames; namespace VEPROMS.CSLA.Library @@ -61,7 +60,8 @@ namespace VEPROMS.CSLA.Library #region Structs / Internal Classes [Serializable] - public struct roHdr + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Keep Older Pre-existing naming conventions")] + public struct roHdr { public int hSize; public int hYear; @@ -78,7 +78,8 @@ namespace VEPROMS.CSLA.Library }; [Serializable] - public struct rodbi + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Keep Older Pre-existing naming conventions")] + public struct rodbi { public int dbiID; public int dbiType; @@ -91,7 +92,8 @@ namespace VEPROMS.CSLA.Library }; [Serializable] - public struct rogrp + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Keep Older Pre-existing naming conventions")] + public struct rogrp { public string value; public string appid; @@ -102,7 +104,8 @@ namespace VEPROMS.CSLA.Library }; [Serializable] - public struct rochild + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Keep Older Pre-existing naming conventions")] + public struct rochild { public int ID; public int ParentID; @@ -133,7 +136,7 @@ namespace VEPROMS.CSLA.Library private List _baseAccPageKeys; // RofstLookup/Conversion Variables - private int _rofstID; + private readonly int _rofstID; private DocVersionInfo _myDocVersionInfo; private int _selectedSlave; private string _otherChild = string.Empty; @@ -149,7 +152,7 @@ namespace VEPROMS.CSLA.Library // B2022-107: Display Progress Bar Messages/Statuses when a new ROFST binary file is loaded into the database private frmRofstLoadStatus _frmRofstLoadStatus = null; private Dictionary _dicRoCounts = null; - private bool _showLoadingStatus = true; + private readonly bool _showLoadingStatus = true; private int _curRoCnt = 0; private int _dbRoCnt = 0; @@ -414,7 +417,6 @@ namespace VEPROMS.CSLA.Library ROFSTLookup.rochild rc = RofstDataGetChildByAccPageID(_rofstID, accPageBase); - //if (rc.ID >=0 && rc.roid.Length < 16 && Regex.IsMatch(accPageKey, @".*\.[A-Z]") && rc.children != null && rc.children.Count() > 0) if (rc.ID >= 0 && rc.roid.Length < 16 && !string.IsNullOrEmpty(accPageExt) && rc.children != null && rc.children.Count() > 0) { // Check if AccPageID/Key has a return value specific extension. Try to find the RoChild record with the specific return value type, @@ -507,8 +509,6 @@ namespace VEPROMS.CSLA.Library // B2023-037: Handle <=, >=, +-, -> and <- symbols. Convert to unicode for output, i.e. print and edit/view (when editing // step, will show as 2 characters, not unicode, unless ro inserted when code replaced link text with unicode. - //(_MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.UseDashGreaterLessThenForArrowsInROValue || - // _MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.ConvertGTELTEPMinROValue)) bool arrows1 = myiteminfo.ActiveFormat.PlantFormat.FormatData.SectData.UseDashGreaterLessThenForArrowsInROValue; bool arrows2 = myiteminfo.ActiveFormat.PlantFormat.FormatData.SectData.ConvertGTELTEPMinROValue; @@ -681,11 +681,10 @@ namespace VEPROMS.CSLA.Library if (minutes > 0) duration = string.Format("{0} min(s) ", minutes.ToString("n0")); if (secs < 0) secs = 0.00; - duration = duration + string.Format("{0,10:#####0.00} sec(s)", secs).Trim(); + duration += string.Format("{0,10:#####0.00} sec(s)", secs).Trim(); return duration; - //return string.Format("{0,10:#####0.00}", TimeSpan.FromTicks(DateTime.Now.Ticks - dtStart.Ticks).TotalSeconds); } //C2026-008 Re-Architect RO.FST to include RO Modification date/time @@ -1475,21 +1474,22 @@ namespace VEPROMS.CSLA.Library private ROFSTLookup.roHdr ConvertFst2Objects(byte[] ab) { - ROFSTLookup.roHdr roh = new ROFSTLookup.roHdr(); + ROFSTLookup.roHdr roh = new ROFSTLookup.roHdr + { + hSize = BitConverter.ToInt32(ab, 0), + hYear = BitConverter.ToInt16(ab, 4), + hMonth = ab[6], + hDay = ab[7], + hcYear = BitConverter.ToInt16(ab, 8), + hcMonth = ab[10], + hcDay = ab[11], + hcHour = ab[12], + hcMin = ab[13], + hcSec = ab[14], + hcHund = ab[15] + }; - roh.hSize = BitConverter.ToInt32(ab, 0); - roh.hYear = BitConverter.ToInt16(ab, 4); - roh.hMonth = ab[6]; - roh.hDay = ab[7]; - roh.hcYear = BitConverter.ToInt16(ab, 8); - roh.hcMonth = ab[10]; - roh.hcDay = ab[11]; - roh.hcHour = ab[12]; - roh.hcMin = ab[13]; - roh.hcSec = ab[14]; - roh.hcHund = ab[15]; - - int hdrOffset = BitConverter.ToInt32(ab, 16); + int hdrOffset = BitConverter.ToInt32(ab, 16); int dbs = BitConverter.ToInt16(ab, hdrOffset + 4); roh.myDbs = new ROFSTLookup.rodbi[dbs]; @@ -1525,12 +1525,13 @@ namespace VEPROMS.CSLA.Library private ROFSTLookup.rogrp LoadGroup(byte[] ab, int offset, int tableID) { - ROFSTLookup.rogrp myGrp = new ROFSTLookup.rogrp(); + ROFSTLookup.rogrp myGrp = new ROFSTLookup.rogrp + { + ID = BitConverter.ToInt32(ab, offset), + ParentID = BitConverter.ToInt32(ab, offset + 4) + }; - myGrp.ID = BitConverter.ToInt32(ab, offset); - myGrp.ParentID = BitConverter.ToInt32(ab, offset + 4); - - int numChildren = BitConverter.ToInt16(ab, offset + 8); + int numChildren = BitConverter.ToInt16(ab, offset + 8); if (numChildren > 0) { @@ -1660,7 +1661,7 @@ namespace VEPROMS.CSLA.Library } // Update Progress Bar Accordingly - if (_totalRoCnt > 0) _pctComplete = _pctComplete + ((Convert.ToDouble(_dbRoCnt) / Convert.ToDouble(_totalRoCnt)) * 80.0); + if (_totalRoCnt > 0) _pctComplete += ((Convert.ToDouble(_dbRoCnt) / Convert.ToDouble(_totalRoCnt)) * 80.0); OnProgressChanged(displayText, Convert.ToInt32(_pctComplete), 100); } @@ -1720,15 +1721,13 @@ namespace VEPROMS.CSLA.Library protected virtual void OnProgressChanged(string title, string displayText, int curVal = 0, int maxVal = 100) { // If frmRofstLoadStatus is not null then call Update Progress Method - if (_frmRofstLoadStatus != null) - _frmRofstLoadStatus.UpdateProgress(title, displayText, curVal, maxVal); + _frmRofstLoadStatus?.UpdateProgress(title, displayText, curVal, maxVal); } protected virtual void OnProgressChanged(string displayText, int curVal = 0, int maxVal = 100) { // If frmRofstLoadStatus is not null then call Update Progress Method - if (_frmRofstLoadStatus != null) - _frmRofstLoadStatus.UpdateProgress(_frmRofstLoadStatus.Title, displayText, curVal, maxVal); + _frmRofstLoadStatus?.UpdateProgress(_frmRofstLoadStatus.Title, displayText, curVal, maxVal); } #endregion @@ -1739,21 +1738,22 @@ namespace VEPROMS.CSLA.Library private ROFSTLookup.roHdr ConvertToRoHdrObject(SafeDataReader dr, bool loadChildren) { - ROFSTLookup.roHdr rh = new ROFSTLookup.roHdr(); + ROFSTLookup.roHdr rh = new ROFSTLookup.roHdr + { + hSize = (int)dr.GetValue("hSize"), + hYear = (int)dr.GetValue("hYear"), + hMonth = (byte)dr.GetValue("hMonth"), + hDay = (byte)dr.GetValue("hDay"), + hcYear = (int)dr.GetValue("hcYear"), + hcMonth = (byte)dr.GetValue("hcMonth"), + hcDay = (byte)dr.GetValue("hcDay"), + hcHour = (byte)dr.GetValue("hcHour"), + hcMin = (byte)dr.GetValue("hcMin"), + hcSec = (byte)dr.GetValue("hcSec"), + hcHund = (byte)dr.GetValue("hcHund") + }; - rh.hSize = (int)dr.GetValue("hSize"); - rh.hYear = (int)dr.GetValue("hYear"); - rh.hMonth = (byte)dr.GetValue("hMonth"); - rh.hDay = (byte)dr.GetValue("hDay"); - rh.hcYear = (int)dr.GetValue("hcYear"); - rh.hcMonth = (byte)dr.GetValue("hcMonth"); - rh.hcDay = (byte)dr.GetValue("hcDay"); - rh.hcHour = (byte)dr.GetValue("hcHour"); - rh.hcMin = (byte)dr.GetValue("hcMin"); - rh.hcSec = (byte)dr.GetValue("hcSec"); - rh.hcHund = (byte)dr.GetValue("hcHund"); - - if (loadChildren) + if (loadChildren) { rh.myDbs = RofstDataGetDatabases(_rofstID); } @@ -1763,17 +1763,18 @@ namespace VEPROMS.CSLA.Library private ROFSTLookup.rodbi ConvertToRodbiObject(SafeDataReader dr, bool loadChildren, bool loadAllChildren) { - ROFSTLookup.rodbi rd = new ROFSTLookup.rodbi(); + ROFSTLookup.rodbi rd = new ROFSTLookup.rodbi + { + dbiID = (int)dr.GetValue("dbiID"), + dbiType = (int)dr.GetValue("dbiType"), + dbiAW = (int)dr.GetValue("dbiAW"), + dbiAP = (string)dr.GetValue("dbiAP"), + dbiTitle = (string)dr.GetValue("dbiTitle"), + ID = (int)dr.GetValue("ID"), + ParentID = (int)dr.GetValue("ParentID") + }; - rd.dbiID = (int)dr.GetValue("dbiID"); - rd.dbiType = (int)dr.GetValue("dbiType"); - rd.dbiAW = (int)dr.GetValue("dbiAW"); - rd.dbiAP = (string)dr.GetValue("dbiAP"); - rd.dbiTitle = (string)dr.GetValue("dbiTitle"); - rd.ID = (int)dr.GetValue("ID"); - rd.ParentID = (int)dr.GetValue("ParentID"); - - if (loadChildren || loadAllChildren) + if (loadChildren || loadAllChildren) { rd.children = RofstDataGetChildrenByID(_rofstID, rd.dbiID, rd.ID, false, loadAllChildren); } @@ -1783,15 +1784,16 @@ namespace VEPROMS.CSLA.Library private ROFSTLookup.rochild ConvertToRochildObject(SafeDataReader dr, bool loadChildren, bool loadAllChildren) { - ROFSTLookup.rochild rc = new ROFSTLookup.rochild(); + ROFSTLookup.rochild rc = new ROFSTLookup.rochild + { + ID = (int)dr.GetValue("ID"), + ParentID = (int)dr.GetValue("ParentID"), + type = (int)dr.GetValue("type"), + title = (string)dr.GetValue("title"), + roid = (string)dr.GetValue("roid") + }; - rc.ID = (int)dr.GetValue("ID"); - rc.ParentID = (int)dr.GetValue("ParentID"); - rc.type = (int)dr.GetValue("type"); - rc.title = (string)dr.GetValue("title"); - rc.roid = (string)dr.GetValue("roid"); - - if (!string.IsNullOrEmpty((string)dr.GetValue("appid"))) + if (!string.IsNullOrEmpty((string)dr.GetValue("appid"))) { rc.appid = (string)dr.GetValue("AccPageID"); @@ -1811,13 +1813,14 @@ namespace VEPROMS.CSLA.Library private ROFSTLookup.RoExtension ConvertToRoExtensionObject(SafeDataReader dr) { - ROFSTLookup.RoExtension re = new ROFSTLookup.RoExtension(); + ROFSTLookup.RoExtension re = new ROFSTLookup.RoExtension + { + Offset = (int)dr.GetValue("Offset"), + RoidExt = (string)dr.GetValue("RoidExt"), + AccPageExt = (string)dr.GetValue("AccPageExt") + }; - re.Offset = (int)dr.GetValue("Offset"); - re.RoidExt = (string)dr.GetValue("RoidExt"); - re.AccPageExt = (string)dr.GetValue("AccPageExt"); - - return re; + return re; } #endregion @@ -1875,7 +1878,6 @@ namespace VEPROMS.CSLA.Library // Instead of returning the RoChildBase object with a single RoReturnVal object attached, just return the single Ro ReturnValue object. var roRetVal = child.children.First(); - //child.title = roRetVal.title; child.appid = roRetVal.appid; child.roid = roRetVal.roid; child.value = roRetVal.value; @@ -2129,44 +2131,71 @@ namespace VEPROMS.CSLA.Library return ProcessRO(match, multiRtnVal); } - private string ProcessMacros(string str) - { - // Takes the RO text value and sees if a macro has been used. - // If so it will perform the macro operation on the substring in the text value - // Note** Right now the only macro is @HSP(), where every space between the "(" and ")" will be replaced with a hard space + // Takes the RO text value and sees if a macro has been used. + // If so it will perform the macro operation on the substring in the text value + // Note** Right now the only macro is @HSP(), where every space between the "(" and ")" will be replaced with a hard space + private static string ProcessMacros(string str) + { - if (string.IsNullOrEmpty(str)) - return str; + if (string.IsNullOrEmpty(str) || str.ToUpper().IndexOf("@HSP(") < 0) + return str; - string rtnstr = str; - int indx; - while ((indx = rtnstr.ToUpper().IndexOf("@HSP(")) > -1) - { - string resstr = rtnstr.Substring(0, indx); - int endHsp = rtnstr.IndexOf(")", indx); + string processingstr = str; //holds current string being processed + int indx; //current position of @HSP( in string + int endpos = 0; //end of last parens - //B2026 - 002 handle if parens inside a HSP - int startpos = indx + 5; - while (rtnstr.Substring(startpos, endHsp - startpos).Contains("(")) - { - startpos = rtnstr.IndexOf("(", startpos + 1, endHsp - startpos) + 1; - endHsp = rtnstr.IndexOf(")", endHsp + 1); - } + StringBuilder sb = new StringBuilder(); + Stack endparens = new Stack(); - string tmpstr = rtnstr.Substring(indx + 5, endHsp - indx - 5); + while ((indx = processingstr.ToUpper().IndexOf("@HSP(")) > -1) + { + sb.Append(processingstr.Substring(0, indx)); // initial string before @HSP( - // B2017-012 Don't convert space to hard spaces for XY Plots. - if (!tmpstr.Contains("< 0) + { + //if cloing parens and it matches an opening parens inside of HSP, remove a level + _ = endparens.Pop(); + } + else if (ch == ')' && endparens.Count == 0) + { + //if closing parens and at same level as HSP, break out since found correct closing parens + endpos = i; + break; + } + else if (i == processingstr.Length - 1) + { + //if hit the end of the string and no matching closing parens found, take to the end of the string + endpos = processingstr.Length; + } + } - return rtnstr; - } + //Add the text inside the @HSP(...) + string tmpstr = processingstr.Substring(indx + 5, endpos - indx - 5); + // B2017-012 Don't convert space to hard spaces for XY Plots. + if (!tmpstr.Contains("<= processingstr.Length ? "" : processingstr.Substring(endpos + 1); + } + + //add text after last end parens + sb.Append(processingstr); + + return sb.ToString(); + } + + private int StringLength(byte[] ab, int offset) { int i = 0; while (ab[i + offset] != 0) i++; @@ -2275,7 +2304,7 @@ namespace VEPROMS.CSLA.Library { rc.roid = FormatRoidKey(roid).Substring(0, 12); - DocVersionConfig dvc = (_myDocVersionInfo != null) ? _myDocVersionInfo.DocVersionConfig : null; + DocVersionConfig dvc = _myDocVersionInfo?.DocVersionConfig; if (dvc != null) dvc.SelectedSlave = this.SelectedSlave; switch (rc.roid) @@ -2283,49 +2312,49 @@ namespace VEPROMS.CSLA.Library case "FFFF00000001": rc.title = "Number"; rc.appid = "U-NUMBER"; - rc.value = (dvc != null) ? dvc.Unit_Number : null; + rc.value = dvc?.Unit_Number; break; case "FFFF00000002": rc.title = "Other Number"; rc.appid = "U-OTHERNUMBER"; - rc.value = (dvc != null) ? dvc.Other_Unit_Number : null; + rc.value = dvc?.Other_Unit_Number; break; case "FFFF00000003": rc.title = "Text"; rc.appid = "U-TEXT"; - rc.value = (dvc != null) ? dvc.Unit_Text : null; + rc.value = dvc?.Unit_Text; break; case "FFFF00000004": rc.title = "Other Text"; rc.appid = "U-OTHERTEXT"; - rc.value = (dvc != null) ? dvc.Other_Unit_Text : null; + rc.value = dvc?.Other_Unit_Text; break; case "FFFF00000005": rc.title = "ID"; rc.appid = "U-ID"; - rc.value = (dvc != null) ? dvc.Unit_ID : null; + rc.value = dvc?.Unit_ID; break; case "FFFF00000006": rc.title = "Other ID"; rc.appid = "U-OTHERID"; - rc.value = (dvc != null) ? dvc.Other_Unit_ID : null; + rc.value = dvc?.Other_Unit_ID; break; case "FFFF00000007": rc.title = "Name"; rc.appid = "U-NAME"; - rc.value = (dvc != null) ? dvc.Unit_Name : null; + rc.value = dvc?.Unit_Name; break; case "FFFF00000008": rc.title = "Other Name"; rc.appid = "U-OTHERNAME"; - rc.value = (dvc != null) ? dvc.Other_Unit_Name : null; + rc.value = dvc?.Other_Unit_Name; break; }