public void importFoundTable(int tId, PcmFile PCM)
        {
            TableSeek  tSeek = tableSeeks[PCM.foundTables[tId].configId];
            FoundTable ft    = PCM.foundTables[tId];

            addrInt = ft.addrInt;
            //Address = ft.Address;
            Category   = ft.Category;
            OutputType = tSeek.OutputType;
            //Floating = tSeek.Floating;
            //ElementSize = (byte)(tSeek.Bits / 8);
            DataType = tSeek.DataType;
            Math     = tSeek.Math;
            //SavingMath = tSeek.SavingMath;
            OS            = PCM.OS;
            RowMajor      = tSeek.RowMajor;
            Rows          = ft.Rows;
            Columns       = ft.Columns;
            ColumnHeaders = tSeek.ColHeaders;
            RowHeaders    = tSeek.RowHeaders;
            Decimals      = tSeek.Decimals;
            //Signed = tSeek.Signed;
            TableDescription = tSeek.Description;
            TableName        = ft.Name;
            Units            = tSeek.Units;
            Origin           = "seek";
            Values           = tSeek.Values;
            Min = tSeek.Min;
            Max = tSeek.Max;
            if (!PCM.tableCategories.Contains(Category))
            {
                PCM.tableCategories.Add(Category);
            }
        }
        public string readTinyDB(PcmFile PCM)
        {
            string          connetionString = null;
            OleDbConnection cnn;
            string          dbFile = Path.Combine(Application.StartupPath, "TinyTuner.mdb");

            connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dbFile;
            cnn             = new OleDbConnection(connetionString);
            try
            {
                string       query         = "Select MapNumber from OSIDData where OSID=" + PCM.OS.ToString();
                OleDbCommand selectCommand = new OleDbCommand(query, cnn);
                cnn.Open();
                DataTable        table   = new DataTable();
                OleDbDataAdapter adapter = new OleDbDataAdapter();
                adapter.SelectCommand = selectCommand;
                adapter.Fill(table);
                string mapNr = "";
                foreach (DataRow row in table.Rows)
                {
                    mapNr = row["MapNumber"].ToString();
                }
                if (mapNr == "")
                {
                    MessageBox.Show("OS not found from TinyTuner DB", "OS not found from TinyTuner DB");
                    return("Not found");
                }

                query                 = "select * from CategoryList order by Category";
                selectCommand         = new OleDbCommand(query, cnn);
                table                 = new DataTable();
                adapter               = new OleDbDataAdapter();
                adapter.SelectCommand = selectCommand;
                adapter.Fill(table);

                if (PCM.tableCategories == null)
                {
                    PCM.tableCategories = new List <string>();
                }
                foreach (DataRow row in table.Rows)
                {
                    string cat = row["Category"].ToString();
                    if (!PCM.tableCategories.Contains(cat))
                    {
                        PCM.tableCategories.Add(cat);
                    }
                }

                query                 = "select * from TableData where MapNumber=" + mapNr + " order by TableName";
                selectCommand         = new OleDbCommand(query, cnn);
                table                 = new DataTable();
                adapter               = new OleDbDataAdapter();
                adapter.SelectCommand = selectCommand;
                adapter.Fill(table);

                if (tableSeeks == null)
                {
                    tableSeeks = new List <TableSeek>();
                }
                if (PCM.foundTables == null)
                {
                    PCM.foundTables = new List <FoundTable>();
                }
                foreach (DataRow row in table.Rows)
                {
                    TableSeek  ts = new TableSeek();
                    FoundTable ft = new FoundTable(PCM);

                    HexToUint(row["StartPosition"].ToString(), out ft.addrInt);
                    ft.Address     = ft.addrInt.ToString("X8");
                    ft.Columns     = Convert.ToUInt16(row["ColumnCount"]);
                    ft.Description = row["TableDescription"].ToString();
                    ft.Name        = row["TableName"].ToString();
                    ft.Rows        = Convert.ToUInt16(row["RowCount"]);
                    ft.Category    = row["MainCategory"].ToString();
                    ft.configId    = tableSeeks.Count;
                    PCM.foundTables.Add(ft);

                    ushort elementSize = (ushort)(Convert.ToUInt16(row["ElementSize"]));
                    bool   signed      = Convert.ToBoolean(row["AllowNegative"]);
                    ts.DataType = convertToDataType(elementSize, signed, true);
                    string colHeaders = row["ColumnHeaders"].ToString();
                    ts.ColHeaders  = RemoveDuplicates(colHeaders);
                    ts.Columns     = Convert.ToUInt16(row["ColumnCount"]);
                    ts.Decimals    = 2;
                    ts.Description = row["TableDescription"].ToString();
                    ts.Math        = "X*" + row["Factor"].ToString();
                    ts.Name        = row["TableName"].ToString();
                    ts.Rows        = Convert.ToUInt16(row["RowCount"]);
                    ts.RowHeaders  = row["RowHeaders"].ToString();
                    if (ts.RowHeaders.Contains(",by,"))
                    {
                        ts.RowHeaders = convertByHeader(ts.RowHeaders, ts.Rows);
                    }
                    ts.SavingMath = "X/" + row["Factor"].ToString();
                    ts.Category   = row["MainCategory"].ToString();
                    ts.Units      = row["Units"].ToString();
                    ts.RowMajor   = false;
                    tableSeeks.Add(ts);
                }


                cnn.Close();
            }
            catch (Exception ex)
            {
                var st = new StackTrace(ex, true);
                // Get the top stack frame
                var frame = st.GetFrame(st.FrameCount - 1);
                // Get the line number from the stack frame
                var line = frame.GetFileLineNumber();
                MessageBox.Show("Error, line " + line + ": " + ex.Message, "Error");
            }
            return("OK");
        }
        public string seekTables(PcmFile PCM1)
        {
            PCM = PCM1;
            string retVal = "";

            try
            {
                PCM.foundTables = new List <FoundTable>();

                PCM.tableCategories = new List <string>();
                PCM.tableCategories.Add("_All");
                if (PCM.segmentinfos == null)
                {
                    return("");
                }
                for (int c = 0; c < PCM.segmentinfos.Length; c++)
                {
                    PCM.tableCategories.Add("Seg-" + PCM.segmentinfos[c].Name);
                }
                string fileName = Path.Combine(Application.StartupPath, "XML", "TableSeek-" + PCM.configFile + ".xml");
                if (fileName != tableSeekFile)
                {
                    tableSeekFile = fileName;
                    if (File.Exists(fileName))
                    {
                        Debug.WriteLine("Loading " + fileName);
                        System.Xml.Serialization.XmlSerializer reader = new System.Xml.Serialization.XmlSerializer(typeof(List <TableSeek>));
                        System.IO.StreamReader file = new System.IO.StreamReader(fileName);
                        tableSeeks = (List <TableSeek>)reader.Deserialize(file);
                        file.Close();
                    }
                    else
                    {
                        if (PCM.Segments[0].CS1Address.StartsWith("GM-V6"))
                        {
                            if (!PCM.tableCategories.Contains("Fuel"))
                            {
                                PCM.tableCategories.Add("Fuel");
                            }
                            tableSeeks = new List <TableSeek>();
                            TableSeek  ts = new TableSeek();
                            FoundTable ft = new FoundTable(PCM);

                            ft.Address     = PCM.v6VeTable.address.ToString("X8");
                            ft.addrInt     = PCM.v6VeTable.address;
                            ft.Rows        = (byte)PCM.v6VeTable.rows;
                            ft.Columns     = 17;
                            ft.configId    = 0;
                            ft.Name        = "VE";
                            ft.Category    = "Fuel";
                            ft.Description = "Volumetric Efficiency";
                            PCM.foundTables.Add(ft);

                            ts.Name        = "VE";
                            ts.Description = "Volumetric Efficiency";
                            ts.DataType    = InDataType.UWORD;
                            //ts.Bits = 16;
                            //ts.Floating = true;
                            ts.OutputType = OutDataType.Float;
                            ts.Decimals   = 6;
                            ts.Math       = "X*0.0002441406";
                            ts.Offset     = 0;
                            ts.SavingMath = "X/0.0002441406";
                            //ts.Signed = false;
                            ts.Category   = "Fuel";
                            ts.ColHeaders = "RPM 0,400,800,1200,1600,2000,2400,2800,3200,3600,4000,4400,4800,5200,5600,6000,6400, 6800";
                            if (ft.Rows == 15)
                            {
                                ts.RowHeaders = "kpa 0,10,20,30,40,50,60,70,80,90,100,110,120,130,140";
                            }
                            else
                            {
                                ts.RowHeaders = "kpa 20,30,40,50,60,70,80,90,100,110,120,130,140";
                            }
                            ts.RowMajor = false;
                            tableSeeks.Add(ts);

                            ft = new FoundTable(PCM);
                            HexToUint(PCM.mafAddress, out ft.addrInt);
                            ft.Address     = ft.addrInt.ToString("X8");
                            ft.Rows        = 81;
                            ft.Columns     = 1;
                            ft.configId    = 1;
                            ft.Name        = "MAF";
                            ft.Category    = "Fuel";
                            ft.Description = "Grams Per Second";
                            PCM.foundTables.Add(ft);

                            ts          = new TableSeek();
                            ts.DataType = InDataType.UWORD;
                            //ts.Bits = 16;
                            ts.Name       = "MAF";
                            ts.Math       = "X*0.0078125";
                            ts.SavingMath = "X/0.0078125";
                            //ts.Floating = true;
                            ts.OutputType = OutDataType.Float;
                            ts.Decimals   = 4;
                            //ts.Signed = false;
                            ts.Category   = "Fuel";
                            ts.Units      = "grams/s";
                            ts.RowHeaders = "1500,";
                            for (int rh = 1; rh < 82; rh++)
                            {
                                ts.RowHeaders += (1500 + rh * 125).ToString();
                                if (rh < 81)
                                {
                                    ts.RowHeaders += ",";
                                }
                            }
                            ts.ColHeaders  = "g/s";
                            ts.Description = "Grams Per Second";
                            ts.RowMajor    = false;
                            tableSeeks.Add(ts);

                            retVal += "OK";
                            return(retVal);
                        }
                        else
                        {
                            tableSeeks = new List <TableSeek>();
                            retVal    += "Configuration not found." + Environment.NewLine;
                            return(retVal);
                        }
                    }
                }
                for (int s = 0; s < tableSeeks.Count; s++)
                {
                    if (tableSeeks[s].SearchStr.Length == 0)
                    {
                        continue;   //Can't search if string is empty!
                    }
                    if (tableSeeks[s].Category != null && !PCM.tableCategories.Contains(tableSeeks[s].Category))
                    {
                        PCM.tableCategories.Add(tableSeeks[s].Category);
                    }
                    uint            startAddr = 0;
                    uint            endAddr   = PCM.fsize;
                    List <Block>    addrList  = new List <Block>();
                    SearchedAddress sAddr;
                    sAddr.Addr    = uint.MaxValue;
                    sAddr.Rows    = 0;
                    sAddr.Columns = 0;
                    Block block = new Block();
                    if (tableSeeks[s].Range != null && tableSeeks[s].Range.Length > 0)
                    {
                        string[] rangeS = tableSeeks[s].Range.Split(',');
                        for (int r = 0; r < rangeS.Length; r++)
                        {
                            string[] range = rangeS[r].Split('-');
                            if (range.Length != 2)
                            {
                                throw new Exception("Unknown address range:" + rangeS[r]);
                            }
                            if (HexToUint(range[0], out block.Start) == false)
                            {
                                throw new Exception("Unknown HEX code:" + range[0]);
                            }
                            if (HexToUint(range[1], out block.End) == false)
                            {
                                throw new Exception("Unknown HEX code:" + range[1]);
                            }
                            addrList.Add(block);
                        }
                    }
                    else if (tableSeeks[s].Segments != null && tableSeeks[s].Segments.Length > 0)
                    {
                        string[] segStrings = tableSeeks[s].Segments.Split(',');
                        for (int y = 0; y < segStrings.Length; y++)
                        {
                            int segNr = 0;
                            if (int.TryParse(segStrings[y], out segNr) == false)
                            {
                                throw new Exception("Unknown segment: " + segStrings[y]);
                            }
                            for (int b = 0; b < PCM.segmentAddressDatas[segNr].SegmentBlocks.Count; b++)
                            {
                                addrList.Add(PCM.segmentAddressDatas[segNr].SegmentBlocks[b]);
                            }
                        }
                    }
                    else
                    {
                        block.Start = 0;
                        block.End   = PCM.fsize;
                        addrList.Add(block);
                    }
                    int           hit           = 0;
                    ushort        wantedHit     = 1;
                    List <ushort> wantedHitList = new List <ushort>();
                    string[]      hParts        = tableSeeks[s].UseHit.Split(',');
                    for (int h = 0; h < hParts.Length; h++)
                    {
                        if (hParts[h].Contains("-"))
                        {
                            string[] hParts2 = hParts[h].Split('-');
                            //It's range, loop through all values
                            ushort hStart = 0;
                            ushort hEnd   = 1;
                            ushort.TryParse(hParts2[0], out hStart);
                            ushort.TryParse(hParts2[1], out hEnd);
                            for (ushort x = hStart; x <= hEnd; x++)
                            {
                                wantedHitList.Add(x);
                            }
                        }
                        else
                        {
                            //Single value
                            if (ushort.TryParse(hParts[h], out wantedHit))
                            {
                                wantedHitList.Add(wantedHit);
                            }
                        }
                    }

                    int wHit = 0;
                    for (int b = 0; b < addrList.Count; b++)
                    {
                        startAddr = addrList[b].Start;
                        endAddr   = addrList[b].End;
                        while (startAddr < PCM.fsize)
                        {
                            wantedHit = wantedHitList[wHit];
                            string[] ssParts = tableSeeks[s].SearchStr.Split('+');     //At end of string can be +D4 +1W6 etc, for reading next address from found addr
                            Debug.WriteLine("TableSeek: Searching: " + tableSeeks[s].SearchStr + ", Start: " + startAddr.ToString("X") + ", end: " + endAddr.ToString("X"));
                            sAddr = getAddrbySearchString(PCM, ssParts[0], ref startAddr, endAddr, tableSeeks[s].ConditionalOffset, tableSeeks[s].ValidationSearchStr);
                            for (int jump = 1; jump < ssParts.Length && sAddr.Addr < PCM.fsize; jump++)
                            {
                                //Read table address from address we found by searchstring
                                string numOnly     = ssParts[jump].Replace("+", "").Replace("D", "").Replace("W", "");
                                int    offset      = Convert.ToInt32(numOnly); //For first jump, use tableseek offset, for other jumps use searchstring offset
                                uint   currentAddr = (uint)(sAddr.Addr + offset);
                                Debug.WriteLine("seekTables: Reading new address from:" + currentAddr.ToString("X"));
                                if (ssParts[jump].Contains("D"))
                                {
                                    sAddr.Addr = (uint)(BEToUint32(PCM.buf, currentAddr));
                                }
                                else
                                {
                                    sAddr.Addr = (uint)(BEToUint16(PCM.buf, currentAddr));
                                }
                                Debug.WriteLine("seekTables: New address:" + sAddr.Addr.ToString("X"));
                            }

                            if (sAddr.Addr < PCM.fsize)
                            {
                                hit++;
                                Debug.WriteLine("Found: " + sAddr.Addr.ToString("X") + ", Hit: " + hit.ToString() + " of " + wantedHit);
                            }
                            if (hit == wantedHit && sAddr.Addr < PCM.fsize)
                            {
                                FoundTable ft = new FoundTable(PCM);
                                ft.configId    = s;
                                ft.Name        = tableSeeks[s].Name.Replace("£", (wHit + 1).ToString());
                                ft.Description = tableSeeks[s].Description.Replace("£", (wHit + 1).ToString());
                                ft.addrInt     = (uint)(sAddr.Addr + tableSeeks[s].Offset);
                                if (tableSeeks[s].Category != null && tableSeeks[s].Category != "")
                                {
                                    ft.Category = tableSeeks[s].Category;
                                }
                                else
                                {
                                    ft.Category = "Seg-" + PCM.GetSegmentName(ft.addrInt);
                                }
                                ft.Address = ft.addrInt.ToString("X8");
                                if (tableSeeks[s].Rows > 0)
                                {
                                    ft.Rows = tableSeeks[s].Rows;
                                }
                                else
                                {
                                    ft.Rows = sAddr.Rows;
                                }
                                if (tableSeeks[s].Columns > 0)
                                {
                                    ft.Columns = tableSeeks[s].Columns;
                                }
                                else
                                {
                                    ft.Columns = sAddr.Columns;
                                }
                                PCM.foundTables.Add(ft);
                                wHit++;
                            }
                            if (wHit >= wantedHitList.Count)
                            {
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                var st = new StackTrace(ex, true);
                // Get the top stack frame
                var frame = st.GetFrame(st.FrameCount - 1);
                // Get the line number from the stack frame
                var line = frame.GetFileLineNumber();
                return("Table seek, line " + line + ": " + ex.Message);
            }
            retVal += "Done";
            return(retVal);
        }