示例#1
0
 /// <summary>
 /// Adds a new RantDictionaryTable object to the collection.
 /// </summary>
 /// <param name="table"></param>
 /// <param name="mergeBehavior">The merging strategy to employ.</param>
 public void AddTable(RantDictionaryTable table, TableMergeBehavior mergeBehavior = TableMergeBehavior.Naive)
 {
     RantDictionaryTable oldTable;
     if (_tables.TryGetValue(table.Name, out oldTable))
     {
         oldTable.Merge(table, mergeBehavior);
     }
     else
     {
         _tables[table.Name] = table;
     }
 }
示例#2
0
        /// <summary>
        /// Adds a new RantDictionaryTable object to the collection.
        /// </summary>
        /// <param name="table"></param>
        /// <param name="mergeBehavior">The merging strategy to employ.</param>
        public void AddTable(RantDictionaryTable table, TableMergeBehavior mergeBehavior = TableMergeBehavior.Naive)
        {
            RantDictionaryTable oldTable;

            if (_tables.TryGetValue(table.Name, out oldTable))
            {
                oldTable.Merge(table, mergeBehavior);
            }
            else
            {
                _tables[table.Name] = table;
            }
        }
示例#3
0
 /// <summary>
 /// Adds a new <see cref="RantDictionaryTable" /> object to the dictionary.
 /// </summary>
 /// <param name="table">The table to add.</param>
 public void AddTable(RantDictionaryTable table)
 {
     if (_tables.TryGetValue(table.Name, out RantDictionaryTable oldTable))
     {
         if (ReferenceEquals(table, oldTable))
         {
             return;
         }
         oldTable.Merge(table);
     }
     else
     {
         _tables[table.Name] = table;
     }
 }
示例#4
0
 /// <summary>
 /// Adds another table's entries to the current table, given that they share the same name and term count.
 /// </summary>
 /// <param name="other">The table whose entries will be added to the current instance.</param>
 /// <returns>True if merge succeeded; otherwise, False.</returns>
 public bool Merge(RantDictionaryTable other)
 {
     if (other.Name != Name || other == this)
     {
         return(false);
     }
     if (other.TermsPerEntry != TermsPerEntry)
     {
         return(false);
     }
     _entriesHash.AddRange(other._entriesHash);
     _entriesList.AddRange(other._entriesHash);
     _dirty = true;
     RebuildCache();
     return(true);
 }
示例#5
0
        /// <summary>
        /// Adds another table's entries to the current table, given that they share the same name and subtypes.
        /// </summary>
        /// <param name="other">The table whose entries will be added to the current instance.</param>
        /// <param name="mergeBehavior">The merging strategy to employ.</param>
        /// <returns>True if merge succeeded; otherwise, False.</returns>
        public bool Merge(RantDictionaryTable other, TableMergeBehavior mergeBehavior = TableMergeBehavior.Naive)
        {
            if (other._name != _name || other == this)
            {
                return(false);
            }
            if (!other._subtypes.SequenceEqual(_subtypes))
            {
                return(false);
            }
            int oldLength = _entries.Length;

            switch (mergeBehavior)
            {
            case TableMergeBehavior.Naive:
                Array.Resize(ref _entries, _entries.Length + other._entries.Length);
                Array.Copy(other._entries, 0, _entries, oldLength, other._entries.Length);
                break;

            case TableMergeBehavior.RemoveEntryDuplicates:                     // TODO: Make this NOT O(n^2*subtypes) -- speed up with HashSet?
            {
                var otherEntries =
                    other._entries.Where(e => !_entries.Any(ee => ee.Terms.SequenceEqual(e.Terms))).ToArray();
                Array.Resize(ref _entries, _entries.Length + otherEntries.Length);
                Array.Copy(otherEntries, 0, _entries, oldLength, otherEntries.Length);
                break;
            }

            case TableMergeBehavior.RemoveFirstTermDuplicates:                     // TODO: Make this NOT O(n^2)
            {
                var otherEntries =
                    other._entries.Where(e => _entries.All(ee => ee.Terms[0] != e.Terms[0])).ToArray();
                Array.Resize(ref _entries, _entries.Length + otherEntries.Length);
                Array.Copy(otherEntries, 0, _entries, oldLength, otherEntries.Length);
                break;
            }
            }

            return(true);
        }
示例#6
0
        public void BuildCache(RantDictionaryTable table)
        {
            lock (syncObject)
            {
                ClearAll();

                foreach (var entry in table.GetEntries())
                {
                    foreach (var cl in entry.GetClasses())
                    {
                        HashSet <RantDictionaryEntry> set;
                        _allClasses.Add(cl);
                        if (!_cache.TryGetValue(cl, out set))
                        {
                            set = _cache[cl] = GetPool();
                        }
                        set.Add(entry);
                    }
                }

                foreach (var cl in _allClasses)
                {
                    if (!_invCache.TryGetValue(cl, out HashSet <RantDictionaryEntry> set))
                    {
                        set = _invCache[cl] = GetPool();
                    }
                    foreach (var entry in table.GetEntries())
                    {
                        if (!entry.ContainsClass(cl))
                        {
                            set.Add(entry);
                        }
                    }
                }
            }
        }
示例#7
0
            public static void ConstructTable(string origin, string name, Dictionary <string, int> subs, ref int termCount, ref RantDictionaryTable table)
            {
                if (table != null)
                {
                    return;
                }
                if (name == null)
                {
                    throw new RantTableLoadException(origin, 1, 1, "err-table-missing-name");
                }

                if (termCount == 0 || subs.Count == 0)
                {
                    subs.Add("default", 0);
                    termCount = 1;
                }

                table = new RantDictionaryTable(name, termCount);

                foreach (var sub in subs)
                {
                    table.AddSubtype(sub.Key, sub.Value);
                }
            }
示例#8
0
 /// <summary>
 /// Loads all dictionary (.dic) files from the specified directory and returns a Dictionary object that contains the loaded data.
 /// </summary>
 /// <param name="directory">The directory from which to load dictionaries.</param>
 /// <param name="filter">Indicates whether dictionary entries marked with the #nsfw flag should be loaded.</param>
 /// <returns></returns>
 public static RantDictionary FromDirectory(string directory, NsfwFilter filter)
 {
     return(new RantDictionary(Directory.GetFiles(directory, "*.dic", SearchOption.AllDirectories).Select(file => RantDictionaryTable.FromFile(file, filter)).ToList()));
 }
示例#9
0
 /// <summary>
 /// Adds a new RantDictionaryTable object to the collection.
 /// </summary>
 /// <param name="dictionary"></param>
 public void AddTable(RantDictionaryTable dictionary)
 {
     _tables[dictionary.Name] = dictionary;
 }
示例#10
0
        public IEnumerable <RantDictionaryEntry> Filter(IEnumerable <ClassFilterRule> rules, RantDictionary dictionary, RantDictionaryTable table)
        {
            lock (syncObject)
            {
                int startIndex = 0;
                var ruleArray  = rules as ClassFilterRule[] ?? rules.ToArray();
                HashSet <RantDictionaryEntry> setCached;
                var set  = GetPool();
                var hide = table.HiddenClasses
                           // Exclude overridden hidden classes
                           .Except(dictionary.IncludedHiddenClasses)
                           // Exclude hidden classes filtered for
                           .Where(cl => !ruleArray.Any(rule => rule.ShouldMatch && String.Equals(rule.Class, cl, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                // Get initial pool
                if (hide.Length > 0)
                {
                    // Retrieve the inverse pool of the first hidden class
                    if (!_invCache.TryGetValue(hide[0], out setCached))
                    {
                        setCached = table.EntriesHash;
                    }
                }
                else if (ruleArray.Length > 0)
                {
                    if (ruleArray[0].ShouldMatch)
                    {
                        if (!_cache.TryGetValue(ruleArray[0].Class, out setCached))
                        {
                            return(null);
                        }
                    }
                    else
                    {
                        if (!_invCache.TryGetValue(ruleArray[0].Class, out setCached))
                        {
                            setCached = table.EntriesHash;
                        }
                    }
                    startIndex = 1;
                }
                else
                {
                    setCached = table.EntriesHash;
                }

                // Transfer items from cached pool to our new pool and exclude hidden classes
                foreach (var item in setCached)
                {
                    if (hide.Length == 0 || !hide.Any(cl => item.ContainsClass(cl)))
                    {
                        set.Add(item);
                    }
                }

                // Apply filters by intersecting pools
                for (int i = startIndex; i < ruleArray.Length; i++)
                {
                    if (ruleArray[i].ShouldMatch)
                    {
                        if (_cache.TryGetValue(ruleArray[i].Class, out setCached))
                        {
                            set.IntersectWith(setCached);
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    else
                    {
                        if (_invCache.TryGetValue(ruleArray[i].Class, out setCached))
                        {
                            set.IntersectWith(setCached);
                        }
                    }
                }

                return(set);
            }
        }
示例#11
0
            public static void ReadTerms(string origin, string str, int len, int line, ref int i,
                                         RantDictionaryTable table, RantDictionaryEntry activeTemplate, Dictionary <string, RantDictionaryEntry> templates, out RantDictionaryEntry result)
            {
                SkipSpace(str, len, ref i);
                int  t      = 0;
                var  terms  = new RantDictionaryTerm[table.TermsPerEntry];
                int  split  = -1;
                char c      = '\0';
                var  buffer = new StringBuilder();
                var  white  = new StringBuilder();

                while (i < len)
                {
                    switch (c = str[i++])
                    {
                    // Inline comment
                    case '#':
                        goto done;

                    // Phrasal split operator
                    case '+':
                        if (split > -1)
                        {
                            throw new RantTableLoadException(origin, line, i, "err-table-multiple-splits");
                        }
                        white.Length = 0;
                        split        = buffer.Length;
                        SkipSpace(str, len, ref i);
                        break;

                    // Term reference
                    case '[':
                    {
                        SkipSpace(str, len, ref i);
                        if (i >= len)
                        {
                            throw new RantTableLoadException(origin, line, i, "err-table-incomplete-term-reference");
                        }
                        int start = i;
                        if (white.Length > 0)
                        {
                            buffer.Append(white);
                            white.Length = 0;
                        }
                        switch (str[i++])
                        {
                        // Current term from active template
                        case ']':
                            if (t == -1)
                            {
                                throw new RantTableLoadException(origin, line, start + 1, "err-table-no-template");
                            }
                            buffer.Append(activeTemplate[t].Value);
                            break;

                        // Custom term from active template
                        case '.':
                        {
                            if (activeTemplate == null)
                            {
                                throw new RantTableLoadException(origin, line, start + 1, "err-table-no-template");
                            }
                            while (i < len && IsValidSubtypeChar(str[i]))
                            {
                                i++;                                                   // Read subtype name
                            }
                            if (str[i] != ']')
                            {
                                throw new RantTableLoadException(origin, line, i, "err-table-incomplete-term-reference");
                            }
                            string subName = str.Substring(start + 1, i - start - 1);
                            if (subName.Length == 0)
                            {
                                throw new RantTableLoadException(origin, line, start + 1, "err-table-empty-subtype-reference");
                            }
                            int templateSubIndex = table.GetSubtypeIndex(subName);
                            if (templateSubIndex == -1)
                            {
                                throw new RantTableLoadException(origin, line, start + 1, "err-table-nonexistent-subtype", subName);
                            }

                            // Add term value to buffer
                            buffer.Append(activeTemplate[templateSubIndex].Value);
                            i++;         // Skip past closing bracket
                            break;
                        }

                        // It is probably a reference to another entry, let's see.
                        default:
                        {
                            while (i < len && IsValidSubtypeChar(str[i]) || str[i] == '.')
                            {
                                i++;
                            }
                            if (str[i] != ']')
                            {
                                throw new RantTableLoadException(origin, line, i, "err-table-incomplete-term-reference");
                            }
                            var id = str.Substring(start, i - start).Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                            switch (id.Length)
                            {
                            // It's just a template ID.
                            case 1:
                            {
                                if (!templates.TryGetValue(id[0], out RantDictionaryEntry entry))
                                {
                                    throw new RantTableLoadException(origin, line, start + 1, "err-table-entry-not-found");
                                }
                                // Append term value to buffer
                                buffer.Append(entry[t].Value);
                                break;
                            }

                            // Template ID and custom subtype
                            case 2:
                            {
                                if (!templates.TryGetValue(id[0], out RantDictionaryEntry entry))
                                {
                                    throw new RantTableLoadException(origin, line, start + 1, "err-table-entry-not-found");
                                }
                                int templateSubIndex = table.GetSubtypeIndex(id[1]);
                                if (templateSubIndex == -1 || templateSubIndex >= table.TermsPerEntry)
                                {
                                    throw new RantTableLoadException(origin, line, start + 1, "err-table-nonexistent-subtype", id[1]);
                                }
                                buffer.Append(entry[templateSubIndex].Value);
                                break;
                            }

                            // ???
                            default:
                                throw new RantTableLoadException(origin, line, start + 1, "err-table-invalid-term-reference");
                            }

                            i++;         // Skip past closing bracket
                            break;
                        }
                        }
                        break;
                    }

                    case '\\':
                    {
                        if (white.Length > 0)
                        {
                            buffer.Append(white);
                            white.Length = 0;
                        }
                        switch (c = str[i++])
                        {
                        case 'n':
                            buffer.Append('\n');
                            continue;

                        case 'r':
                            buffer.Append('\r');
                            continue;

                        case 't':
                            buffer.Append('\t');
                            continue;

                        case 'v':
                            buffer.Append('\v');
                            continue;

                        case 'f':
                            buffer.Append('\f');
                            continue;

                        case 'b':
                            buffer.Append('\b');
                            continue;

                        case 's':
                            buffer.Append(' ');
                            continue;

                        case 'u':
                        {
                            if (i + 4 > len)
                            {
                                throw new RantTableLoadException(origin, line, i + 1, "err-table-incomplete-escape");
                            }
                            if (!ushort.TryParse(str.Substring(i, 4), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out ushort codePoint))
                            {
                                throw new RantTableLoadException(origin, line, i + 1, "err-table-unrecognized-codepoint");
                            }
                            buffer.Append((char)codePoint);
                            i += 4;
                            continue;
                        }

                        case 'U':
                        {
                            if (i + 8 > len)
                            {
                                throw new RantTableLoadException(origin, line, i + 1, "err-table-incomplete-escape");
                            }
                            if (!Util.TryParseSurrogatePair(str.Substring(i, 8), out char high, out char low))
                            {
                                throw new RantTableLoadException(origin, line, i + 1, "err-table-unrecognized-codepoint");
                            }
                            buffer.Append(high).Append(low);
                            i += 8;
                            continue;
                        }

                        default:
                            buffer.Append(c);
                            continue;
                        }
                        continue;
                    }

                    case ',':
                        if (t >= terms.Length)
                        {
                            throw new RantTableLoadException(origin, line, i, "err-table-too-many-terms", terms.Length, t);
                        }
                        terms[t++]    = new RantDictionaryTerm(buffer.ToString(), split);
                        buffer.Length = 0;
                        white.Length  = 0;
                        split         = -1;
                        SkipSpace(str, len, ref i);
                        break;

                    default:
                        if (char.IsWhiteSpace(c))
                        {
                            white.Append(c);
                        }
                        else
                        {
                            if (white.Length > 0)
                            {
                                buffer.Append(white);
                                white.Length = 0;
                            }
                            buffer.Append(c);
                        }
                        continue;
                    }
                }

done:

                if (t != terms.Length - 1)
                {
                    throw new RantTableLoadException(origin, line, i, "err-table-too-few-terms", terms.Length, t + 1);
                }

                terms[t] = new RantDictionaryTerm(buffer.ToString());

                result = new RantDictionaryEntry(terms);

                // Add classes from template
                if (activeTemplate != null)
                {
                    foreach (string cl in activeTemplate.GetRequiredClasses())
                    {
                        result.AddClass(cl, false);
                    }
                    foreach (string cl in activeTemplate.GetOptionalClasses())
                    {
                        result.AddClass(cl, true);
                    }
                }
            }
示例#12
0
		static void GenerateTable(string tablePath, RantDictionaryTable table, string rootDir, string entriesDir)
		{
			var tableClasses = new HashSet<string>();
			foreach (var entry in table.GetEntries())
			{
				foreach (var entryClass in entry.GetClasses())
				{
					tableClasses.Add(entryClass);
				}
			}

			File.WriteAllText(rootDir + "/" + "table-" + table.Name + ".html", PageGenerator.GenerateTablePage(table, tablePath));

			foreach (var tableClass in tableClasses)
			{
				File.WriteAllText(entriesDir + "/" + table.Name + "-" + tableClass + ".html", PageGenerator.GenerateTableClassPage(table, tableClass));
			}

			File.WriteAllText(entriesDir + "/" + table.Name + ".html", PageGenerator.GenerateTableClassPage(table, ""));
		}
示例#13
0
        public static string GenerateTablePage(RantDictionaryTable table, string filename)
        {
            int entryCount = table.GetEntries().Count();

            // Get all the classes
            var tableClasses = new HashSet<string>();
            foreach (var entryClass in table.GetEntries().SelectMany(entry => entry.GetClasses()))
            {
                tableClasses.Add(entryClass);
            }

            var text = new StringWriter();

            using (var writer = new HtmlTextWriter(text))
            {
                writer.WriteLine("<!DOCTYPE html>");

                writer.RenderBeginTag(HtmlTextWriterTag.Html);

                // Header
                writer.RenderBeginTag(HtmlTextWriterTag.Head);

                // Title
                writer.RenderBeginTag(HtmlTextWriterTag.Title);
                writer.WriteEncodedText(table.Name);
                writer.RenderEndTag();

                // Stylesheet
                writer.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
                writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");
                writer.AddAttribute(HtmlTextWriterAttribute.Href, "dicdoc.css");
                writer.RenderBeginTag(HtmlTextWriterTag.Link);
                writer.RenderEndTag();

                writer.RenderEndTag(); // </head>

                writer.RenderBeginTag(HtmlTextWriterTag.Body);

                // Header
                writer.RenderBeginTag(HtmlTextWriterTag.H1);
                writer.WriteEncodedText("<" + table.Name + ">");
                writer.RenderEndTag();

                // Description
                writer.RenderBeginTag(HtmlTextWriterTag.P);
                writer.WriteEncodedText("The ");
                writer.RenderBeginTag(HtmlTextWriterTag.B);
                writer.WriteEncodedText(table.Name);
                writer.RenderEndTag(); // </b>
                writer.WriteEncodedText(
                    $" table ({Path.GetFileName(filename)}) contains {entryCount} {(entryCount == 1 ? " entry" : " entries")} and {tableClasses.Count} {(tableClasses.Count == 1 ? " class" : " classes")}.");
                writer.RenderEndTag(); // </p>

                // Subtypes
                if (table.Subtypes.Length == 1)
                {
                    writer.WriteEncodedText("It has one subtype: ");
                    writer.RenderBeginTag(HtmlTextWriterTag.B);
                    writer.WriteEncodedText(table.Subtypes[0]);
                    writer.RenderEndTag();
                    writer.WriteEncodedText(".");
                }
                else
                {
                    writer.WriteEncodedText("It has " + table.Subtypes.Length + (table.Subtypes.Length == 1 ? " subtype" : " subtypes")
                        + ": ");
                    for(int i = 0; i < table.Subtypes.Length; i++)
                    {
                        if (i == table.Subtypes.Length - 1)
                            writer.WriteEncodedText(table.Subtypes.Length == 2 ? " and " :  "and ");

                        writer.RenderBeginTag(HtmlTextWriterTag.B);
                        writer.WriteEncodedText(table.Subtypes[i]);
                        writer.RenderEndTag();

                        if (i < table.Subtypes.Length - 1 && table.Subtypes.Length > 2)
                            writer.WriteEncodedText(", ");
                    }
                    writer.WriteEncodedText(".");
                }

                // Separator
                writer.RenderBeginTag(HtmlTextWriterTag.Hr);
                writer.RenderEndTag();

                // "View All" link
                writer.AddAttribute(HtmlTextWriterAttribute.Href, "entries/" + table.Name + ".html");
                writer.RenderBeginTag(HtmlTextWriterTag.A);

                writer.WriteEncodedText("Browse All Entries");

                writer.RenderEndTag(); // </a>

                // Class list
                writer.RenderBeginTag(HtmlTextWriterTag.H2);
                writer.WriteEncodedText("Classes");
                writer.RenderEndTag(); // </h2>

                writer.RenderBeginTag(HtmlTextWriterTag.Ul);

                foreach (var tableClass in tableClasses)
                {
                    writer.RenderBeginTag(HtmlTextWriterTag.Li);
                    
                    writer.AddAttribute(HtmlTextWriterAttribute.Href, "entries/" + table.Name + "-" + tableClass + ".html");
                    writer.RenderBeginTag(HtmlTextWriterTag.A);
                    writer.WriteEncodedText(tableClass);
                    writer.RenderEndTag(); // </a>

                    writer.RenderEndTag(); // </li>
                }

                writer.RenderEndTag(); // </ul>

                writer.RenderEndTag(); // </body>

                writer.RenderEndTag(); // </html>
            }

            return text.ToString();
        }
示例#14
0
        /// <summary>
        /// Adds another table's entries to the current table, given that they share the same name and subtypes.
        /// </summary>
        /// <param name="other">The table whose entries will be added to the current instance.</param>
        /// <param name="mergeBehavior">The merging strategy to employ.</param>
        /// <returns>True if merge succeeded; otherwise, False.</returns>
        public bool Merge(RantDictionaryTable other, TableMergeBehavior mergeBehavior = TableMergeBehavior.Naive)
        {
            if (other._name != _name || other == this) return false;
            if (!other._subtypes.SequenceEqual(_subtypes)) return false;
            int oldLength = _entries.Length;
            switch (mergeBehavior)
            {
                case TableMergeBehavior.Naive:
                    Array.Resize(ref _entries, _entries.Length + other._entries.Length);
                    Array.Copy(other._entries, 0, _entries, oldLength, other._entries.Length);
                    break;
                case TableMergeBehavior.RemoveEntryDuplicates: // TODO: Make this NOT O(n^2*subtypes) -- speed up with HashSet?
                    {
                        var otherEntries =
                            other._entries.Where(e => !_entries.Any(ee => ee.Terms.SequenceEqual(e.Terms))).ToArray();
                        Array.Resize(ref _entries, _entries.Length + otherEntries.Length);
                        Array.Copy(otherEntries, 0, _entries, oldLength, otherEntries.Length);
                        break;
                    }
                case TableMergeBehavior.RemoveFirstTermDuplicates: // TODO: Make this NOT O(n^2)
                    {
                        var otherEntries =
                            other._entries.Where(e => _entries.All(ee => ee.Terms[0] != e.Terms[0])).ToArray();
                        Array.Resize(ref _entries, _entries.Length + otherEntries.Length);
                        Array.Copy(otherEntries, 0, _entries, oldLength, otherEntries.Length);
                        break;
                    }
            }

            return true;
        }
示例#15
0
        /// <summary>
        /// Loads a package from the specified stream and returns it as a RantPackage object.
        /// </summary>
        /// <param name="source">The stream to load the package data from.</param>
        /// <returns></returns>
        public static RantPackage Load(Stream source)
        {
            using (var reader = new EasyReader(source))
            {
                var magic = Encoding.ASCII.GetString(reader.ReadBytes(4));
                if (magic == OLD_MAGIC)
                    return LoadOldPackage(reader);
                if (magic != MAGIC)
                    throw new InvalidDataException("File is corrupt.");
                var package = new RantPackage();
                var version = reader.ReadUInt32();
                if (version != PACKAGE_VERSION)
                    throw new InvalidDataException("Invalid package version: " + version);
                var compress = reader.ReadBoolean();
                var size = reader.ReadInt32();
                var data = reader.ReadBytes(size);
                if (compress)
                    data = EasyCompressor.Decompress(data);
                var doc = BsonDocument.Read(data);

                var info = doc["info"];
				if (info == null)
					throw new InvalidDataException("Metadata is missing from package.");

				package.Title = info["title"];
				package.ID = info["id"];
				package.Version = RantPackageVersion.Parse(info["version"]);
				package.Description = info["description"];
	            package.Authors = (string[])info["authors"];
				package.Tags = (string[])info["tags"];
				var deps = info["dependencies"];
				if (deps != null && deps.IsArray)
				{
					for(int i = 0; i < deps.Count; i++)
					{
						var dep = deps[i];
						var depId = dep["id"].Value;
						var depVersion = dep["version"].Value;
						bool depAllowNewer = (bool)dep["allow-newer"].Value;
						package.AddDependency(new RantPackageDependency(depId.ToString(), depVersion.ToString()) { AllowNewer = depAllowNewer });
					}
				}

				var patterns = doc["patterns"];
                if(patterns != null)
                {
                    var names = patterns.Keys;
                    foreach (string name in names)
                        package.AddPattern(new RantPattern(name, RantPatternOrigin.File, patterns[name]));
                }

                var tables = doc["tables"];
                if(tables != null)
                {
                    var names = tables.Keys;
                    foreach(string name in names)
                    {
                        var table = tables[name];
                        string tableName = table["name"];
                        string[] tableSubs = (string[])table["subs"];
                        string[] hiddenClasses = (string[])table["hidden"];

                        var entries = new List<RantDictionaryEntry>();
                        var entryList = table["entries"];
                        for(var i = 0; i < entryList.Count; i++)
                        {
                            var loadedEntry = entryList[i];
                            int weight = 1;
                            if (loadedEntry.HasKey("weight"))
                                weight = (int)loadedEntry["weight"].Value;
                            string[] requiredClasses = (string[])loadedEntry["classes"];
                            string[] optionalClasses = (string[])loadedEntry["optional_classes"];
                            var terms = new List<RantDictionaryTerm>();
                            var termList = loadedEntry["terms"];
                            for(var j = 0; j < termList.Count; j++)
                            {
                                var t = new RantDictionaryTerm(termList[j]["value"], termList[j]["pron"]);
                                terms.Add(t);
                            }
                            var entry = new RantDictionaryEntry(
                                terms.ToArray(),
                                requiredClasses.Concat(optionalClasses.Select(x => x + "?")),
                                weight
                            );
                            entries.Add(entry);
                        }
                        var rantTable = new RantDictionaryTable(
                            tableName,
                            tableSubs,
                            entries,
                            hiddenClasses
                        );
                        package.AddTable(rantTable);
                    }
                }

                return package;
            }
        }
示例#16
0
 /// <summary>
 /// Loads all dictionary (.dic) files from the specified directories and returns a Dictionary object that contains the loaded data.
 /// </summary>
 /// <param name="directories">The directories from which to load dictionaries.</param>
 /// <param name="filter">Indicates whether dictionary entries marked with the #nsfw flag should be loaded.</param>
 /// <returns></returns>
 public static RantDictionary FromMultiDirectory(string[] directories, NsfwFilter filter)
 {
     return(new RantDictionary(directories.SelectMany(path => Directory.GetFiles(path, "*.dic", SearchOption.AllDirectories)).Select(file => RantDictionaryTable.FromFile(file, filter))));
 }
示例#17
0
        public static string GenerateTableClassPage(RantDictionaryTable table, string tableClass)
        {
            bool all = String.IsNullOrEmpty(tableClass);

            var entries = all ? table.GetEntries() : table.GetEntries().Where(e => e.ContainsClass(tableClass));

            var text = new StringWriter();

            using (var writer = new HtmlTextWriter(text))
            {
                writer.WriteLine("<!DOCTYPE html>");

                writer.RenderBeginTag(HtmlTextWriterTag.Html);

                // Header
                writer.RenderBeginTag(HtmlTextWriterTag.Head);

                // Title
                writer.RenderBeginTag(HtmlTextWriterTag.Title);
                writer.WriteEncodedText((all ? table.Name : table.Name + ": " + tableClass) + " entries");
                writer.RenderEndTag();

                // Stylesheet
                writer.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
                writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");
                writer.AddAttribute(HtmlTextWriterAttribute.Href, "../dicdoc.css");
                writer.RenderBeginTag(HtmlTextWriterTag.Link);
                writer.RenderEndTag();

                writer.RenderEndTag(); // </head>

                // Body
                writer.RenderBeginTag(HtmlTextWriterTag.Body);

                // Heading
                writer.RenderBeginTag(HtmlTextWriterTag.H1);
                writer.WriteEncodedText("<" + table.Name + (all ? "" : "-" + tableClass) + ">");
                writer.RenderEndTag();

                // Entry list
                foreach (var e in entries)
                {
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "entry");
                    writer.RenderBeginTag(HtmlTextWriterTag.Div);

                    // Terms
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "termset");
                    writer.RenderBeginTag(HtmlTextWriterTag.Div);

                    for (int i = 0; i < e.Terms.Length; i++)
                    {
                        writer.AddAttribute(HtmlTextWriterAttribute.Class, "term");
                        writer.RenderBeginTag(HtmlTextWriterTag.Span);
                        writer.WriteEncodedText(e.Terms[i].Value);

                        if (e.Terms[i].PronunciationParts.Length > 0)
                        {
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "terminfo");
                            writer.RenderBeginTag(HtmlTextWriterTag.Span);
                            writer.RenderBeginTag(HtmlTextWriterTag.I);
                            writer.WriteEncodedText(" [" + e.Terms[i].Pronunciation + "]");
                            writer.RenderEndTag(); // </i>
                            writer.RenderEndTag(); // </span>
                        }

                        // Subtype
                        writer.AddAttribute(HtmlTextWriterAttribute.Class, "subtype");
                        writer.RenderBeginTag(HtmlTextWriterTag.Span);
                        writer.WriteEncodedText(i < table.Subtypes.Length ? table.Subtypes[i] : "???");
                        writer.RenderEndTag();

                        writer.RenderEndTag();
                    }

                    writer.RenderEndTag();

                    // Notes
                    var notes = new List<HtmlGenFunc>();
                    var otherClasses = e.GetClasses().Where(cl => cl != tableClass);

                    if (e.Terms.All(t => t.PronunciationParts.Length > 0))
                        notes.Add(html => html.WriteEncodedText("Full pronunciation"));
                    else if (e.Terms.Any(t => t.PronunciationParts.Length > 0))
                        notes.Add(html => html.WriteEncodedText("Partial pronunciation"));

                    if (e.Weight != 1) notes.Add(html => html.WriteEncodedText("Weight: " + e.Weight));

                    if (all && e.GetClasses().Any())
                    {
                        notes.Add(html =>
                        {
                            html.WriteEncodedText("Classes: ");
                            var classes = e.GetClasses().ToArray();
                            for (int i = 0; i < classes.Length; i++)
                            {
                                if (i > 0) html.WriteEncodedText(", ");

                                html.AddAttribute(HtmlTextWriterAttribute.Href, $"{table.Name}-{classes[i]}.html");
                                html.RenderBeginTag(HtmlTextWriterTag.A);
                                html.WriteEncodedText(classes[i]);
                                html.RenderEndTag();
                            }
                        });
                    }
                    else if (otherClasses.Any())
                    {
                        notes.Add(html =>
                        {
                            html.WriteEncodedText("Classes: ");
                            var classes = otherClasses.ToArray();
                            for (int i = 0; i < classes.Length; i++)
                            {
                                if (i > 0) html.WriteEncodedText(", ");

                                html.AddAttribute(HtmlTextWriterAttribute.Href, $"{table.Name}-{classes[i]}.html");
                                html.RenderBeginTag(HtmlTextWriterTag.A);
                                html.WriteEncodedText(classes[i]);
                                html.RenderEndTag();
                            }
                        });
                    }
                    

                    if (e.ContainsClass("nsfw")) notes.Add(html => html.WriteEncodedText("NSFW"));

                    GenerateUL(writer, notes);

                    writer.RenderEndTag();
                }

                writer.RenderEndTag(); // </body>

                writer.RenderEndTag(); // </html>
            }

            return text.ToString();
        }
示例#18
0
        /// <summary>
        /// Loads a table from the specified stream.
        /// </summary>
        /// <param name="origin">The origin of the stream. This will typically be a file path or package name.</param>
        /// <param name="stream">The stream to load the table from.</param>
        /// <returns></returns>
        public static RantDictionaryTable FromStream(string origin, Stream stream)
        {
            string name               = null;                           // Stores the table name before final table construction
            int    termsPerEntry      = 0;                              // Stores the term count
            var    subtypes           = new Dictionary <string, int>(); // Stores subtypes before final table construction
            var    hidden             = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
            RantDictionaryTable table = null;                           // The table object, constructed when first entry is found
            string l;                                                   // Current line string
            int    line = 0;                                            // Current line number
            int    len, i;                                              // Length and character index of current line
            bool   dummy = false;                                       // Determines if the next entry is a dummy entry
            string tId   = null;                                        // Template ID
            RantDictionaryEntry activeTemplate = null;                  // Current template
            var templates = new Dictionary <string, RantDictionaryEntry>();
            RantDictionaryEntry currentEntry = null;
            var autoClasses    = new HashSet <string>();
            var autoClassStack = new Stack <List <string> >();

            using (var reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    line++;

                    // Skip blank lines
                    if (Util.IsNullOrWhiteSpace(l = reader.ReadLine()))
                    {
                        continue;
                    }

                    // Update line info
                    len = l.Length;
                    i   = 0;

                    // Skip whitespace at the start of the line
                    while (i < len && char.IsWhiteSpace(l[i]))
                    {
                        i++;
                    }

                    switch (l[i++])
                    {
                    // Comments
                    case '#':
                        continue;

                    // Directive
                    case '@':
                    {
                        // Read directive name
                        int dPos = i;
                        if (!Tools.ReadDirectiveName(l, len, ref i, out string directiveName))
                        {
                            throw new RantTableLoadException(origin, line, dPos + 1, "err-table-missing-directive-name");
                        }

                        // Read arguments
                        var args = new List <Argument>();
                        while (Tools.ReadArg(origin, l, len, line, ref i, out Argument arg))
                        {
                            args.Add(arg);
                        }

                        switch (directiveName.ToLowerInvariant())
                        {
                        // Table name definition
                        case "name":
                        {
                            // Do not allow this to appear anywhere except at the top of the file
                            if (table != null)
                            {
                                throw new RantTableLoadException(origin, line, dPos + 1, "err-table-misplaced-header-directive");
                            }
                            // Do not allow multiple @name directives
                            if (name != null)
                            {
                                throw new RantTableLoadException(origin, line, dPos + 1, "err-table-multiple-names");
                            }
                            // One argument required
                            if (args.Count != 1)
                            {
                                throw new RantTableLoadException(origin, line, dPos + 1, "err-table-name-args");
                            }
                            // Must meet standard identifier requirements
                            if (!Util.ValidateName(args[0].Value))
                            {
                                throw new RantTableLoadException(origin, line, args[0].CharIndex + 1, "err-table-invalid-name", args[0].Value);
                            }
                            name = args[0].Value;
                            break;
                        }

                        // Subtype definition
                        case "sub":
                        {
                            // Do not allow this to appear anywhere except at the top of the file
                            if (table != null)
                            {
                                throw new RantTableLoadException(origin, line, dPos + 1, "err-table-misplaced-header-directive");
                            }
                            // @sub requires at least one argument
                            if (args.Count == 0)
                            {
                                throw new RantTableLoadException(origin, line, dPos + 1, "err-table-subtype-args");
                            }

                            // If the first argument is a number, use it as the subtype index.
                            if (Util.ParseInt(args[0].Value, out int termIndex))
                            {
                                // Disallow negative term indices
                                if (termIndex < 0)
                                {
                                    throw new RantTableLoadException(origin, line, dPos + 1, "err-table-sub-index-negative", termIndex);
                                }
                                // Requires at least one name
                                if (args.Count < 2)
                                {
                                    throw new RantTableLoadException(origin, line, dPos + 1, "err-table-sub-missing-name");
                                }
                                // If the index is outside the current term index range, increase the number.
                                if (termIndex >= termsPerEntry)
                                {
                                    termsPerEntry = termIndex + 1;
                                }
                                // Assign all following names to the index
                                for (int j = 1; j < args.Count; j++)
                                {
                                    // Validate subtype name
                                    if (!Util.ValidateName(args[j].Value))
                                    {
                                        throw new RantTableLoadException(origin, line, args[j].CharIndex + 1, "err-table-bad-subtype", args[j].Value);
                                    }
                                    subtypes[args[j].Value] = termIndex;
                                }
                            }
                            else
                            {
                                // Add to last index
                                termIndex = termsPerEntry++;
                                // Assign all following names to the index
                                foreach (var a in args)
                                {
                                    // Validate subtype name
                                    if (!Util.ValidateName(a.Value))
                                    {
                                        throw new RantTableLoadException(origin, line, a.CharIndex + 1, "err-table-bad-subtype", a.Value);
                                    }
                                    subtypes[a.Value] = termIndex;
                                }
                            }
                            break;
                        }

                        case "hide":
                            if (args.Count == 0)
                            {
                                break;
                            }
                            foreach (var a in args)
                            {
                                if (!Util.ValidateName(a.Value))
                                {
                                    throw new RantTableLoadException(origin, line, i, "err-table-invalid-class", a.Value);
                                }
                                hidden.Add(String.Intern(a.Value));
                            }
                            break;

                        case "dummy":
                            if (args.Count != 0)
                            {
                                throw new RantTableLoadException(origin, line, i, "err-table-argc-mismatch", directiveName, 0, args.Count);
                            }
                            dummy = true;
                            break;

                        case "id":
                            if (args.Count != 1)
                            {
                                throw new RantTableLoadException(origin, line, i, "err-table-argc-mismatch", directiveName, 1, args.Count);
                            }
                            if (!Util.ValidateName(args[0].Value))
                            {
                                throw new RantTableLoadException(origin, line, args[0].CharIndex + 1, "err-table-bad-template-id", args[0].Value);
                            }
                            tId = args[0].Value;
                            break;

                        case "using":
                            if (args.Count != 1)
                            {
                                throw new RantTableLoadException(origin, line, i, "err-table-argc-mismatch", directiveName, 1, args.Count);
                            }
                            if (!Util.ValidateName(args[0].Value))
                            {
                                throw new RantTableLoadException(origin, line, args[0].CharIndex + 1, "err-table-bad-template-id", args[0].Value);
                            }
                            if (!templates.TryGetValue(args[0].Value, out activeTemplate))
                            {
                                throw new RantTableLoadException(origin, line, args[0].CharIndex + 1, "err-table-template-not-found", args[0].Value);
                            }
                            break;

                        case "class":
                        {
                            var cList = new List <string>();
                            if (args.Count == 0)
                            {
                                throw new RantTableLoadException(origin, line, i, "err-table-args-expected", directiveName);
                            }
                            foreach (var cArg in args)
                            {
                                if (!Tools.ValidateClassName(cArg.Value))
                                {
                                    throw new RantTableLoadException(origin, line, cArg.CharIndex + 1, "err-table-invalid-class", cArg.Value);
                                }
                                cList.Add(cArg.Value);
                                autoClasses.Add(cArg.Value);
                            }
                            autoClassStack.Push(cList);
                            break;
                        }

                        case "endclass":
                        {
                            if (args.Count == 0)
                            {
                                if (autoClassStack.Count > 0)
                                {
                                    foreach (string cName in autoClassStack.Pop())
                                    {
                                        autoClasses.Remove(cName);
                                    }
                                }
                            }
                            break;
                        }
                        }
                        break;
                    }

                    // Entry
                    case '>':
                        Tools.ConstructTable(origin, name, subtypes, ref termsPerEntry, ref table);
                        Tools.ReadTerms(origin, l, len, line, ref i, table, activeTemplate, templates, out currentEntry);
                        if (!dummy)
                        {
                            table.AddEntry(currentEntry);
                        }
                        foreach (string autoClass in autoClasses)
                        {
                            currentEntry.AddClass(autoClass);
                        }
                        if (tId != null)
                        {
                            templates[tId] = currentEntry;
                            tId            = null;
                        }
                        dummy          = false;
                        activeTemplate = null;
                        break;

                    // Property
                    case '-':
                    {
                        Tools.ConstructTable(origin, name, subtypes, ref termsPerEntry, ref table);
                        Tools.SkipSpace(l, len, ref i);

                        // Read property name
                        int dPos = i;
                        if (!Tools.ReadDirectiveName(l, len, ref i, out string propName))
                        {
                            throw new RantTableLoadException(origin, line, dPos + 1, "err-table-missing-property-name");
                        }

                        // Read arguments
                        var args = new List <Argument>();
                        while (Tools.ReadArg(origin, l, len, line, ref i, out Argument arg))
                        {
                            args.Add(arg);
                        }

                        // No args? Skip it.
                        if (args.Count == 0)
                        {
                            continue;
                        }

                        switch (propName.ToLowerInvariant())
                        {
                        case "class":
                            foreach (var cArg in args)
                            {
                                if (!Tools.ValidateClassName(cArg.Value))
                                {
                                    throw new RantTableLoadException(origin, line, cArg.CharIndex + 1, "err-table-invalid-class", cArg.Value);
                                }
                                currentEntry.AddClass(cArg.Value);
                            }
                            break;

                        case "weight":
                        {
                            if (!float.TryParse(args[0].Value, out float weight) || weight <= 0)
                            {
                                throw new RantTableLoadException(origin, line, args[0].CharIndex + 1, "err-table-invalid-weight", args[0].Value);
                            }
                            currentEntry.Weight   = weight;
                            table.EnableWeighting = true;
                            break;
                        }

                        case "pron":
                            if (args.Count != table.TermsPerEntry)
                            {
                                continue;
                            }
                            for (int j = 0; j < currentEntry.TermCount; j++)
                            {
                                currentEntry[j].Pronunciation = args[j].Value;
                            }
                            break;

                        default:
                            if (args.Count == 1)
                            {
                                currentEntry.SetMetadata(propName, args[0].Value);
                            }
                            else
                            {
                                currentEntry.SetMetadata(propName, args.Select(a => a.Value).ToArray());
                            }
                            break;
                        }
                        break;
                    }
                    }
                }
            }

            // Add hidden classes
            foreach (string hc in hidden)
            {
                table.HideClass(hc);
            }

            table.RebuildCache();

            return(table);
        }
示例#19
0
 /// <summary>
 /// Adds the specified table to the package.
 /// </summary>
 /// <param name="table">The table to add.</param>
 public void AddTable(RantDictionaryTable table)
     => (_tables ?? (_tables = new HashSet<RantDictionaryTable>())).Add(table);
示例#20
0
 /// <summary>
 /// Loads all dictionary (.dic) files from the specified directories and returns a Dictionary object that contains the loaded data.
 /// </summary>
 /// <param name="directories">The directories from which to load dictionaries.</param>
 /// <param name="mergeBehavior">The merging strategy to employ.</param>
 /// <returns></returns>
 public static RantDictionary FromMultiDirectory(string[] directories, TableMergeBehavior mergeBehavior)
 {
     return(new RantDictionary(directories.SelectMany(path => Directory.GetFiles(path, "*.dic", SearchOption.AllDirectories)).Select(file => RantDictionaryTable.FromFile(file)), mergeBehavior));
 }