877 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			877 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
/*********************************************************************************************
 | 
						|
 * Copyright 2002 - 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 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
 | 
						|
				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;
 | 
						|
		}
 | 
						|
 | 
						|
		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);
 | 
						|
//					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);
 | 
						|
 | 
						|
			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);
 | 
						|
			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);
 | 
						|
 | 
						|
			// 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);
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
}
 |