Пример #1
0
            // --- load ---
            /// <summary>Loads a database from a byte array.</summary>
            /// <param name="bytes">The byte array.</param>
            /// <returns>The database.</returns>
            internal static Database Load(byte[] bytes)
            {
                /*
                 * Parse the enclosing file format that holds the
                 * compressed (gzip) data and then decompress the data.
                 * */
                int version;

                byte[] compressed;
                byte[] md5;
                using (MemoryStream stream = new MemoryStream(bytes)) {
                    using (BinaryReader reader = new BinaryReader(stream, Encoding.UTF8)) {
                        // 0x5453494C5F46535 = "TSF_LIST"
                        if (reader.ReadUInt64() != 0x5453494C5F465354)
                        {
                            throw new InvalidDataException("The identifier in the header is invalid.");
                        }
                        version = reader.ReadInt32();
                        if (version != 2)
                        {
                            throw new InvalidDataException("The version number in the header is invalid.");
                        }
                        md5 = reader.ReadBytes(16);
                        int length = reader.ReadInt32();
                        compressed = reader.ReadBytes(length);
                        // 0x444E455F = "_END"
                        if (reader.ReadUInt32() != 0x444E455F)
                        {
                            throw new InvalidDataException("The identifier in the footer is invalid.");
                        }
                    }
                }
                byte[] check = (new MD5CryptoServiceProvider()).ComputeHash(compressed);
                for (int i = 0; i < 16; i++)
                {
                    if (md5[i] != check[i])
                    {
                        throw new InvalidDataException("The MD5 does not match.");
                    }
                }
                byte[] decompressed = Gzip.Decompress(compressed);

                /*
                 * Parse the raw file format and extract the database.
                 * */
                Database database = new Database();

                using (MemoryStream stream = new MemoryStream(decompressed)) {
                    using (BinaryReader reader = new BinaryReader(stream)) {
                        // 0x74727473 = "strt"
                        if (reader.ReadUInt32() != 0x74727473)
                        {
                            throw new InvalidDataException("The uncompressed stream is invalid.");
                        }
                        database.Packages = new Package[reader.ReadInt32()];
                        for (int i = 0; i < database.Packages.Length; i++)
                        {
                            database.Packages[i]          = new Package();
                            database.Packages[i].Name     = reader.ReadString();
                            database.Packages[i].Versions = new Version[reader.ReadInt32()];
                            for (int j = 0; j < database.Packages[i].Versions.Length; j++)
                            {
                                database.Packages[i].Versions[j]         = new Version();
                                database.Packages[i].Versions[j].Name    = database.Packages[i].Name;
                                database.Packages[i].Versions[j].Number  = reader.ReadString();
                                database.Packages[i].Versions[j].Sources = new Source[reader.ReadInt32()];
                                for (int k = 0; k < database.Packages[i].Versions[j].Sources.Length; k++)
                                {
                                    database.Packages[i].Versions[j].Sources[k].Size = reader.ReadInt32();
                                    database.Packages[i].Versions[j].Sources[k].MD5  = reader.ReadBytes(16);
                                    database.Packages[i].Versions[j].Sources[k].Url  = reader.ReadString();
                                }
                                database.Packages[i].Versions[j].Dependencies = new Dependency[reader.ReadInt32()];
                                for (int k = 0; k < database.Packages[i].Versions[j].Dependencies.Length; k++)
                                {
                                    database.Packages[i].Versions[j].Dependencies[k]         = new Dependency();
                                    database.Packages[i].Versions[j].Dependencies[k].Name    = reader.ReadString();
                                    database.Packages[i].Versions[j].Dependencies[k].Version = reader.ReadString();
                                }
                                database.Packages[i].Versions[j].Suggestions = new Dependency[reader.ReadInt32()];
                                for (int k = 0; k < database.Packages[i].Versions[j].Suggestions.Length; k++)
                                {
                                    database.Packages[i].Versions[j].Suggestions[k]         = new Dependency();
                                    database.Packages[i].Versions[j].Suggestions[k].Name    = reader.ReadString();
                                    database.Packages[i].Versions[j].Suggestions[k].Version = reader.ReadString();
                                }
                                database.Packages[i].Versions[j].Metadata = new KeyValuePair[reader.ReadInt32()];
                                for (int k = 0; k < database.Packages[i].Versions[j].Metadata.Length; k++)
                                {
                                    string key   = reader.ReadString();
                                    string value = reader.ReadString();
                                    database.Packages[i].Versions[j].Metadata[k] = new KeyValuePair(key, value);
                                }
                            }
                        }
                        if (reader.ReadUInt32() != 0x646E655F)
                        {
                            throw new InvalidDataException("The uncompressed stream is invalid.");
                        }
                    }
                }
                return(database);
            }
Пример #2
0
            /// <summary>Installs the specified package, but not its dependencies.</summary>
            /// <param name="version">The specific version of the package.</param>
            /// <param name="size">Accumulates the size of the downloaded data in an interlocked operation. If the operation fails, all accumulated size is subtracted again.</param>
            /// <returns>Whether the package was successfully installed.</returns>
            internal bool InstallPackage(Version version, ref int size)
            {
                try {
                    /*
                     * Check whether the package is protected.
                     * */
                    if (IsInstalledPackageProtected(version.Name))
                    {
                        return(false);
                    }

                    /*
                     * Remove existing versions of this package.
                     */
                    string packageDirectory = GetInstalledPackageDirectory(version.Name);
                    if (packageDirectory != null)
                    {
                        RemoveDirectory(packageDirectory);
                    }
                    else
                    {
                        packageDirectory = Path.Combine(Program.FileSystem.ManagedContentFolders[0], version.Name);
                    }

                    /*
                     * Install the package.
                     * */
                    Source[] sources = version.Sources;
                    Shuffle(sources);
                    int attemps = sources.Length == 1 ? 3 : sources.Length == 2 ? 2 : 1;
                    for (int a = 0; a < attemps; a++)
                    {
                        for (int i = 0; i < sources.Length; i++)
                        {
                            byte[] bytes;
                            if (Internet.TryDownloadBytesFromUrl(sources[i].Url, out bytes, ref size))
                            {
                                if (bytes.Length == sources[i].Size)
                                {
                                    byte[] md5 = (new MD5CryptoServiceProvider()).ComputeHash(bytes);
                                    bool   add = true;
                                    for (int k = 0; k < 16; k++)
                                    {
                                        if (md5[k] != sources[i].Md5[k])
                                        {
                                            add = false;
                                            break;
                                        }
                                    }
                                    if (add)
                                    {
                                        if (bytes.Length >= 2 && bytes[0] == 0x1F && bytes[1] == 0x8B)
                                        {
                                            /* GZIP-compressed */
                                            bytes = Gzip.Decompress(bytes);
                                        }
                                        if ((bytes.Length & 0x1FF) == 0)
                                        {
                                            /* TAR archive */
                                            RemoveDirectory(packageDirectory);
                                            CreateDirectory(packageDirectory);
                                            Tar.Unpack(bytes, packageDirectory, version.Name);
                                        }
                                        else
                                        {
                                            add = false;
                                        }
                                        if (add)
                                        {
                                            /*
                                             * The installation was successful. Save some of
                                             * the package information for offline storage.
                                             * */
                                            StringBuilder builder = new StringBuilder();
                                            builder.AppendLine("name = " + version.Name);
                                            builder.AppendLine("version = " + version.Number);
                                            if (version.Sources.Length != 0)
                                            {
                                                builder.Append("sources = ");
                                                for (int j = 0; j < version.Sources.Length; j++)
                                                {
                                                    if (j != 0)
                                                    {
                                                        builder.Append(',').Append(' ');
                                                    }
                                                    builder.Append(version.Sources[j].Url);
                                                }
                                                builder.AppendLine();
                                            }
                                            if (version.Dependencies.Length != 0)
                                            {
                                                builder.Append("dependencies = ");
                                                for (int j = 0; j < version.Dependencies.Length; j++)
                                                {
                                                    if (j != 0)
                                                    {
                                                        builder.Append(',').Append(' ');
                                                    }
                                                    builder.Append(version.Dependencies[j].Name);
                                                    builder.Append(' ').Append('(');
                                                    builder.Append(version.Dependencies[j].Version);
                                                    builder.Append(')');
                                                }
                                                builder.AppendLine();
                                            }
                                            if (version.Suggestions.Length != 0)
                                            {
                                                builder.Append("suggestions = ");
                                                for (int j = 0; j < version.Suggestions.Length; j++)
                                                {
                                                    if (j != 0)
                                                    {
                                                        builder.Append(',').Append(' ');
                                                    }
                                                    builder.Append(version.Suggestions[j].Name);
                                                    builder.Append(' ').Append('(');
                                                    builder.Append(version.Suggestions[j].Version);
                                                    builder.Append(')');
                                                }
                                                builder.AppendLine();
                                            }
                                            builder.AppendLine();
                                            foreach (KeyValuePair pair in version.Metadata)
                                            {
                                                if (
                                                    !string.Equals(pair.Key, "protected", StringComparison.OrdinalIgnoreCase) &&
                                                    !string.Equals(pair.Key, "wip", StringComparison.OrdinalIgnoreCase)
                                                    )
                                                {
                                                    builder.AppendLine(pair.ToString());
                                                }
                                            }
                                            string file = Path.Combine(packageDirectory, "package.cfg");
                                            File.WriteAllText(file, builder.ToString(), new UTF8Encoding(true));
                                            return(true);
                                        }
                                    }
                                }
                                Interlocked.Add(ref size, -bytes.Length);
                            }
                        }
                        Thread.Sleep(1000);
                    }
                    return(false);
                } catch {
                    return(false);
                }
            }