/********************************************************************************************* * Copyright 2021 - Volian Enterprises, Inc. All rights reserved. * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE * ------------------------------------------------------------------------------ * $Workfile: RO_FST.cs $ $Revision: 15 $ * $Author: Jsj $ $Date: 8/23/06 11:33a $ * * $History: RO_FST.cs $ * * ***************** Version 15 ***************** * User: Jsj Date: 8/23/06 Time: 11:33a * Updated in $/EXE/RefObj/ROEditor * debug statements commented out * * ***************** Version 14 ***************** * User: Jsj Date: 5/03/05 Time: 11:48a * Updated in $/EXE/RefObj/ROEditor * 2005 upgrade, move some ROFST logic to ROFST library * * ***************** Version 13 ***************** * User: Jsj Date: 5/11/04 Time: 9:29a * Updated in $/EXE/RefObj/ROEditor * Bug fix B2004-011, could not create FST file if user opened nodes on * tree. * * ***************** Version 12 ***************** * User: Jsj Date: 4/08/04 Time: 9:48a * Updated in $/EXE/RefObj/ROEditor * Modified code to speed up the creation of the RO.FST file * * ***************** Version 11 ***************** * User: Jsj Date: 6/30/03 Time: 1:20p * Updated in $/EXE/RefObj/ROEditor * a NULL Accessory Page ID was giving problems in creating a new RO.FST * file. * * ***************** Version 10 ***************** * User: Kathy Date: 6/11/03 Time: 2:01p * Updated in $/EXE/RefObj/ROEditor * Fix bug B2003-045 * * ***************** Version 9 ***************** * User: Kathy Date: 5/30/03 Time: 12:48p * Updated in $/EXE/RefObj/ROEditor * B2003-044: sync up xml with UI tree view * * ***************** Version 8 ***************** * User: Kathy Date: 5/21/03 Time: 12:51p * Updated in $/EXE/RefObj/ROEditor * B2003-034: process data if only one field for RO & also, convert return * value for xml save * * ***************** Version 7 ***************** * User: Jsj Date: 4/14/03 Time: 3:02p * Updated in $/EXE/RefObj/ROEditor * Speed up the creation of the RO.FST file * * ***************** Version 6 ***************** * User: Kathy Date: 4/04/03 Time: 9:41a * Updated in $/EXE/RefObj/ROEditor * B2003-030 convert new top group name to user readable for ro.fst * * ***************** Version 5 ***************** * User: Jsj Date: 2/21/03 Time: 9:51a * Updated in $/EXE/RefObj/ROEditor * added RO FST completed message * * ***************** Version 4 ***************** * User: Jsj Date: 1/02/03 Time: 9:31a * Updated in $/EXE/RefObj/ROEditor * Save Graphics file date in RO.FST file * * ***************** Version 3 ***************** * User: Jsj Date: 12/17/02 Time: 4:54p * Updated in $/EXE/RefObj/ROEditor * save real date for graphic files * * ***************** Version 2 ***************** * User: Jsj Date: 12/06/02 Time: 3:26p * Updated in $/EXE/RefObj/ROEditor * parameter display data fix (ingoring this data for now) * * ***************** Version 1 ***************** * User: Jsj Date: 11/27/02 Time: 12:53p * Created in $/EXE/RefObj/ROEditor * Modification to create the RO.FST file *********************************************************************************************/ using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Xml; using System.Xml.Schema; using System.Text; using System.IO; using RODBInterface; using System.Runtime.InteropServices; using VlnStatus; using System.Collections.Specialized; using ROFST_FILE; using Volian.Base.Library; //using VlnProfiler; //don't forget to add VlnProfiler to the reference list namespace ROEditor { /// /// This creates an RO.FST file /// class FstTmpSTRC { public ushort thistype; public uint thisoff; public string title; public FstTmpSTRC(ushort type, uint offset, string tl) { thistype = type; thisoff = offset; title = tl; } void WriteString(BinaryWriter bw, string str) { int n=str.Length; byte [] b = new byte[n+1]; for(int i =0; i < n; i++) { b[i] = (byte)str[i]; } bw.Write(b,0,n+1); // +1 to include null /** byte nullbyte = 0; int i; for(i =0; i < str.Length; i++) { byte WrByte; WrByte = (byte)str[i]; bw.Write(WrByte); } bw.Write(nullbyte); ***/ } public void Write(BinaryWriter bw) { bw.Write(thisoff); bw.Write(thistype); WriteString(bw,title); } } // The Sorted Array was not sorting via the ASCII value of each character in a given string. // This sorting function compares two strings by doing a character by character comparison. public class MyComparer : IComparer { public int Compare (object x, object y) { int rtnval = 0; int xcnt=0,ycnt=0; int xlen,ylen; byte xbyte, ybyte; string xbuff = x.ToString(); string ybuff = y.ToString(); xlen = xbuff.Length; ylen = ybuff.Length; if (xbuff[0] == '<') rtnval = 0; if (ybuff[0] == '<') rtnval = 0; while ((rtnval==0) && ((xcnt < xlen) || (ycnt < ylen))) { xbyte = (xcnt == xlen)? (byte)0 : (byte)xbuff[xcnt++]; ybyte = (ycnt == ylen)? (byte)0 : (byte)ybuff[ycnt++]; rtnval = xbyte - ybyte; } return rtnval; } } public class RO_FST { private FST_FileHeader FstHeader; private string FstDir; // path to the RO directory private string FstPath; // RO directory Path and RO.FST file name private string FstOld; // ROFST.Old file name (backup of previous fst file) private string FstNew; // ROFST.New hold the RO.FST info during creation private BinaryWriter fhFST; // write handle to FST file being created private VlnStatusBar StatusWin; private RODB ROdatabase; private XmlDocument FSTroXmlDoc; // private HybridDictionary dicTiming; // private HybridDictionary dicDuration; ushort widestAcPgId; SortedList IdsAndAccPgIds; SortedList IdsAndOffsets; ushort AllTypesUsed; private Stack InUseListStack; private Stack RtnValTmplateStack; // private DateTime dtLast=DateTime.Now; public RO_FST(RODB TheROdb, XmlDocument TheXmlDoc) { ROdatabase = TheROdb; // point to the RO database FSTroXmlDoc = TheXmlDoc; } public bool Create() { bool RtnStat = true; // dicDuration=new HybridDictionary(); // dicTiming=new HybridDictionary(); // Profiler.Reset(); // position to the top of the tree // CurrentNode = roTree.TopNode; // Setup the paths to the FST files FstDir = Directory.GetCurrentDirectory(); FstPath = FstDir + "\\RO.FST"; FstOld = FstDir + "\\ROFST.Old"; FstNew = FstDir + "\\ROFST.New"; // open a temporary file for building the RO.FST try { fhFST = new BinaryWriter(File.Open(FstNew,System.IO.FileMode.Create,System.IO.FileAccess.ReadWrite)); } catch (Exception fhExc) { string errmsg = fhExc.Message; MessageBox.Show(errmsg,"Error Creating RO.FST file",System.Windows.Forms.MessageBoxButtons.OK); RtnStat = false; } // If we were able to open a new ROFST.NEW file then go ahead and put the // new FST information into it. if (RtnStat) RtnStat = BuildNewRoFST(); if (RtnStat) // successful in creating new RO FST file? { //If an RO.FST file already exists, // rename the existing file for safe keeping if (File.Exists(FstPath)) { // copy the existing RO.FST to ROFST.OLD // - overrite ROFST.OLD if it already exists File.Copy(FstPath,FstOld,true); // save RO.FST as ROFST.OLD File.Delete(FstPath); // remove RO.FST } File.Copy(FstNew,FstPath,true); // save ROFST.NEW as RO.fST File.Delete(FstNew); // remove ROFST.NEW if (OrphanedRecords.Length > 0) { using (StreamWriter sw = new StreamWriter(Path.Combine(FstDir, @"Orphaned RO Records.txt"), false)) { sw.Write(OrphanedRecords.ToString()); sw.Close(); } MessageBox.Show("The file Orphaned RO Records.txt has been created", "Warning - Orphan RO Record"); } MessageBox.Show("New RO.FST file created successfully.","Create RO.FST file",System.Windows.Forms.MessageBoxButtons.OK); } // MessageBox.Show(Profiler.ToString("000.00%"),"Timings"); // dicDuration=null; // dicTiming=null; return RtnStat; } private bool BuildNewRoFST() { bool RtnVal = true; int i; int numDatabases; // write the empty header - save space for the header info FstHeader = new FST_FileHeader(); FstHeader.Write(fhFST); // point to the ROMASTER and get the number of databases it has VlnXmlElement ROdbtables = (VlnXmlElement) FSTroXmlDoc.FirstChild; numDatabases = ROdbtables.ChildNodes.Count; // Allocate a list of database info structures ROFST_DbInfo[] dbinfo = new ROFST_DbInfo[numDatabases]; //For each RO database, process each group XmlNode ROtableNode = ROdbtables; ROtableNode = ROtableNode.FirstChild; StatusWin = new VlnStatusBar("Creating RO.FST file"); for (i=0; i < numDatabases && RtnVal; i++) { dbinfo[i] = new ROFST_DbInfo(); RtnVal = SaveToFSTFile(ROtableNode,dbinfo[i]); dbinfo[i].dbiType = AllTypesUsed; ROtableNode = ROtableNode.NextSibling; } if (RtnVal) { VlnXmlElement tblnode = (VlnXmlElement) ROdbtables.FirstChild; StatusWin.BarMax = numDatabases * 2; StatusWin.BarStepValue = 1; StatusWin.BarValue = 0; // All of the RO database, group, and return value information // was saved to the FST file. Now save the information needed // to read the FST file. // Save DB list uint lngbuf = 0; uint dblength = (uint)fhFST.BaseStream.Position; fhFST.Write(lngbuf); ushort intbuf = Convert.ToUInt16(numDatabases); fhFST.Write(intbuf); // The old code did a sizeof() on a structure containing the ROFSTDatabaseInfo (dbi) // You cannot read/write a Struct type in C# like you can with C++. The C# books suggest // creating a Class to replace the Struct, then create methods that perform the binary // read/write. So I created a method that calculates the "struct" size to simulate the // sizeof(struct dbi) uint lngval = (dbinfo[0].GetStructSize()) * (uint)numDatabases; for (i=0; i=0) { outstr += tmpstr.Substring(cur,indx-cur); asc_spchar = tmpstr.Substring(indx+3,3); decval = System.Convert.ToInt16(asc_spchar,10); outstr += System.Convert.ToChar(decval).ToString(); cur = indx+6; if (cur+6 > len) indx = -1; else indx = tmpstr.IndexOf(OKpunch,cur); } if (cur= 1) && !TheMenuTitle.Equals("")) { curOffset = (uint)fhFST.BaseStream.Position; curType = SaveROToFST(chldnode,InUseList,RtnValTmplate,AccPageIDTplate); } else { SkipThisOne = true; } } if (!SkipThisOne) { string tmpstr = ChildElem.GetAttribute("MenuTitle"); tmpfststrc = new FstTmpSTRC(curType,curOffset,tmpstr); FstTmp.Add(tmpfststrc); typ |= curType; numgroups++; } } // end if VlnXmlElement // Get next child chldnode = chldnode.NextSibling; }// end while } // if child is not null // pop the InUseList stack if (PopInUseStack) InUseListStack.Pop(); // pop the return valuse template stack if (PopRtnValStack) RtnValTmplateStack.Pop(); // save the current position of the FST file for the return value RtnVal = (uint)fhFST.BaseStream.Position; // Save the ID and offset entry for the current ID IdsAndOffsets.Add(curRecID,RtnVal); fhFST.Write(curRecID); fhFST.Write(elemParentID); fhFST.Write(numgroups); // write the FstTmp for (int i=0; i < FstTmp.Count; i++) { tmpfststrc = (FstTmpSTRC)FstTmp[i]; tmpfststrc.Write(fhFST); } FstTmp.Clear(); return RtnVal; } public void WriteGraphicsReturnValue(string OrigStr) { string text, tmptext, hgttxt, widtxt, imgdateStr; int idx; int hgt, wid; int imgdateInt; byte newline = 10; char[] tmpbuf = OrigStr.ToCharArray(); // remove the trailing "\r\n" tmptext = OrigStr.Substring(0,OrigStr.Length-2); // parse out the image width idx = tmptext.LastIndexOf("\r\n"); widtxt = tmptext.Substring(idx+2,tmptext.Length-(idx+2)); wid = Convert.ToInt32(widtxt,10); widtxt = wid.ToString("x4"); tmptext = tmptext.Substring(0,idx); // parse out the image height idx = tmptext.LastIndexOf("\r\n"); hgttxt = tmptext.Substring(idx+2,tmptext.Length-(idx+2)); hgt = Convert.ToInt32(hgttxt,10); hgttxt = hgt.ToString("x4"); tmptext = tmptext.Substring(0,idx); // parse out the image file name and image date idx = tmptext.IndexOf(" "); text = tmptext.Substring(idx+1); if (tmptext.StartsWith("\r\n")) imgdateStr = tmptext.Substring(2,idx-2); // first 2 chars are "\r\n" else { if(idx < 1) imgdateStr=null; else imgdateStr = tmptext.Substring(0,idx); } if (imgdateStr == null|| imgdateStr=="") imgdateInt = 0; else imgdateInt = Convert.ToInt32(imgdateStr,10); // write graphics file name WriteString(text,false); fhFST.Write(newline); // write dummy date (old FST file had only zeros! // WriteString("00000000",false); WriteString(imgdateInt.ToString("x8"),false); fhFST.Write(newline); // write the image height WriteString(hgttxt,false); fhFST.Write(newline); //write the image width WriteString(widtxt,true); } private ushort SaveROToFST(XmlNode RONode,ArrayList InUseList,string RtnValTmplate, string AccPageIDTplate) { ushort RtnVal; uint startFST = (uint)fhFST.BaseStream.Position; uint RORecID; uint ParID; byte nullbyte=0; VlnXmlElement elem; elem = (VlnXmlElement) RONode; // string dummy = ""; // need for RODB_GetFIeldsInUse call, won't be used. // ArrayList AvailList, InUseList; // //Get the "In Use" field list // AvailList = ROdatabase.RODB_GetFields(elem, (uint) RecordType.Schema); // InUseList = ROdatabase.RODB_GetFieldsInUse(elem, AvailList,"FieldsInUse", ref dummy); //Write the RO's record ID string RecIdStr = elem.GetAttribute("RecID"); RORecID = System.Convert.ToUInt32(RecIdStr,16);// B2019-105 Corrected conversion to 32 bit fhFST.Write(RORecID); // **** Debug // if (RecIdStr.Equals("000000a6")) // nullbyte=0; // *** // Get the Accessory Page ID // string AccPageIDTplate = elem.GetAccPageIDTemplate(); string AccPageID = elem.GetAccPageIDString(AccPageIDTplate); // **** Debug // if (AccPageID.Equals("S:1")) // nullbyte=0; // ***** //Write the parent ID string ParIDstr = elem.GetAttribute("ParentID"); ParID = System.Convert.ToUInt32(ParIDstr,16);// B2019-104 Corrected to 32 Bit fhFST.Write(ParID); // not sure why, was in old FST code but no comment! // I assume that it's some sort of separater short none = -1; fhFST.Write(none); //Get the RO Return value and return type // string RtnValTmplate = elem.GetReturnValueTemplate(); RtnVal = 0; string tablename = elem.GetAttribute("Table"); // if (RtnValTmplate.Equals("")) // { // int i; // i =0; // } string cvttmp= CvtFldToUserFld(RtnValTmplate); string RORtnVal = elem.GetReturnValue(ROdatabase,tablename,cvttmp,InUseList,ref RtnVal,ROEditor.Form1.PCChildren); // C2021-026 pass in P/C Children // Write the field type to the FST fhFST.Write(RtnVal); if (RtnVal == 8) // is this an Image (graphics) record? WriteGraphicsReturnValue(RORtnVal); else WriteString(RORtnVal); // Write the Accessory Page ID // Fix for Bug B2003-039. Added check for a NULL AccPageID // If is null, then assign a blank string if (AccPageID != null) AccPageID = AccPageID.Trim(); else AccPageID = " "; WriteString(AccPageID); // Save the ID and offset entry for the current ID IdsAndOffsets.Add(RORecID,startFST); // Save the RecID and Accessory Page id IdsAndAccPgIds[AccPageID] = RORecID; // Save the widest AccPageID width int acclen = AccPageID.Length; if (acclen > widestAcPgId) widestAcPgId = (ushort)acclen; // if(dtLast.AddSeconds(.3) < DateTime.Now) // { StatusWin.StatMsg = AccPageID; StatusWin.PerformStep(); // dtLast=DateTime.Now; // } return RtnVal; } public void WriteString(string str) { WriteString(str,true); } public void WriteString(string str,bool AddNull) { int n=str.Length; if (AddNull) n++; byte [] b = new byte[n]; for(int i =0; i < str.Length; i++) { b[i] = (byte)str[i]; } fhFST.Write(b,0,n); } } }