private static void BuildPackage(ProgramArgs args, BuildConfigPackage buildConfigPackage) { var packageBasePath = Path.Combine(Path.GetDirectoryName(args.BuildConfigPath) ?? "", "src", buildConfigPackage.SourceName); var packageConfigPath = Path.Combine(packageBasePath, "config.json"); if (!File.Exists(packageConfigPath)) { throw new Exception($"Could not find config file for package {buildConfigPackage.SourceName} ({buildConfigPackage.DistributionName}): looking for {packageConfigPath}"); } var packageConfig = Serialization.Deserialize <PackageConfig>(File.ReadAllText(packageConfigPath)); var masterKey = new byte[0]; Console.WriteLine($"Building: {buildConfigPackage.SourceName} ({buildConfigPackage.DistributionName})"); var outPath = Path.Combine(args.OutPath, buildConfigPackage.DistributionName + ".mods"); using var fs = File.Open(outPath, FileMode.Create, FileAccess.Write); using var ms = new MemoryStream(); var packageHeader = new PackageHeader { Magic = 0x4459495A, CompilationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), EncryptionEnabled = packageConfig.EncryptFiles }; if (packageConfig.EncryptFiles) { packageHeader.KeyLength = KeyLength; masterKey = CryptUtil.GenerateKey(KeyLength); } BinaryUtils.MarshalStruct(ms, packageHeader); if (packageConfig.EncryptFiles) { byte[] xorTable = { 0x94, 0xce, 0xc3, 0xae, 0x73, 0xf9, 0xf1, 0xb9 }; for (var i = 0; i < masterKey.Length; i++) { ms.WriteByte((byte)(masterKey[i] ^ xorTable[i % xorTable.Length])); } } using (var zipFile = new ZipFile()) { if (packageConfig.EncryptFiles) { zipFile.Encryption = EncryptionAlgorithm.WinZipAes256; zipFile.Password = Encoding.ASCII.GetString(masterKey); } foreach (var packageConfigEntry in packageConfig.Entries) { ProcessPackageEntry(args, packageConfigEntry, buildConfigPackage, zipFile); } Console.WriteLine($"Saving: {buildConfigPackage.SourceName} ({buildConfigPackage.DistributionName})"); zipFile.Save(ms); } Console.WriteLine($"Flushing: {buildConfigPackage.SourceName} ({buildConfigPackage.DistributionName}) -> {outPath}"); ms.Position = 0; ms.CopyTo(fs); }
private static void ProcessFileEntry(ProgramArgs args, PackageEntry packageConfigEntry, BuildConfigPackage buildConfigPackage, ZipFile zipFile) { var dirName = Path.GetDirectoryName(packageConfigEntry.GamePath); if (!string.IsNullOrWhiteSpace(dirName)) { var newDirName = dirName; if (!newDirName.EndsWith("/")) { newDirName += "/"; } if (zipFile[newDirName] == null) { zipFile.AddDirectoryByName(newDirName); } } var packageBasePath = Path.Combine(Path.GetDirectoryName(args.BuildConfigPath) ?? "", "src", buildConfigPackage.SourceName); var path = Path.Combine(packageBasePath, packageConfigEntry.LocalPath); if (!File.Exists(path)) { throw new Exception($"Package {buildConfigPackage.SourceName}: Directory {path} does not exist"); } var data = File.ReadAllBytes(path); zipFile.AddEntry(packageConfigEntry.GamePath, data); }
private static void ProcessDirectoryEntry(ProgramArgs args, PackageEntry packageConfigEntry, BuildConfigPackage buildConfigPackage, ZipFile zipFile) { var packageBasePath = Path.Combine(Path.GetDirectoryName(args.BuildConfigPath) ?? "", "src", buildConfigPackage.SourceName); var directoryPath = Path.Combine(packageBasePath, packageConfigEntry.LocalPath); if (!Directory.Exists(directoryPath)) { throw new Exception($"Package {buildConfigPackage.SourceName}: Directory {directoryPath} does not exist"); } Console.WriteLine($"Read files from {directoryPath}..."); zipFile.AddDirectory(directoryPath, packageConfigEntry.GamePath); }
private static void ProcessPackageEntry(ProgramArgs args, PackageEntry packageConfigEntry, BuildConfigPackage buildConfigPackage, ZipFile zipFile) { switch (packageConfigEntry.Type) { // check entry type. if we're working with a file, just write the data - otherwise, create a hierarchy case PackageEntryType.File: ProcessFileEntry(args, packageConfigEntry, buildConfigPackage, zipFile); break; case PackageEntryType.Directory: ProcessDirectoryEntry(args, packageConfigEntry, buildConfigPackage, zipFile); break; default: throw new ArgumentOutOfRangeException(); } }