internal static Database Load(byte[] bytes)
{
/*
* Parse the enclosing file format that holds the
* compressed data and then decompress the data.
* */
uint version;
byte[] compressed;
byte[] md5;
using (MemoryStream stream = new MemoryStream(bytes)) {
using (BinaryReader reader = new BinaryReader(stream, Encoding.UTF8)) {
if (reader.ReadUInt64() != 0x5453494C5F465354) {
throw new InvalidDataException("The identifier in the header is invalid.");
}
version = reader.ReadUInt32();
if (version != 1 & 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);
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)) {
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();
int sourceSize;
byte[] sourceMd5;
if (version == 1) {
sourceSize = reader.ReadInt32();
sourceMd5 = reader.ReadBytes(16);
} else {
sourceSize = 0;
sourceMd5 = null;
}
database.Packages[i].Versions[j].Sources = new Source[reader.ReadInt32()];
for (int k = 0; k < database.Packages[i].Versions[j].Sources.Length; k++) {
if (version == 1) {
database.Packages[i].Versions[j].Sources[k].Size = sourceSize;
database.Packages[i].Versions[j].Sources[k].Md5 = sourceMd5;
} else {
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;
}