/// <summary>
        /// Calculate number of segments based on data file length and segment size
        /// </summary>
        /// <returns></returns>
        public int CalcSegmentCount()
        {
            if (SegmentSizeL == 0)
            {
                SegmentCount = 0;
                return(0);
            }
            Monitor.Enter(DataF_);
            long FileSize;

            if (IsDummyFile)
            {
                FileSize = DummyFileSize;
            }
            else
            {
                FileStream DataS = DataOpen();
                if (ParamDigestMode)
                {
                    byte[] Buf = new byte[16];
                    DataS.Read(Buf, 0, 16);
                    FileSize = long.Parse(MailSegment.BinToStr(Buf), NumberStyles.HexNumber);
                }
                else
                {
                    FileSize = DataS.Length;
                }
                DataS.Close();
            }
            FileSize__   = FileSize;
            SegmentCount = (int)(FileSize / SegmentSizeL);
            if ((FileSize % SegmentSizeL) > 0)
            {
                SegmentCount++;
            }
            Monitor.Exit(DataF_);
            return(SegmentCount);
        }
        /// <summary>
        /// Create or check the digest file
        /// </summary>
        /// <param name="DigestMode">Digest mode</param>
        /// <param name="DataFile_">Data file name</param>
        /// <param name="MapFile_">Map file name</param>
        /// <param name="DigestFile_">Digest file name</param>
        /// <param name="SegmentSize_">Segment size</param>
        public void Proc(int DigestMode, string DataFile_, string MapFile_, string DigestFile_, int SegmentSize_, bool PromptConfirm)
        {
            long DigestFileSize    = 0;
            int  DigestSegmentSize = 0;

            int SegmentSize = SegmentSize_;

            DigestSegmentSize = SegmentSize;

            MailFile MF = new MailFile();

            if (MF.Open(false, true, DataFile_, MapFile_))
            {
                MF.SetSegmentSize(SegmentSize);
                MF.CalcSegmentCount();

                long FileSize = MF.GetDataSize();
                DigestFileSize = FileSize;
                int SegmentCount__ = MF.GetSegmentCount();
                MailSegment.ConsoleLineToLog    = true;
                MailSegment.ConsoleLineToLogSum = true;
                MailSegment.Console_WriteLine("");
                MailSegment.Console_WriteLine("Data file size: " + FileSize);
                MailSegment.Console_WriteLine("Data segment count: " + SegmentCount__);
                MailSegment.ConsoleLineToLogSum = false;
                MailSegment.ConsoleLineToLog    = false;
                MailSegment.Console_WriteLine("");

                if (DigestMode != 0)
                {
                    MailFile MD = new MailFile();
                    if (MD.Open(true, DigestMode != 0, DigestFile_, null))
                    {
                        MD.SetSegmentSize(SegmentSize);
                        if (DigestFile_ != null)
                        {
                            MD.CalcSegmentCount();
                            DigestSegmentSize = MD.DigestSegmentSize;
                            DigestFileSize    = MD.DigestFileSize;
                        }
                        else
                        {
                            DigestSegmentSize = 0;
                            DigestFileSize    = 0;
                        }
                        MailSegment.Console_WriteLine("Data file size from digest file: " + DigestFileSize);
                        MailSegment.Console_WriteLine("Segment size from digest file: " + DigestSegmentSize);
                        MailSegment.Console_WriteLine("");
                        MD.Close();
                    }
                    else
                    {
                        MailSegment.Console_WriteLine("Digest file open error");
                    }
                }

                if (Program.PromptConfirm(PromptConfirm))
                {
                    if ((DigestMode == 1) && (DigestMode == 3))
                    {
                        MF.MapChange(1, 0);
                        MF.MapChange(2, 0);
                    }

                    if (DigestMode == 0)
                    {
                        try
                        {
                            if (File.Exists(DigestFile_))
                            {
                                File.Delete(DigestFile_);
                            }
                        }
                        catch
                        {
                            MailSegment.ConsoleLineToLog    = true;
                            MailSegment.ConsoleLineToLogSum = true;
                            MailSegment.Console_WriteLine("Digest file creation error");
                            MailSegment.ConsoleLineToLogSum = false;
                            MailSegment.ConsoleLineToLog    = false;
                            return;
                        }
                    }

                    MailFile MD = new MailFile();
                    if (MD.Open(true, DigestMode != 0, DigestFile_, null))
                    {
                        Stopwatch_ TSW = new Stopwatch_();
                        MailSegment.Log();
                        MailSegment.LogReset();
                        MailSegment.Log("Time stamp", "Processed segments since previous entry", "Totally processed segments", "All segments", "Processed bytes since previous entry", "Totally processed bytes", "All bytes");

                        MD.SetSegmentSize(SegmentSize);
                        if (DigestMode != 0)
                        {
                            if (DigestFile_ != null)
                            {
                                MD.CalcSegmentCount();
                                DigestSegmentSize = MD.DigestSegmentSize;
                                DigestFileSize    = MD.DigestFileSize;
                            }
                            else
                            {
                                DigestSegmentSize = 0;
                                DigestFileSize    = 0;
                            }
                        }
                        if ((DigestMode == 2) || (DigestMode == 3))
                        {
                            if (DigestSegmentSize == SegmentSize)
                            {
                                if (FileSize != DigestFileSize)
                                {
                                    MailSegment.Console_WriteLine("Data file size correction started");
                                    MF.ResizeData(DigestFileSize);
                                    MF.CalcSegmentCount();
                                    FileSize = MF.GetDataSize();
                                    MailSegment.Console_WriteLine("Data file size correction finished");
                                    MailSegment.Console_WriteLine("");
                                }
                                else
                                {
                                    MailSegment.Console_WriteLine("Data file size is correct");
                                    MailSegment.Console_WriteLine("");
                                }
                            }
                        }
                        if ((DigestSegmentSize == SegmentSize) && (FileSize == DigestFileSize))
                        {
                            if (DigestMode != 2)
                            {
                                Stopwatch_ SWProgress = new Stopwatch_();
                                long       SWWorkTime = 0;
                                SWProgress.Reset();

                                int DigestG = 0;
                                int DigestB = 0;

                                long ToLogSize         = 0;
                                bool PrintLastProgress = true;

                                for (int i = 0; i < SegmentCount__; i++)
                                {
                                    ToLogSize += MF.DataGetSize(i);
                                    if (DigestMode == 0)
                                    {
                                        if (DigestFile_ != null)
                                        {
                                            byte[] Temp = MF.DataGet(i);
                                            MD.DataSet(i, Temp, Temp.Length);
                                        }
                                        MF.MapSet(i, 1);
                                        DigestG++;
                                    }
                                    else
                                    {
                                        if ((DigestFile_ != null) && (MailSegment.BinToStr(MD.DataGetDigest(i)) == MailSegment.BinToStr(MF.DataGetDigest(i))))
                                        {
                                            MF.MapSet(i, 1);
                                            DigestG++;
                                        }
                                        else
                                        {
                                            MF.MapSet(i, 0);
                                            DigestB++;
                                        }
                                    }

                                    if (SWWorkTime < SWProgress.Elapsed())
                                    {
                                        while (SWWorkTime < SWProgress.Elapsed())
                                        {
                                            SWWorkTime += 1000L;
                                        }
                                        MailSegment.Console_WriteLine("Segment " + (i + 1) + "/" + SegmentCount__ + " (" + ((i + 1) * 100 / SegmentCount__) + "%)");
                                        MailSegment.Log(TSW.Elapsed().ToString(), MailSegment.LogDiffS(i + 1).ToString(), (i + 1).ToString(), SegmentCount__.ToString(), MailSegment.LogDiffB(ToLogSize).ToString(), ToLogSize.ToString(), FileSize.ToString());
                                        if ((i + 1) == SegmentCount__)
                                        {
                                            PrintLastProgress = false;
                                        }
                                    }
                                }
                                MF.ResizeMap();

                                if (PrintLastProgress)
                                {
                                    MailSegment.Console_WriteLine("Segment " + SegmentCount__ + "/" + SegmentCount__ + " (100%)");
                                    MailSegment.Log(TSW.Elapsed().ToString(), MailSegment.LogDiffS(SegmentCount__).ToString(), SegmentCount__.ToString(), SegmentCount__.ToString(), MailSegment.LogDiffB(ToLogSize).ToString(), ToLogSize.ToString(), FileSize.ToString());
                                }

                                MailSegment.ConsoleLineToLog    = true;
                                MailSegment.ConsoleLineToLogSum = true;
                                MailSegment.Console_WriteLine("");
                                MailSegment.Console_WriteLine("Total segments: " + (DigestG + DigestB));
                                if (DigestMode != 0)
                                {
                                    MailSegment.Console_WriteLine("Good segments: " + DigestG);
                                    MailSegment.Console_WriteLine("Bad segments: " + DigestB);
                                }
                                MailSegment.Console_WriteLine("Total time: " + MailSegment.TimeHMSM(TSW.Elapsed()));
                                MailSegment.ConsoleLineToLogSum = false;
                                MailSegment.ConsoleLineToLog    = false;
                            }
                            else
                            {
                                MailSegment.ConsoleLineToLog    = true;
                                MailSegment.ConsoleLineToLogSum = true;
                                MailSegment.Console_WriteLine("Data file contents are not checked");
                                MailSegment.Console_WriteLine("Total time: " + MailSegment.TimeHMSM(TSW.Elapsed()));
                                MailSegment.ConsoleLineToLogSum = false;
                                MailSegment.ConsoleLineToLog    = false;
                            }
                        }
                        else
                        {
                            MailSegment.ConsoleLineToLog    = true;
                            MailSegment.ConsoleLineToLogSum = true;
                            if (FileSize != DigestFileSize)
                            {
                                MailSegment.Console_WriteLine("Data file size mismatch");
                            }
                            if (DigestSegmentSize != SegmentSize)
                            {
                                MailSegment.Console_WriteLine("Segment size mismatch");
                            }
                            MailSegment.Console_WriteLine("Total time: " + MailSegment.TimeHMSM(TSW.Elapsed()));
                            MailSegment.ConsoleLineToLogSum = false;
                            MailSegment.ConsoleLineToLog    = false;
                        }

                        MD.Close();
                    }
                    else
                    {
                        MailSegment.ConsoleLineToLog    = true;
                        MailSegment.ConsoleLineToLogSum = true;
                        if (DigestMode == 0)
                        {
                            MailSegment.Console_WriteLine("Digest file creation error");
                        }
                        else
                        {
                            MailSegment.Console_WriteLine("Digest file open error");
                        }
                        MailSegment.ConsoleLineToLogSum = false;
                        MailSegment.ConsoleLineToLog    = false;
                    }
                }

                MF.Close();
            }
            else
            {
                MailSegment.ConsoleLineToLog    = true;
                MailSegment.ConsoleLineToLogSum = true;
                MailSegment.Console_WriteLine("Data file open error");
                MailSegment.ConsoleLineToLogSum = false;
                MailSegment.ConsoleLineToLog    = false;
            }
        }
 /// <summary>
 /// Open data/map file object with accessibility test before action
 /// </summary>
 /// <param name="DigestMode"></param>
 /// <param name="DataRead"></param>
 /// <param name="DataFile"></param>
 /// <param name="MapFile"></param>
 /// <returns></returns>
 public bool Open(bool DigestMode, bool DataRead, string DataFile, string MapFile)
 {
     MapDummy.Clear();
     OpenError         = "";
     ParamDigestMode   = DigestMode;
     ParamDataRead     = DataRead;
     ParamDataFile     = DataFile;
     ParamMapFile      = MapFile;
     SegmentSizeL      = 0;
     SegmentSize       = 0;
     SegmentCount      = 0;
     DigestFileSize    = 0;
     DigestSegmentSize = 0;
     try
     {
         if (DataFile != null)
         {
             IsDummyFile = DataFile.StartsWith(DummyFileSign, StringComparison.InvariantCulture);
             if (IsDummyFile)
             {
                 RandomSequence_ = RandomSequence.CreateRS(DataFile.Substring(1), MailSegment.RandomCacheStep);
                 if (RandomSequence_ == null)
                 {
                     throw new Exception(RandomSequence.ErrorMsg);
                 }
                 DummyFileSize = RandomSequence.DummyFileSize;
             }
             else
             {
                 FileStream Temp = DataOpen();
                 if (ParamDigestMode)
                 {
                     if (ParamDataRead)
                     {
                         if (Temp.Length < 32)
                         {
                             if (ParamDataRead)
                             {
                                 Temp.Close();
                                 OpenError = "Incorrect digest file";
                                 return(false);
                             }
                             else
                             {
                                 for (int i = 0; i < DigestSize; i++)
                                 {
                                     Temp.WriteByte((byte)'_');
                                 }
                                 Temp.Seek(0, SeekOrigin.Begin);
                             }
                         }
                         else
                         {
                             byte[] Buf1 = new byte[16];
                             byte[] Buf2 = new byte[16];
                             Temp.Seek(0, SeekOrigin.Begin);
                             Temp.Read(Buf1, 0, 16);
                             Temp.Read(Buf2, 0, 16);
                             Temp.Seek(0, SeekOrigin.Begin);
                             try
                             {
                                 DigestFileSize    = long.Parse(MailSegment.BinToStr(Buf1), NumberStyles.HexNumber);
                                 DigestSegmentSize = int.Parse(MailSegment.BinToStr(Buf2), NumberStyles.HexNumber);
                             }
                             catch
                             {
                                 Temp.Close();
                                 OpenError = "Incorrect digest file";
                                 return(false);
                             }
                         }
                     }
                 }
                 Temp.Close();
             }
         }
     }
     catch (Exception e)
     {
         OpenError = e.Message;
         return(false);
     }
     try
     {
         if (MapFile != null)
         {
             FileStream Temp = MapOpen();
             Temp.Close();
         }
     }
     catch (Exception e)
     {
         OpenError = e.Message;
         return(false);
     }
     return(true);
 }
        public void ResizeData()
        {
            if ((SegmentCount == 0) || (SegmentSize == 0))
            {
                return;
            }

            long FileSize__Min = (long)(SegmentCount - 1) * (long)(SegmentSize) + 1L;
            long FileSize__Max = (long)SegmentCount * (long)SegmentSize;

            Monitor.Enter(DataF_);
            if ((!IsDummyFile) && (ParamDataFile != null) && (!ParamDataRead))
            {
                FileStream DataS = ParamDigestMode ? DataOpenRW(false) : DataOpen();
                if (ParamDigestMode)
                {
                    if (DataS.Length >= 16L)
                    {
                        byte[] Buf1 = new byte[16];
                        //byte[] Buf2 = new byte[16];
                        DataS.Seek(0, SeekOrigin.Begin);
                        DataS.Read(Buf1, 0, 16);
                        //DataS.Read(Buf2, 0, 16);
                        DigestFileSize = 0;
                        try
                        {
                            DigestFileSize = long.Parse(MailSegment.BinToStr(Buf1), NumberStyles.HexNumber);
                            //DigestSegmentSize = int.Parse(MailSegment.BinToStr(Buf2), NumberStyles.HexNumber);
                        }
                        catch
                        {
                            DigestFileSize = 0;
                        }
                    }

                    long FileSizeDig = DigestFileSize;
                    if (FileSizeDig < FileSize__Min)
                    {
                        FileSizeDig = FileSize__Min;
                    }
                    if (FileSizeDig > FileSize__Max)
                    {
                        FileSizeDig = FileSize__Max;
                    }

                    DataS.Seek(0, SeekOrigin.Begin);
                    byte[] SegmentData = MailSegment.StrToBin(FileSizeDig.ToString("X").PadLeft(16, '0'));
                    DataS.Write(SegmentData, 0, 16);
                    SegmentData = MailSegment.StrToBin(SegmentSize.ToString("X").PadLeft(16, '0'));
                    DataS.Write(SegmentData, 0, 16);

                    long DigestDataSize__ = ((long)(SegmentCount + 1) * (long)DigestSize);
                    if (DataS.Length < DigestDataSize__)
                    {
                        DataS.Seek(0, SeekOrigin.End);
                        while (DataS.Length < DigestDataSize__)
                        {
                            DataS.Write(Dummy, 0, DigestSize);
                        }
                    }
                    DataS.SetLength(DigestDataSize__);
                }
                else
                {
                    if (DataS.Length < FileSize__Min)
                    {
                        DataS.SetLength(FileSize__Min);
                    }
                    if (DataS.Length > FileSize__Max)
                    {
                        DataS.SetLength(FileSize__Max);
                    }
                }
                DataS.Close();
            }
            Monitor.Exit(DataF_);
        }