Check-in [355de8cbb4]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added C# project for automatic updater for ZTreeWin.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | develop
Files: files | file ages | folders
SHA1:355de8cbb41048e980e2aefff3473172dee4b32a
User & Date: tinus 2018-03-12 00:30:32
Context
2018-03-12
02:28
Various improvements to ZTUpdater. Got rid of Html2Markdown, ported own poor man’s HtmlToText to C#, which appears to work better for this forum. check-in: 56d8711cc9 user: tinus tags: develop
00:30
Added C# project for automatic updater for ZTreeWin. check-in: 355de8cbb4 user: tinus tags: develop
2015-09-09
10:45
Auto-update form keeps track of the current executable and version up front, and uses that when necessary. check-in: 11941c0935 user: tinus tags: develop
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to .fossil-settings/ignore-glob.

10
11
12
13
14
15
16






































































































































































































































































*.GID
*.tvsconfig
*/out/
*.dcu
*.rsm
*.exe
*.dll













































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
*.GID
*.tvsconfig
*/out/
*.dcu
*.rsm
*.exe
*.dll

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
*/[Dd]ebug/
*/[Dd]ebugPublic/
*/[Rr]elease/
*/[Rr]eleases/
*/x64/
*/x86/
*/bld/
*/[Bb]in/
*/[Oo]bj/
*/[Ll]og/

# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# DNX
project.lock.json
project.fragment.lock.json
artifacts/

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
*.mdf
*.ldf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

Added ZTUpdater/App.config.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.7.1.0" newVersion="1.7.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Added ZTUpdater/Program.cs.





































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Diagnostics;
using System.Globalization;

namespace ZTUpdater
{
    class Program
    {
        [STAThread]
        static int Main(string[] args)
        {
            try
            {
                foreach (var arg in args)
                {
                    if (arg == "/?" || arg.StartsWith("/h", true, CultureInfo.CurrentCulture))
                    {
                        ShowHelp();
                        return 0;
                    }
                }

                var Updater = new ZTWUpdater(true)
                {
                    OnLog = (msg, level) =>
                    {
                        var Output = level >= TraceLevel.Warning ? Console.Error : Console.Out;
                        Output.WriteLine(msg);
                    }
                };
                var UpdateTask = Updater.Update();
                UpdateTask.Wait();
                return UpdateTask.Result ? 0 : 1;
            }
            catch (Exception ex)
            {
                var BackupColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Error.WriteLine(ex.Message);
                Console.ForegroundColor = BackupColor;
                return 255;
            }
        }

        private static void ShowHelp()
        {
            throw new NotImplementedException();
        }
    }
}

Added ZTUpdater/Properties/AssemblyInfo.cs.









































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ZTUpdater")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZTUpdater")]
[assembly: AssemblyCopyright("Copyright ©  2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("954f46ba-c534-4c0c-97b6-cbff10e25a86")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Added ZTUpdater/ZTUpdater.cs.

















































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Win32;
using Syroot.Windows.IO;

namespace ZTUpdater
{
    public class ZTWUpdater
    {
        public Action<string, TraceLevel> OnLog = (msg, level) => Debug.WriteLine(msg, level.ToString());

        public string ZTreeHome;
        public string Executable;
        public string CurrentVersion;
        public string LatestVersion;
        public string WhatsNew;

        public ZTWUpdater(bool askforLocationIfNecessary)
        {
            if (Environment.Is64BitOperatingSystem)
                Executable = "ZTW64.exe";
            else
                Executable = "ZTW.exe";
            
            // figure out where ZTreeWin is located
            ZTreeHome = GetZTreeHome(askforLocationIfNecessary);
            Executable = Path.Combine(ZTreeHome, Executable);

            // determine version of local executable
            CurrentVersion = FileVersionInfo.GetVersionInfo(Executable).FileVersion;
        }

        protected void Log(string message, TraceLevel level = TraceLevel.Verbose)
        {
            OnLog(message, level);
        }

        public string GetZTreeHome(bool askforLocationIfNecessary)
        {
            // from command-line arguments
            bool Found = false;
            foreach (var Arg in Environment.GetCommandLineArgs())
            {
                if (Found)
                    return Arg;
                else if (Arg == "/home")
                    Found = true;
            }

            // from the environment
            string ZTHome = Environment.GetEnvironmentVariable("#ZTHome");
            if (Directory.Exists(ZTHome))
                return ZTHome;

            // from registry (both Win32 and Win64)
            var InstallDir = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\ZTreeWin", "Install_Dir", null);
            if (InstallDir is string)
                return (string)InstallDir;
            if (Environment.Is64BitProcess)
            {
                InstallDir = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ZTreeWin", "Install_Dir", null);
                if (InstallDir is string)
                    return (string)InstallDir;
            }

            // otherwise, ask for folder (using dialog?)
            if (askforLocationIfNecessary)
            {
                var Dialog = new System.Windows.Forms.FolderBrowserDialog
                {
                    SelectedPath = @"C:\ZTree",
                    ShowNewFolderButton = false,
                    Description = "Please select the folder where ZTreeWin is installed"
                };
                if (Dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    return Dialog.SelectedPath;
            }
            return null;
        }

        private Regex _rexZetaAvailable = new Regex(@"forum_entry.php\?id=(\d+)""[^\<]*?v(\d+\.\S+) Now Available", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        private Regex _rexWhatsNew = new Regex(@"<div class=""posting"">(.*?)</div><p class=""signature"">", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
        private Regex _rexLink = new Regex(@"""(https?://www.z(edtek|tree).com\/[^""]*\.(zip|exe))""", RegexOptions.Compiled | RegexOptions.IgnoreCase);

        public async Task<Uri> GetUriLatestVersion()
        {
            using (var Client = new HttpClient())
            {
                // get the forum home page
                Log("Looking for announcement on ZTreeWin Forum...");
                var Response = await Client.GetAsync("https://www.ztw3.com/forum", HttpCompletionOption.ResponseContentRead);
                var Html = await Response.Content.ReadAsStringAsync();
                var Match = _rexZetaAvailable.Match(Html);
                if (!Match.Success)
                {
                    Log("None found.");
                    return null;
                }

                // Extract the version and the post’s ID
                string PostID = Match.Groups[1].Value;
                LatestVersion = Match.Groups[2].Value;
                Log($"Found announcement for version {LatestVersion}.");
                if (!IsVersionNewer(LatestVersion, CurrentVersion))
                    return null;

                // get the announcement post
                Response = await Client.GetAsync($"http://www.ztw3.com/forum/forum_entry.php?id={PostID}");
                Html = await Response.Content.ReadAsStringAsync();

                // extract the "What’s New"
                Match = _rexWhatsNew.Match(Html);
                if (Match.Success)
                {
                    WhatsNew = Match.Groups[1].Value;
                    try
                    {
                        WhatsNew = new Html2Markdown.Converter().Convert(WhatsNew);
                    }
                    catch
                    {
                        // ignore errors, just use the HTML instead
                    }
                    Log("What’s New:" + Environment.NewLine + WhatsNew, TraceLevel.Info);
                }

                // extract the download link
                Match = _rexLink.Match(Html);
                if (!Match.Success)
                {
                    Log($"No download link found for version {LatestVersion}!", TraceLevel.Warning);
                    return null;
                }
                // return the link
                Log("Download link found: " + Match.Groups[1].Value);
                return new Uri(Match.Groups[1].Value);
            }
        }

        public bool IsVersionNewer(string newVersion, string oldVersion)
        {
            var New = new Version(newVersion);
            var Old = new Version(oldVersion);
            return newVersion.CompareTo(oldVersion) >= 0;
        }

        public async Task<bool> Update()
        {
            Log($"ZTreeWin version {CurrentVersion} located in \"{ZTreeHome}\".", TraceLevel.Info);

            var DownloadUri = await GetUriLatestVersion();
            if (DownloadUri == null)
                return false;

            // Prepare to save the file in the user’s Downloads folder
            string OrgZipFile = DownloadUri.AbsolutePath;
            int Pos = OrgZipFile.LastIndexOf("/");
            if (Pos > -1)
                OrgZipFile = OrgZipFile.Substring(Pos + 1);
            OrgZipFile = Path.Combine(KnownFolders.Downloads.Path, OrgZipFile);

            string ZipFile = OrgZipFile;
            string Extension = Path.GetExtension(ZipFile);
            string Base = ZipFile.Substring(0, ZipFile.Length - Extension.Length);
            int Counter = 0;
            while (File.Exists(ZipFile))
            {
                Counter++;
                ZipFile = Base + $" ({Counter})" + Extension;
            }

            Log($@"Downloading updated file to ""{ZipFile}""...");
            using (var Client = new HttpClient())
            {
                var ZipStream = await Client.GetStreamAsync(DownloadUri);
                using (var FileStream = new FileStream(ZipFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read))
                {
                    await ZipStream.CopyToAsync(FileStream);
                }
            }

            // If the newly downloaded file is identical to the existing one, delete the new one and just reuse the old one.
            if (OrgZipFile != ZipFile)
            {
                bool IdenticalFiles;
                using (var Old = new FileStream(OrgZipFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (var New = new FileStream(ZipFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                    IdenticalFiles = Old.Length == New.Length && IdenticalStreams(Old, New);
                if (IdenticalFiles)
                {
                    File.Delete(ZipFile);
                    ZipFile = OrgZipFile;
                }
            }

            // Perform the update based on the downloaded file
            UpdateFromFile(ZipFile);
            return true;
        }

        public void UpdateFromFile(string file)
        {
            Log($"Extracting files...");
            var Zip = ZipFile.OpenRead(file);
            foreach(var Entry in Zip.Entries)
            {
                var File = new FileInfo(Path.Combine(ZTreeHome, Entry.FullName.Replace('/', '\\')));
                if (File.Exists)
                {
                    if (Identical(Entry, File))
                    {
                        Log($"\t{Entry.FullName}: identical to existing file; skipping.");
                        continue;
                    }

                    // rename as backup for current version
                    var Extension = File.Extension;
                    var BackupName = File.FullName.Substring(0, File.FullName.Length - Extension.Length) + "-v" + CurrentVersion + Extension;
                    Log($"\t{Entry.FullName}: backing up existing file.");
                    File.MoveTo(BackupName);
                }

                Log($"\t{Entry.FullName}: extracting...");
                Entry.ExtractToFile(File.FullName);
            }
        }

        private bool Identical(ZipArchiveEntry Entry, FileInfo File)
        {
            if (Entry.Length != File.Length)
                return false;

            using (var ZipStream = Entry.Open())
            using (var FileStream = File.OpenRead())
            using (var BufferedFileStream = new BufferedStream(FileStream))
            {
                return IdenticalStreams(ZipStream, BufferedFileStream);
            }
        }

        private bool IdenticalStreams(Stream a, Stream b)
        {
            const int BufferSize = 2048;
            byte[] BufferA = new byte[BufferSize];
            byte[] BufferB = new byte[BufferSize];

            bool AtEndOfA = false, AtEndOfB = false;
            while (!AtEndOfA && !AtEndOfB)
            {
                AtEndOfA = a.Read(BufferA, 0, BufferSize) == 0;
                AtEndOfB = b.Read(BufferB, 0, BufferSize) == 0;
                if (!BufferA.SequenceEqual(BufferB))
                    return false;
            }
            return (AtEndOfA == AtEndOfB);
        }
    }
}

Added ZTUpdater/ZTUpdater.csproj.





































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{954F46BA-C534-4C0C-97B6-CBFF10E25A86}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>ZTUpdater</RootNamespace>
    <AssemblyName>ZTUpdater</AssemblyName>
    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Html2Markdown, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\Html2Markdown.3.2.1.341\lib\net45\Html2Markdown.dll</HintPath>
    </Reference>
    <Reference Include="HtmlAgilityPack, Version=1.7.1.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
      <HintPath>packages\HtmlAgilityPack.1.7.1\lib\Net45\HtmlAgilityPack.dll</HintPath>
    </Reference>
    <Reference Include="Syroot.Windows.IO.KnownFolders, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>packages\Syroot.Windows.IO.KnownFolders.1.0.2\lib\net40\Syroot.Windows.IO.KnownFolders.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.IO.Compression" />
    <Reference Include="System.IO.Compression.FileSystem" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="ZTUpdater.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
    <None Include="packages.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Added ZTUpdater/ZTUpdater.sln.



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZTUpdater", "ZTUpdater.csproj", "{954F46BA-C534-4C0C-97B6-CBFF10E25A86}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{954F46BA-C534-4C0C-97B6-CBFF10E25A86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{954F46BA-C534-4C0C-97B6-CBFF10E25A86}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{954F46BA-C534-4C0C-97B6-CBFF10E25A86}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{954F46BA-C534-4C0C-97B6-CBFF10E25A86}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {C45EA399-3FFF-45C0-890F-A9316C06448C}
	EndGlobalSection
EndGlobal

Added ZTUpdater/packages.config.













>
>
>
>
>
>
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Html2Markdown" version="3.2.1.341" targetFramework="net461" />
  <package id="HtmlAgilityPack" version="1.7.1" targetFramework="net461" />
  <package id="Syroot.Windows.IO.KnownFolders" version="1.0.2" targetFramework="net461" />
</packages>