| Index: third_party/sqlite/sqlite-src-3100200/tool/GetFile.cs
|
| diff --git a/third_party/sqlite/sqlite-src-3100200/tool/GetFile.cs b/third_party/sqlite/sqlite-src-3100200/tool/GetFile.cs
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2a62deb552d827bd04420504d1711af4c50ab2ff
|
| --- /dev/null
|
| +++ b/third_party/sqlite/sqlite-src-3100200/tool/GetFile.cs
|
| @@ -0,0 +1,450 @@
|
| +/*
|
| +** 2015 October 7
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +** This file contains C# code to download a single file based on a URI.
|
| +*/
|
| +
|
| +using System;
|
| +using System.ComponentModel;
|
| +using System.Diagnostics;
|
| +using System.IO;
|
| +using System.Net;
|
| +using System.Reflection;
|
| +using System.Runtime.InteropServices;
|
| +using System.Threading;
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +#region Assembly Metadata
|
| +[assembly: AssemblyTitle("GetFile Tool")]
|
| +[assembly: AssemblyDescription("Download a single file based on a URI.")]
|
| +[assembly: AssemblyCompany("SQLite Development Team")]
|
| +[assembly: AssemblyProduct("SQLite")]
|
| +[assembly: AssemblyCopyright("Public Domain")]
|
| +[assembly: ComVisible(false)]
|
| +[assembly: Guid("5c4b3728-1693-4a33-a218-8e6973ca15a6")]
|
| +[assembly: AssemblyVersion("1.0.*")]
|
| +
|
| +#if DEBUG
|
| +[assembly: AssemblyConfiguration("Debug")]
|
| +#else
|
| +[assembly: AssemblyConfiguration("Release")]
|
| +#endif
|
| +#endregion
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +namespace GetFile
|
| +{
|
| + /// <summary>
|
| + /// This enumeration is used to represent all the possible exit codes from
|
| + /// this tool.
|
| + /// </summary>
|
| + internal enum ExitCode
|
| + {
|
| + /// <summary>
|
| + /// The file download was a success.
|
| + /// </summary>
|
| + Success = 0,
|
| +
|
| + /// <summary>
|
| + /// The command line arguments are missing (i.e. null). Generally,
|
| + /// this should not happen.
|
| + /// </summary>
|
| + MissingArgs = 1,
|
| +
|
| + /// <summary>
|
| + /// The wrong number of command line arguments was supplied.
|
| + /// </summary>
|
| + WrongNumArgs = 2,
|
| +
|
| + /// <summary>
|
| + /// The URI specified on the command line could not be parsed as a
|
| + /// supported absolute URI.
|
| + /// </summary>
|
| + BadUri = 3,
|
| +
|
| + /// <summary>
|
| + /// The file name portion of the URI specified on the command line
|
| + /// could not be extracted from it.
|
| + /// </summary>
|
| + BadFileName = 4,
|
| +
|
| + /// <summary>
|
| + /// The temporary directory is either invalid (i.e. null) or does not
|
| + /// represent an available directory.
|
| + /// </summary>
|
| + BadTempPath = 5,
|
| +
|
| + /// <summary>
|
| + /// An exception was caught in <see cref="Main" />. Generally, this
|
| + /// should not happen.
|
| + /// </summary>
|
| + Exception = 6,
|
| +
|
| + /// <summary>
|
| + /// The file download was canceled. This tool does not make use of
|
| + /// the <see cref="WebClient.CancelAsync" /> method; therefore, this
|
| + /// should not happen.
|
| + /// </summary>
|
| + DownloadCanceled = 7,
|
| +
|
| + /// <summary>
|
| + /// The file download encountered an error. Further information about
|
| + /// this error should be displayed on the console.
|
| + /// </summary>
|
| + DownloadError = 8
|
| + }
|
| +
|
| + ///////////////////////////////////////////////////////////////////////////
|
| +
|
| + internal static class Program
|
| + {
|
| + #region Private Data
|
| + /// <summary>
|
| + /// This is used to synchronize multithreaded access to the
|
| + /// <see cref="previousPercent" /> and <see cref="exitCode"/>
|
| + /// fields.
|
| + /// </summary>
|
| + private static readonly object syncRoot = new object();
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + /// <summary>
|
| + /// This event will be signed when the file download has completed,
|
| + /// even if the file download itself was canceled or unsuccessful.
|
| + /// </summary>
|
| + private static EventWaitHandle doneEvent;
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + /// <summary>
|
| + /// The previous file download completion percentage seen by the
|
| + /// <see cref="DownloadProgressChanged" /> event handler. This value
|
| + /// is never decreased, nor is it ever reset to zero.
|
| + /// </summary>
|
| + private static int previousPercent = 0;
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + /// <summary>
|
| + /// This will be the exit code returned by this tool after the file
|
| + /// download completes, successfully or otherwise. This value is only
|
| + /// changed by the <see cref="DownloadFileCompleted" /> event handler.
|
| + /// </summary>
|
| + private static ExitCode exitCode = ExitCode.Success;
|
| + #endregion
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + #region Private Support Methods
|
| + /// <summary>
|
| + /// This method displays an error message to the console and/or
|
| + /// displays the command line usage information for this tool.
|
| + /// </summary>
|
| + /// <param name="message">
|
| + /// The error message to display, if any.
|
| + /// </param>
|
| + /// <param name="usage">
|
| + /// Non-zero to display the command line usage information.
|
| + /// </param>
|
| + private static void Error(
|
| + string message,
|
| + bool usage
|
| + )
|
| + {
|
| + if (message != null)
|
| + Console.WriteLine(message);
|
| +
|
| + string fileName = Path.GetFileName(
|
| + Process.GetCurrentProcess().MainModule.FileName);
|
| +
|
| + Console.WriteLine(String.Format("usage: {0} <uri>", fileName));
|
| + }
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + /// <summary>
|
| + /// This method attempts to determine the file name portion of the
|
| + /// specified URI.
|
| + /// </summary>
|
| + /// <param name="uri">
|
| + /// The URI to process.
|
| + /// </param>
|
| + /// <returns>
|
| + /// The file name portion of the specified URI -OR- null if it cannot
|
| + /// be determined.
|
| + /// </returns>
|
| + private static string GetFileName(
|
| + Uri uri
|
| + )
|
| + {
|
| + if (uri == null)
|
| + return null;
|
| +
|
| + string pathAndQuery = uri.PathAndQuery;
|
| +
|
| + if (String.IsNullOrEmpty(pathAndQuery))
|
| + return null;
|
| +
|
| + int index = pathAndQuery.LastIndexOf('/');
|
| +
|
| + if ((index < 0) || (index == pathAndQuery.Length))
|
| + return null;
|
| +
|
| + return pathAndQuery.Substring(index + 1);
|
| + }
|
| + #endregion
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + #region Private Event Handlers
|
| + /// <summary>
|
| + /// This method is an event handler that is called when the file
|
| + /// download completion percentage changes. It will display progress
|
| + /// on the console. Special care is taken to make sure that progress
|
| + /// events are not displayed out-of-order, even if duplicate and/or
|
| + /// out-of-order events are received.
|
| + /// </summary>
|
| + /// <param name="sender">
|
| + /// The source of the event.
|
| + /// </param>
|
| + /// <param name="e">
|
| + /// Information for the event being processed.
|
| + /// </param>
|
| + private static void DownloadProgressChanged(
|
| + object sender,
|
| + DownloadProgressChangedEventArgs e
|
| + )
|
| + {
|
| + if (e != null)
|
| + {
|
| + int percent = e.ProgressPercentage;
|
| +
|
| + lock (syncRoot)
|
| + {
|
| + if (percent > previousPercent)
|
| + {
|
| + Console.Write('.');
|
| +
|
| + if ((percent % 10) == 0)
|
| + Console.Write(" {0}% ", percent);
|
| +
|
| + previousPercent = percent;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + /// <summary>
|
| + /// This method is an event handler that is called when the file
|
| + /// download has completed, successfully or otherwise. It will
|
| + /// display the overall result of the file download on the console,
|
| + /// including any <see cref="Exception" /> information, if applicable.
|
| + /// The <see cref="exitCode" /> field is changed by this method to
|
| + /// indicate the overall result of the file download and the event
|
| + /// within the <see cref="doneEvent" /> field will be signaled.
|
| + /// </summary>
|
| + /// <param name="sender">
|
| + /// The source of the event.
|
| + /// </param>
|
| + /// <param name="e">
|
| + /// Information for the event being processed.
|
| + /// </param>
|
| + private static void DownloadFileCompleted(
|
| + object sender,
|
| + AsyncCompletedEventArgs e
|
| + )
|
| + {
|
| + if (e != null)
|
| + {
|
| + lock (syncRoot)
|
| + {
|
| + if (previousPercent < 100)
|
| + Console.Write(' ');
|
| + }
|
| +
|
| + if (e.Cancelled)
|
| + {
|
| + Console.WriteLine("Canceled");
|
| +
|
| + lock (syncRoot)
|
| + {
|
| + exitCode = ExitCode.DownloadCanceled;
|
| + }
|
| + }
|
| + else
|
| + {
|
| + Exception error = e.Error;
|
| +
|
| + if (error != null)
|
| + {
|
| + Console.WriteLine("Error: {0}", error);
|
| +
|
| + lock (syncRoot)
|
| + {
|
| + exitCode = ExitCode.DownloadError;
|
| + }
|
| + }
|
| + else
|
| + {
|
| + Console.WriteLine("Done");
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (doneEvent != null)
|
| + doneEvent.Set();
|
| + }
|
| + #endregion
|
| +
|
| + ///////////////////////////////////////////////////////////////////////
|
| +
|
| + #region Program Entry Point
|
| + /// <summary>
|
| + /// This is the entry-point for this tool. It handles processing the
|
| + /// command line arguments, setting up the web client, downloading the
|
| + /// file, and saving it to the file system.
|
| + /// </summary>
|
| + /// <param name="args">
|
| + /// The command line arguments.
|
| + /// </param>
|
| + /// <returns>
|
| + /// Zero upon success; non-zero on failure. This will be one of the
|
| + /// values from the <see cref="ExitCode" /> enumeration.
|
| + /// </returns>
|
| + private static int Main(
|
| + string[] args
|
| + )
|
| + {
|
| + //
|
| + // NOTE: Sanity check the command line arguments.
|
| + //
|
| + if (args == null)
|
| + {
|
| + Error(null, true);
|
| + return (int)ExitCode.MissingArgs;
|
| + }
|
| +
|
| + if (args.Length != 1)
|
| + {
|
| + Error(null, true);
|
| + return (int)ExitCode.WrongNumArgs;
|
| + }
|
| +
|
| + //
|
| + // NOTE: Attempt to convert the first (and only) command line
|
| + // argument to an absolute URI.
|
| + //
|
| + Uri uri;
|
| +
|
| + if (!Uri.TryCreate(args[0], UriKind.Absolute, out uri))
|
| + {
|
| + Error("Could not create absolute URI from argument.", false);
|
| + return (int)ExitCode.BadUri;
|
| + }
|
| +
|
| + //
|
| + // NOTE: Attempt to extract the file name portion of the URI we
|
| + // just created.
|
| + //
|
| + string fileName = GetFileName(uri);
|
| +
|
| + if (fileName == null)
|
| + {
|
| + Error("Could not extract the file name from the URI.", false);
|
| + return (int)ExitCode.BadFileName;
|
| + }
|
| +
|
| + //
|
| + // NOTE: Grab the temporary path setup for this process. If it is
|
| + // unavailable, we will not continue.
|
| + //
|
| + string directory = Path.GetTempPath();
|
| +
|
| + if (String.IsNullOrEmpty(directory) ||
|
| + !Directory.Exists(directory))
|
| + {
|
| + Error("Temporary directory is invalid or unavailable.", false);
|
| + return (int)ExitCode.BadTempPath;
|
| + }
|
| +
|
| + try
|
| + {
|
| + using (WebClient webClient = new WebClient())
|
| + {
|
| + //
|
| + // NOTE: Create the event used to signal completion of the
|
| + // file download.
|
| + //
|
| + doneEvent = new ManualResetEvent(false);
|
| +
|
| + //
|
| + // NOTE: Hookup the event handlers we care about on the web
|
| + // client. These are necessary because the file is
|
| + // downloaded asynchronously.
|
| + //
|
| + webClient.DownloadProgressChanged +=
|
| + new DownloadProgressChangedEventHandler(
|
| + DownloadProgressChanged);
|
| +
|
| + webClient.DownloadFileCompleted +=
|
| + new AsyncCompletedEventHandler(
|
| + DownloadFileCompleted);
|
| +
|
| + //
|
| + // NOTE: Build the fully qualified path and file name,
|
| + // within the temporary directory, where the file to
|
| + // be downloaded will be saved.
|
| + //
|
| + fileName = Path.Combine(directory, fileName);
|
| +
|
| + //
|
| + // NOTE: If the file name already exists (in the temporary)
|
| + // directory, delete it.
|
| + //
|
| + // TODO: Perhaps an error should be raised here instead?
|
| + //
|
| + if (File.Exists(fileName))
|
| + File.Delete(fileName);
|
| +
|
| + //
|
| + // NOTE: After kicking off the asynchronous file download
|
| + // process, wait [forever] until the "done" event is
|
| + // signaled.
|
| + //
|
| + Console.WriteLine(
|
| + "Downloading \"{0}\" to \"{1}\"...", uri, fileName);
|
| +
|
| + webClient.DownloadFileAsync(uri, fileName);
|
| + doneEvent.WaitOne();
|
| + }
|
| +
|
| + lock (syncRoot)
|
| + {
|
| + return (int)exitCode;
|
| + }
|
| + }
|
| + catch (Exception e)
|
| + {
|
| + //
|
| + // NOTE: An exception was caught. Report it via the console
|
| + // and return failure.
|
| + //
|
| + Error(e.ToString(), false);
|
| + return (int)ExitCode.Exception;
|
| + }
|
| + }
|
| + #endregion
|
| + }
|
| +}
|
|
|