From 919f45c9f2e9eb68eeec82f36c1f40185b554796 Mon Sep 17 00:00:00 2001 From: icedream Date: Wed, 22 Oct 2014 16:29:51 +0200 Subject: [PATCH] Implemented some addon.json stuff. --- src/addoncreator/Addon.cs | 29 +++++-- src/addoncreator/AddonJson.cs | 55 ++++++++++++ src/addoncreator/AddonWhitelist.cs | 87 +++++++++++++++++++ .../{BinaryCodecExt.cs => Extensions.cs} | 11 ++- .../GarrysMod.AddonCreator.csproj | 4 +- 5 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 src/addoncreator/AddonJson.cs create mode 100644 src/addoncreator/AddonWhitelist.cs rename src/addoncreator/{BinaryCodecExt.cs => Extensions.cs} (72%) diff --git a/src/addoncreator/Addon.cs b/src/addoncreator/Addon.cs index 113b359..4873058 100644 --- a/src/addoncreator/Addon.cs +++ b/src/addoncreator/Addon.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; using CRC32; +using Newtonsoft.Json; namespace GarrysMod.AddonCreator { @@ -132,10 +133,26 @@ namespace GarrysMod.AddonCreator throw new FileNotFoundException("Addon building requires a valid addon.json file."); } - // TODO: Check addon.json for errors - // TODO: Ignore or remove files marked to be ignored in addon.json - // TODO: Sort in alphabetic order - // TODO: Filter files by general whitelist + var files = Files; + + // Check for errors and ignores in addon.json + var addonJson = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Files["addon.json"].GetContents())); + addonJson.CheckForErrors(); + addonJson.RemoveIgnoredFiles(ref files); + + // Sort files + var resultingFiles = new SortedDictionary(files); + + // General whitelist + var blacklistedFiles = AddonWhitelist + .FindBlacklistedFiles(resultingFiles.Select(i => i.Key)) + .ToArray(); + if (blacklistedFiles.Any()) + { + throw new InvalidOperationException("Found files which aren't whitelisted. Remove or ignore those files before you retry packing your addon:" + + Environment.NewLine + Environment.NewLine + + string.Join(Environment.NewLine, blacklistedFiles)); + } using (var stream = new MemoryStream()) { @@ -175,7 +192,7 @@ namespace GarrysMod.AddonCreator throw new IndexOutOfRangeException("Number of addon files must not exceed " + uint.MaxValue + " elements."); } uint fileNum = 0; - foreach (var file in Files) + foreach (var file in resultingFiles) { fileNum++; sw.Write(fileNum); @@ -186,7 +203,7 @@ namespace GarrysMod.AddonCreator sw.Write((uint)0); // End of file list // File contents - foreach (var file in Files) + foreach (var file in resultingFiles) { if (file.Value.Size == 0) continue; diff --git a/src/addoncreator/AddonJson.cs b/src/addoncreator/AddonJson.cs new file mode 100644 index 0000000..dda8d46 --- /dev/null +++ b/src/addoncreator/AddonJson.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +namespace GarrysMod.AddonCreator +{ + public class AddonJson + { + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("tags")] + public List Tags { get; set; } + + [JsonProperty("ignore")] + public List Ignores { get; set; } + + public void CheckForErrors() + { + if (string.IsNullOrEmpty(Title)) + { + throw new MissingFieldException("Title is empty or not specified."); + } + + if (!string.IsNullOrEmpty(Description) && Description.Contains('\0')) + { + throw new InvalidDataException("Description contains NULL character."); + } + + if (string.IsNullOrEmpty(Type)) + { + throw new MissingFieldException("Type is empty or not specified."); + } + } + + public void RemoveIgnoredFiles(ref Dictionary files) + { + foreach (var key in files.Keys.ToArray()) + // ToArray makes a shadow copy of Keys to avoid "mid-loop-removal" conflicts + { + if (Ignores.Any(w => w.WildcardRegex().IsMatch(key))) + files.Remove(key); + } + } + } +} diff --git a/src/addoncreator/AddonWhitelist.cs b/src/addoncreator/AddonWhitelist.cs new file mode 100644 index 0000000..7cc5ade --- /dev/null +++ b/src/addoncreator/AddonWhitelist.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace GarrysMod.AddonCreator +{ + public class AddonWhitelist + { + private static readonly string[] Whitelist = + { + "addon.json", + "lua/*.lua", + "scenes/*.vcd", + "particles/*.pcf", + "resource/fonts/*.ttf", + "scripts/vehicles/*.txt", + "resource/localization/*/*.properties", + "maps/*.bsp", + "maps/*.nav", + "maps/*.ain", + "maps/thumb/*.png", + "sound/*.wav", + "sound/*.mp3", + "sound/*.ogg", + "materials/*.vmt", + "materials/*.vtf", + "materials/*.png", + "materials/*.jpg", + "materials/*.jpeg", + "models/*.mdl", + "models/*.vtx", + "models/*.phy", + "models/*.ani", + "models/*.vvd", + "gamemodes/*/*.txt", + "gamemodes/*/*.fgd", + "gamemodes/*/logo.png", + "gamemodes/*/icon24.png", + "gamemodes/*/gamemode/*.lua", + "gamemodes/*/entities/effects/*.lua", + "gamemodes/*/entities/weapons/*.lua", + "gamemodes/*/entities/entities/*.lua", + "gamemodes/*/backgrounds/*.png", + "gamemodes/*/backgrounds/*.jpg", + "gamemodes/*/backgrounds/*.jpeg", + "gamemodes/*/content/models/*.mdl", + "gamemodes/*/content/models/*.vtx", + "gamemodes/*/content/models/*.phy", + "gamemodes/*/content/models/*.ani", + "gamemodes/*/content/models/*.vvd", + "gamemodes/*/content/materials/*.vmt", + "gamemodes/*/content/materials/*.vtf", + "gamemodes/*/content/materials/*.png", + "gamemodes/*/content/materials/*.jpg", + "gamemodes/*/content/materials/*.jpeg", + "gamemodes/*/content/scenes/*.vcd", + "gamemodes/*/content/particles/*.pcf", + "gamemodes/*/content/resource/fonts/*.ttf", + "gamemodes/*/content/scripts/vehicles/*.txt", + "gamemodes/*/content/resource/localization/*/*.properties", + "gamemodes/*/content/maps/*.bsp", + "gamemodes/*/content/maps/*.nav", + "gamemodes/*/content/maps/*.ain", + "gamemodes/*/content/maps/thumb/*.png", + "gamemodes/*/content/sound/*.wav", + "gamemodes/*/content/sound/*.mp3", + "gamemodes/*/content/sound/*.ogg" + }; + + private static Regex[] RegularExpressions; + + static void ConvertWhitelist() + { + if (RegularExpressions != null) + return; + + RegularExpressions = Whitelist.Select(w => w.WildcardRegex).ToArray(); + } + + public static IEnumerable FindBlacklistedFiles(IEnumerable files) + { + return files.Where(f => RegularExpressions.Any(rx => !rx.IsMatch(f))); + } + } +} diff --git a/src/addoncreator/BinaryCodecExt.cs b/src/addoncreator/Extensions.cs similarity index 72% rename from src/addoncreator/BinaryCodecExt.cs rename to src/addoncreator/Extensions.cs index f1ddcc4..4308098 100644 --- a/src/addoncreator/BinaryCodecExt.cs +++ b/src/addoncreator/Extensions.cs @@ -3,11 +3,20 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; namespace GarrysMod.AddonCreator { - static class BinaryCodecExt + static class Extensions { + public static Regex WildcardRegex(this string pattern) + { + return new Regex("^" + Regex.Escape(pattern) + .Replace(@"\*", ".*") + .Replace(@"\?", ".") + + "$"); + } + public static string ReadString(this BinaryReader br, bool nullTerminated) { if (!nullTerminated) diff --git a/src/addoncreator/GarrysMod.AddonCreator.csproj b/src/addoncreator/GarrysMod.AddonCreator.csproj index d1cfd17..e7d1616 100644 --- a/src/addoncreator/GarrysMod.AddonCreator.csproj +++ b/src/addoncreator/GarrysMod.AddonCreator.csproj @@ -54,7 +54,9 @@ - + + +