static void DownloadFile(Uri uri, InstallerPackage package, InstallerFile file)
 {
     if (package.RemotePath != "")
         uri = new Uri (uri, package.RemotePath);//why the fuc should there be a '--' operator in the implementation there?
     using (Stream stream = Fetch (uri, file.Name)) {
         string plp = package.InstallPath;
         if (plp == "")
             plp = "./";
         string path = Path.Combine (plp, file.Name);
         if (!HashCompare (Wack (stream, path), file.SHA256SUM)) {//VERY DANGEROUS if for any reason we fail to delete a malicously downloaded file we're royally screwed
             File.Delete (path);
         }
     }
 }
 static bool PlatformSupportsPackage(InstallerPackage package)
 {
     if (package.Bits != null) {
         if (Environment.Is64BitProcess && (package.Bits != 64)) {//who knows, maybe 64 bit ain't enough for everyone
             return false;
         }
         if (!Environment.Is64BitProcess && (package.Bits != 32)) {
             return false;
         }
     }
     if (package.Platform != Platform.Common) {
         if ((Environment.OSVersion.Platform == PlatformID.Win32NT) ^ (package.Platform == Platform.Windows)) {
             return false;
         }
         if ((Environment.OSVersion.Platform == PlatformID.Unix) ^ (package.Platform == Platform.Linux)) {
             return false;
         }
     }
     return true;
 }
 static void DownloadEntirePackage(Uri uri, InstallerPackage package)
 {
     foreach (InstallerFile file in package.Files) {
         DownloadFile (uri, package, file);
     }
 }
 static void DownloadDeltaPackage(Uri uri, InstallerPackage local, InstallerPackage remote, IDictionary<string, InstallerFileTuple> files)
 {
     foreach (var file in files.Values) {
         if ((file.Local != null) && (file.Remote == null)) {
             DeleteFile (local, file.Local);
         }
         if ((file.Local == null) && (file.Remote != null)) {
             DownloadFile (uri, remote, file.Remote);
         }
         if ((file.Local != null) && (file.Remote != null)) {
             string localPath = Path.Combine (local.InstallPath, file.Local.Name);
             if (System.IO.File.Exists (localPath)) {
                 using (Stream stream = File.OpenRead (localPath)) {
                     if (!HashCompare (stream, file.Remote.SHA256SUM)) {
                         stream.Close ();
                         if (DeleteFile (local, file.Local)) { //download file if not changed localy
                             DownloadFile (uri, remote, file.Remote);
                         }
                     }
                 }
             } else {
                 DownloadFile (uri, remote, file.Remote);
             }
         }
     }
 }
 static bool DeleteFile(InstallerPackage package, InstallerFile file)
 {
     string path = Path.Combine (package.InstallPath, file.Name);
     if (!File.Exists (path)) //we don't have to delete it:P
         return true;
     bool compResult;
     using (var stream = File.OpenRead (path)) {
         compResult = HashCompare (stream, file.SHA256SUM);
     }
     if (compResult)
         File.Delete (path);
     return compResult;
 }
 static void DeleteEntirePackage(InstallerPackage package)
 {
     string plp = package.InstallPath;
     if (plp == "")
         plp = "./";
     foreach (var f in package.Files) {
         File.Delete (Path.Combine (plp, f.Name));
     }
     if (!Directory.EnumerateFiles (plp).GetEnumerator ().MoveNext ()) {
         Directory.Delete (plp);//delete directory if empty
     }
 }
        static void Configure(Queue<string> queue)
        {
            string output = null;
            InstallerConfiguration installerConfiguration = new InstallerConfiguration ();
            bool autoDiscovery = false;
            string version = null;
            List<string> uris = new List<string> ();
            List<InstallerPackage> packages = new List<InstallerPackage> ();
            List<string> certificates = new List<string> ();
            List<string> ignore = new List<string> ();
            while (queue.Count > 0) {
                switch (queue.Dequeue ()) {
                case "--output":
                    output = queue.Dequeue ();
                    break;
                case "--auto-discovery":
                    autoDiscovery = true;
                    break;
                case "--certificate":
                    certificates.Add (queue.Dequeue ());
                    break;
                case "--version":
                    version = queue.Dequeue ();
                    break;
                case "--ignore":
                    while (!queue.Peek ().StartsWith ("--", StringComparison.Ordinal)) {
                        ignore.Add (queue.Dequeue ());
                    }
                    break;
                case "--package":
                    InstallerPackage package = new InstallerPackage ();
                    while (queue.Count > 0) {
                        string current = queue.Peek ();
                        if (current.StartsWith ("--", StringComparison.Ordinal)) {
                            break;
                        }
                        queue.Dequeue ();
                        const string name = "name=";
                        if (current.StartsWith (name, StringComparison.Ordinal)) {
                            package.Name = current.Substring (name.Length);
                        }
                        const string platform = "platform=";
                        if (current.StartsWith (platform, StringComparison.Ordinal)) {
                            package.Platform = (Platform)Enum.Parse (typeof(Platform), current.Substring (platform.Length));
                        }
                        const string bits = "bits=";
                        if (current.StartsWith (bits, StringComparison.Ordinal)) {
                            package.Bits = ushort.Parse (current.Substring (bits.Length));
                        }
                        const string installPath = "install-path=";
                        if (current.StartsWith (installPath, StringComparison.Ordinal)) {
                            package.InstallPath = current.Substring (installPath.Length);
                        }
                        const string remotePath = "remote-path=";
                        if (current.StartsWith (remotePath, StringComparison.Ordinal)) {
                            package.RemotePath = current.Substring (remotePath.Length);
                        }
                        const string executable = "executable=";
                        if (current.StartsWith (executable, StringComparison.Ordinal)) {
                            package.ExecutableName = current.Substring (executable.Length);
                        }
                    }
                    packages.Add (package);
                    break;
                case "--uri":
                    uris.Add (queue.Dequeue ());
                    break;
                }
            }
            Dictionary<string, InstallerPackage> pathes = new  Dictionary<string, InstallerPackage> ();

            foreach (InstallerPackage package in packages) {
                string prp = package.RemotePath;
                if (prp == "")
                    prp = "./";
                prp = Path.GetFullPath (prp);
                int packagePathLen = prp.Length;

                List<InstallerFile> files = new List<InstallerFile> ();
                foreach (var file in Directory.GetFiles (prp, "*", SearchOption.AllDirectories)) {
                    bool belongsToMe = !pathes.ContainsKey (file);
                    if (!belongsToMe) {
                        continue;
                    }
                    pathes.Add (file, package);
                    string relativePath = file.Substring (packagePathLen);
                    if (ignore.Contains (relativePath))
                        continue;
                    InstallerFile installerFile = new InstallerFile ();
                    installerFile.Name = relativePath;
                    using (Stream stream = File.OpenRead (file)) {
                        installerFile.SHA256SUM = ComputeHash (stream);
                    }
                    files.Add (installerFile);
                }
                package.Files = files.ToArray ();
            }

            installerConfiguration.AutoDiscovery = autoDiscovery;
            installerConfiguration.Version = version;
            installerConfiguration.Packages = packages.ToArray ();
            installerConfiguration.URIs = uris.ToArray ();
            installerConfiguration.Certificates = new byte[certificates.Count][];
            for (int i = 0; i != certificates.Count; i++)
                installerConfiguration.Certificates [i] = File.ReadAllBytes (certificates [i]);
            var xmlSerializer = CreateSerializer ();
            using (Stream outputStream = File.Open (output, FileMode.CreateNew)) {
                xmlSerializer.Serialize (outputStream, installerConfiguration);
                outputStream.Flush ();
            }
        }