mschill 8ec820a7f7 C2025-019 RO Editor - Update the Orphaned RO Record text file to save in the current RO folder instead of the users appdata folder.
Found while using the WEP ROMOD database and the ROEPU folder.
Note for Word doc:  Update D.2.10 in the PROMS Manual for this update
2025-02-20 15:54:29 -05:00

888 lines
26 KiB
C#

/*********************************************************************************************
* 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
{
/// <summary>
/// This creates an RO.FST file
/// </summary>
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<numDatabases; i++)
{
StatusWin.PerformStep();
dbinfo[i].WriteUntAndShort(fhFST);
fhFST.Write(lngval);
lngval += (uint)dbinfo[i].dbiTitle.Length+1;
fhFST.Write(lngval);
lngval += (uint)dbinfo[i].dbiAP.Length+1;
}
// write the titles and accessory page ids
for (i=0; i<numDatabases;i++)
{
tblnode.SetAttribute("TreeNotData","True");
StatusWin.PerformStep();
dbinfo[i].WriteStrings(fhFST);
tblnode = (VlnXmlElement) tblnode.NextSibling;
}
int dbend = (int)fhFST.BaseStream.Position;
fhFST.Seek((int)dblength,System.IO.SeekOrigin.Begin);
lngbuf = (uint)(dbend-dblength-4);//sizeof(dblength);
fhFST.Write(lngbuf);
fhFST.Seek(0,System.IO.SeekOrigin.Begin);
// save the header information
FstHeader.SetHeader(dblength);
FstHeader.Write(fhFST);
// Close the status window
StatusWin.Dispose();
// close tmporary FST file
fhFST.Close();
}
return RtnVal;
}
private string CvtFldToUserFld(string fldname)
{
string tmpstr0;
if (fldname.Length < 2) return fldname;
// an xml element name cannot begin with a digit. we had prepended a "__"
if (fldname.Substring(0,2) == "__" && char.IsDigit(fldname,2))
tmpstr0 = fldname.Substring(2,fldname.Length-2);
else
tmpstr0 = fldname;
// an xml element name cannot have a space, we converted to a "__"
string tmpstr = tmpstr0.Replace("__"," ");
int len = tmpstr.Length;
int cur = 0;
// this is also our sequence that tells us the follow 3 digits is the ascii number (base 10)
// of the character we replaced.
string OKpunch = "-._";
string outstr = "";
int decval, indx;
if (tmpstr.Length <6)
indx = -1;
else
indx=tmpstr.IndexOf(OKpunch,cur);
string asc_spchar;
while (indx>=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<len) outstr += tmpstr.Substring(cur,len-cur);
return outstr;
}
// If any of the nodes on the user interface tree were open,
// the group info for those nodes were aleady read.
// To speed up the RO.FST file creation, remove these read in
// child nodes so the the code can do one big database read
// to get all of the child info for a high level group, instead
// of many database reads (one for each lower level group).
private void RemoveGroupChildNodes(XmlNode TheROtableNode)
{
VlnXmlElement elem = (VlnXmlElement) TheROtableNode;
string strHasChild = elem.GetAttribute("HasChild");
string strChildLoaded = elem.GetAttribute("ChildLoaded");
if (strHasChild.Equals("True") && strChildLoaded.Equals("True"))
{
VlnXmlElement kid, delkid;
XmlNode chldNode = TheROtableNode.FirstChild;
while (chldNode != null)
{
delkid = null;
if (chldNode is VlnXmlElement)
{
kid = (VlnXmlElement) chldNode;
if (kid.HasAttribute("RecID"))delkid = kid;
}
chldNode = chldNode.NextSibling;
if (delkid != null) elem.RemoveChild(delkid);
}
elem.SetAttribute("ChildLoaded","False");
}
}
private bool SaveToFSTFile(XmlNode TheROtableNode,ROFST_DbInfo Thedbinfo)
{
// Profiler.Start("Startup");
bool RtnVal = false;
IComparer StrCompare = new MyComparer();
IdsAndAccPgIds = new SortedList(StrCompare);
IdsAndOffsets = new SortedList();
VlnXmlElement elem = (VlnXmlElement) TheROtableNode;
// Save The Database Filename NUMBER (EX 02 FOR RO000002)
// note that the number part of the filename is in base 10, NOT base 16!
string tablename = elem.GetAttribute("Table");
ushort shorttmp = System.Convert.ToUInt16(tablename.Substring(2),10);
Thedbinfo.dbiID = shorttmp;
// Save the database title
Thedbinfo.dbiTitle = CvtFldToUserFld(elem.FirstChild.InnerText);
StatusWin.StatusBoxTitle = "Processing " + Thedbinfo.dbiTitle;
// Save the Accessory Page ID Prefix
Thedbinfo.dbiAP = elem.GetAttribute("AccPageIDPrefix");
// Get the Accessory Page ID Template
string AccPageIDTplate = elem.GetAccPageIDTemplate();
// Get the list of available fields
ArrayList AvailList;
AvailList = ROdatabase.RODB_GetFields(elem, (uint) RecordType.Schema);
// Initialize a stack for the FieldsInUse lists
InUseListStack = new Stack();
//Initialize a stack for the return value template
RtnValTmplateStack = new Stack();
widestAcPgId = 0;
AllTypesUsed = 0;
// for each group..
// ... save to the FST file and get widestAcPgId
// .... also save a RECID/ACCPGID to a sorted list
// ... also save a RECID/FSToffset to a sorted list
// XmlNode GroupNode = TheROtableNode;
StatusWin.BarMax = ROdatabase.RODB_GetNumberOfROValueRecords(tablename)+1;
StatusWin.BarStepValue = 1;
StatusWin.BarValue = 0;
StatusWin.StatMsg = "Saving To RO.FST File";
// Profiler.End("Startup");
RemoveGroupChildNodes(TheROtableNode);
Thedbinfo.dbiGL = SaveFstGroup(TheROtableNode,0,ref AllTypesUsed,AvailList,AccPageIDTplate);
// Profiler.Start("Finish");
Thedbinfo.dbiIL = (uint)fhFST.BaseStream.Position;
StatusWin.StatMsg = "Saving RO References";
StatusWin.BarMax = IdsAndOffsets.Count + IdsAndAccPgIds.Count;
StatusWin.BarStepValue = 1;
StatusWin.BarValue = 0;
// save the IdsAndOffsets list
for (int i=0; i<IdsAndOffsets.Count; i++)
{
uint buf1;
uint buf2;
// IDsAndOffsetMemBlock tbuf = new IDsAndOffsetMemBlock();
StatusWin.PerformStep();
buf1 = System.Convert.ToUInt32(IdsAndOffsets.GetKey(i));
// buf1 = SwapBytes(buf1);
buf2 = System.Convert.ToUInt32(IdsAndOffsets.GetByIndex(i));
fhFST.Write(buf1);
fhFST.Write(buf2);
RtnVal = true;
}
IdsAndOffsets.Clear();
// write ACCPageIDs and offsets
Thedbinfo.dbiAL = (uint)fhFST.BaseStream.Position;
Thedbinfo.dbiAW = widestAcPgId;
// spin through the children nodes and look for AccPageIds
for (int i=0; i<IdsAndAccPgIds.Count; i++)
{
string ACCPageIDstr;
uint RecIDint;
StatusWin.PerformStep();
ACCPageIDstr = Convert.ToString(IdsAndAccPgIds.GetKey(i));
ACCPageIDstr = ACCPageIDstr.PadRight(widestAcPgId,(char)0);
RecIDint = Convert.ToUInt32(IdsAndAccPgIds.GetByIndex(i));
fhFST.Write(RecIDint);
WriteString(ACCPageIDstr,false);
}
IdsAndAccPgIds.Clear();
// Save the end offset for this database (table)
Thedbinfo.dbiEND = (uint)fhFST.BaseStream.Position;
// Profiler.End("Finish");
return RtnVal;
}
StringBuilder OrphanedRecords = new StringBuilder();
private uint SaveFstGroup(XmlNode GroupNode, uint parentID,ref ushort typ,ArrayList AvailList,string AccPageIDTplate)
{
uint RtnVal;
uint curRecID;
ushort curType = 0;
ushort numgroups;
uint elemParentID;
ArrayList FstTmp;
FstTmpSTRC tmpfststrc;
bool PopInUseStack = false;
bool PopRtnValStack = false;
// FstTmp is an array that stores record type, menu title,
// and offset into the FST file for each RO (non group) record
FstTmp = new ArrayList();
VlnXmlElement elem;
elem = (VlnXmlElement) GroupNode;
// Get the current node's record id
string RecIdStr = elem.GetAttribute("RecID");
curRecID = System.Convert.ToUInt32(RecIdStr,16);
// Get the current node's parent id
string ParIdStr = elem.GetAttribute("ParentID");
elemParentID = Convert.ToUInt32(ParIdStr,16);
string HasKids = elem.GetAttribute("HasChild");
string KidsLoaded = elem.GetAttribute("ChildLoaded");
numgroups = 0;
if (KidsLoaded != "True" && HasKids.Equals("True"))
{
// Profiler.Start("GetChildData");
// ROdatabase.RODB_GetChildData(elem,true);
ROdatabase.RODB_GetGroupAndSubgroups(elem, OrphanedRecords);
// Profiler.End("GetChildData");
}
XmlNode tmpnode = GroupNode;
XmlNode chldnode;
VlnXmlElement ChildElem;
// Process the children. If the child is a subgroup,
// call this function (SaveFstGroup) again. If the
// child is a RO record, save the RO information to
// the FST file.
chldnode = tmpnode.FirstChild;
if (chldnode != null)
{
string dummy = ""; // need for RODB_GetFIeldsInUse call, won't be used.
// ArrayList AvailList, InUseList;
ArrayList InUseList;
// ArrayList tmpAvailList;
string RtnValTmplate;
// if the current group has a "FieldInUse" list, go get it.
if (elem.HasAttribute("FieldsInUse") == true)
{
// Profiler.Start("GetFieldsInUse");
InUseList = ROdatabase.RODB_GetFieldsInUse(elem, AvailList,"FieldsInUse", ref dummy, false);
// save the InUseList on a stack for children to use if they don't have one of their own
InUseListStack.Push(InUseList);
// Profiler.End("GetFieldsInUse");
PopInUseStack = true;
}
else
{
// Use the InUseList from this group's parent
InUseList = (ArrayList)InUseListStack.Peek();
PopInUseStack = false;
}
// if the current group has a "RetVal", go get it
if (elem.HasAttribute("RetVal") == true)
{
RtnValTmplate = elem.GetReturnValueTemplate();
// save the RtnValTmplate on a stack for children to use if they don't have one
RtnValTmplateStack.Push(RtnValTmplate);
PopRtnValStack = true;
}
else
{
// use the parent's RtnValTmplate
RtnValTmplate = (string) RtnValTmplateStack.Peek();
PopRtnValStack = false;
}
while (chldnode != null)
{
uint curOffset =0;
bool SkipThisOne;
if (chldnode is VlnXmlElement)
{
SkipThisOne = false;
ChildElem = (VlnXmlElement) chldnode;
if (ChildElem.Name == "vlnGroup") // is a subgroup?
{
curType=0;
curOffset = SaveFstGroup(chldnode,curRecID,ref curType,AvailList,AccPageIDTplate); // process subgroup
}
else // save RO info.
{
int levelCnt = chldnode.ChildNodes.Count;
string TheMenuTitle = ChildElem.GetAttribute("MenuTitle");
if ((levelCnt >= 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("<Setpoint__Value>"))
// {
// 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);
}
}
}