Index: third_party/sqlite/sqlite-src-3170000/tool/GetFile.cs |
diff --git a/third_party/sqlite/sqlite-src-3170000/tool/GetFile.cs b/third_party/sqlite/sqlite-src-3170000/tool/GetFile.cs |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2a62deb552d827bd04420504d1711af4c50ab2ff |
--- /dev/null |
+++ b/third_party/sqlite/sqlite-src-3170000/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 |
+ } |
+} |