diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/CodePointFilters.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/CodePointFilters.cs
new file mode 100644
index 0000000000..9268062fd5
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/CodePointFilters.cs
@@ -0,0 +1,2585 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Contains predefined Unicode code point filters.
+ ///
+ public static class CodePointFilters
+ {
+ ///
+ /// A filter which allows no characters.
+ ///
+ public static ICodePointFilter None
+ {
+ get
+ {
+ return LazyInitializer.EnsureInitialized(ref _none);
+ }
+ }
+ private static EmptyCodePointFilter _none;
+
+ ///
+ /// A filter which allows all Unicode Basic Multilingual Plane characters.
+ ///
+ ///
+ /// This range spans the code points U+0000 .. U+FFFF.
+ ///
+ public static ICodePointFilter All
+ {
+ get
+ {
+ return GetFilter(ref _all, first: '\u0000', last: '\uFFFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _all;
+
+ ///
+ /// A filter which allows characters in the 'Basic Latin' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0000 .. U+007F.
+ /// See http://www.unicode.org/charts/PDF/U0000.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter BasicLatin
+ {
+ get
+ {
+ return GetFilter(ref _basicLatin, first: '\u0000', last: '\u007F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _basicLatin;
+
+ ///
+ /// A filter which allows characters in the 'Latin-1 Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0080 .. U+00FF.
+ /// See http://www.unicode.org/charts/PDF/U0080.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Latin1Supplement
+ {
+ get
+ {
+ return GetFilter(ref _latin1Supplement, first: '\u0080', last: '\u00FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latin1Supplement;
+
+ ///
+ /// A filter which allows characters in the 'Latin Extended-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0100 .. U+017F.
+ /// See http://www.unicode.org/charts/PDF/U0100.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LatinExtendedA
+ {
+ get
+ {
+ return GetFilter(ref _latinExtendedA, first: '\u0100', last: '\u017F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latinExtendedA;
+
+ ///
+ /// A filter which allows characters in the 'Latin Extended-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0180 .. U+024F.
+ /// See http://www.unicode.org/charts/PDF/U0180.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LatinExtendedB
+ {
+ get
+ {
+ return GetFilter(ref _latinExtendedB, first: '\u0180', last: '\u024F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latinExtendedB;
+
+ ///
+ /// A filter which allows characters in the 'IPA Extensions' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0250 .. U+02AF.
+ /// See http://www.unicode.org/charts/PDF/U0250.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter IPAExtensions
+ {
+ get
+ {
+ return GetFilter(ref _ipaExtensions, first: '\u0250', last: '\u02AF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ipaExtensions;
+
+ ///
+ /// A filter which allows characters in the 'Spacing Modifier Letters' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+02B0 .. U+02FF.
+ /// See http://www.unicode.org/charts/PDF/U02B0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SpacingModifierLetters
+ {
+ get
+ {
+ return GetFilter(ref _spacingModifierLetters, first: '\u02B0', last: '\u02FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _spacingModifierLetters;
+
+ ///
+ /// A filter which allows characters in the 'Combining Diacritical Marks' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0300 .. U+036F.
+ /// See http://www.unicode.org/charts/PDF/U0300.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CombiningDiacriticalMarks
+ {
+ get
+ {
+ return GetFilter(ref _combiningDiacriticalMarks, first: '\u0300', last: '\u036F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _combiningDiacriticalMarks;
+
+ ///
+ /// A filter which allows characters in the 'Greek and Coptic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0370 .. U+03FF.
+ /// See http://www.unicode.org/charts/PDF/U0370.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter GreekandCoptic
+ {
+ get
+ {
+ return GetFilter(ref _greekandCoptic, first: '\u0370', last: '\u03FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _greekandCoptic;
+
+ ///
+ /// A filter which allows characters in the 'Cyrillic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0400 .. U+04FF.
+ /// See http://www.unicode.org/charts/PDF/U0400.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Cyrillic
+ {
+ get
+ {
+ return GetFilter(ref _cyrillic, first: '\u0400', last: '\u04FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cyrillic;
+
+ ///
+ /// A filter which allows characters in the 'Cyrillic Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0500 .. U+052F.
+ /// See http://www.unicode.org/charts/PDF/U0500.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CyrillicSupplement
+ {
+ get
+ {
+ return GetFilter(ref _cyrillicSupplement, first: '\u0500', last: '\u052F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cyrillicSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Armenian' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0530 .. U+058F.
+ /// See http://www.unicode.org/charts/PDF/U0530.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Armenian
+ {
+ get
+ {
+ return GetFilter(ref _armenian, first: '\u0530', last: '\u058F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _armenian;
+
+ ///
+ /// A filter which allows characters in the 'Hebrew' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0590 .. U+05FF.
+ /// See http://www.unicode.org/charts/PDF/U0590.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Hebrew
+ {
+ get
+ {
+ return GetFilter(ref _hebrew, first: '\u0590', last: '\u05FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hebrew;
+
+ ///
+ /// A filter which allows characters in the 'Arabic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0600 .. U+06FF.
+ /// See http://www.unicode.org/charts/PDF/U0600.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Arabic
+ {
+ get
+ {
+ return GetFilter(ref _arabic, first: '\u0600', last: '\u06FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _arabic;
+
+ ///
+ /// A filter which allows characters in the 'Syriac' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0700 .. U+074F.
+ /// See http://www.unicode.org/charts/PDF/U0700.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Syriac
+ {
+ get
+ {
+ return GetFilter(ref _syriac, first: '\u0700', last: '\u074F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _syriac;
+
+ ///
+ /// A filter which allows characters in the 'Arabic Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0750 .. U+077F.
+ /// See http://www.unicode.org/charts/PDF/U0750.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter ArabicSupplement
+ {
+ get
+ {
+ return GetFilter(ref _arabicSupplement, first: '\u0750', last: '\u077F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _arabicSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Thaana' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0780 .. U+07BF.
+ /// See http://www.unicode.org/charts/PDF/U0780.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Thaana
+ {
+ get
+ {
+ return GetFilter(ref _thaana, first: '\u0780', last: '\u07BF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _thaana;
+
+ ///
+ /// A filter which allows characters in the 'NKo' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+07C0 .. U+07FF.
+ /// See http://www.unicode.org/charts/PDF/U07C0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter NKo
+ {
+ get
+ {
+ return GetFilter(ref _nKo, first: '\u07C0', last: '\u07FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _nKo;
+
+ ///
+ /// A filter which allows characters in the 'Samaritan' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0800 .. U+083F.
+ /// See http://www.unicode.org/charts/PDF/U0800.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Samaritan
+ {
+ get
+ {
+ return GetFilter(ref _samaritan, first: '\u0800', last: '\u083F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _samaritan;
+
+ ///
+ /// A filter which allows characters in the 'Mandaic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0840 .. U+085F.
+ /// See http://www.unicode.org/charts/PDF/U0840.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Mandaic
+ {
+ get
+ {
+ return GetFilter(ref _mandaic, first: '\u0840', last: '\u085F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _mandaic;
+
+ ///
+ /// A filter which allows characters in the 'Arabic Extended-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+08A0 .. U+08FF.
+ /// See http://www.unicode.org/charts/PDF/U08A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter ArabicExtendedA
+ {
+ get
+ {
+ return GetFilter(ref _arabicExtendedA, first: '\u08A0', last: '\u08FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _arabicExtendedA;
+
+ ///
+ /// A filter which allows characters in the 'Devanagari' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0900 .. U+097F.
+ /// See http://www.unicode.org/charts/PDF/U0900.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Devanagari
+ {
+ get
+ {
+ return GetFilter(ref _devanagari, first: '\u0900', last: '\u097F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _devanagari;
+
+ ///
+ /// A filter which allows characters in the 'Bengali' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0980 .. U+09FF.
+ /// See http://www.unicode.org/charts/PDF/U0980.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Bengali
+ {
+ get
+ {
+ return GetFilter(ref _bengali, first: '\u0980', last: '\u09FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _bengali;
+
+ ///
+ /// A filter which allows characters in the 'Gurmukhi' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0A00 .. U+0A7F.
+ /// See http://www.unicode.org/charts/PDF/U0A00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Gurmukhi
+ {
+ get
+ {
+ return GetFilter(ref _gurmukhi, first: '\u0A00', last: '\u0A7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _gurmukhi;
+
+ ///
+ /// A filter which allows characters in the 'Gujarati' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0A80 .. U+0AFF.
+ /// See http://www.unicode.org/charts/PDF/U0A80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Gujarati
+ {
+ get
+ {
+ return GetFilter(ref _gujarati, first: '\u0A80', last: '\u0AFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _gujarati;
+
+ ///
+ /// A filter which allows characters in the 'Oriya' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0B00 .. U+0B7F.
+ /// See http://www.unicode.org/charts/PDF/U0B00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Oriya
+ {
+ get
+ {
+ return GetFilter(ref _oriya, first: '\u0B00', last: '\u0B7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _oriya;
+
+ ///
+ /// A filter which allows characters in the 'Tamil' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0B80 .. U+0BFF.
+ /// See http://www.unicode.org/charts/PDF/U0B80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Tamil
+ {
+ get
+ {
+ return GetFilter(ref _tamil, first: '\u0B80', last: '\u0BFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _tamil;
+
+ ///
+ /// A filter which allows characters in the 'Telugu' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0C00 .. U+0C7F.
+ /// See http://www.unicode.org/charts/PDF/U0C00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Telugu
+ {
+ get
+ {
+ return GetFilter(ref _telugu, first: '\u0C00', last: '\u0C7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _telugu;
+
+ ///
+ /// A filter which allows characters in the 'Kannada' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0C80 .. U+0CFF.
+ /// See http://www.unicode.org/charts/PDF/U0C80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Kannada
+ {
+ get
+ {
+ return GetFilter(ref _kannada, first: '\u0C80', last: '\u0CFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _kannada;
+
+ ///
+ /// A filter which allows characters in the 'Malayalam' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0D00 .. U+0D7F.
+ /// See http://www.unicode.org/charts/PDF/U0D00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Malayalam
+ {
+ get
+ {
+ return GetFilter(ref _malayalam, first: '\u0D00', last: '\u0D7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _malayalam;
+
+ ///
+ /// A filter which allows characters in the 'Sinhala' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0D80 .. U+0DFF.
+ /// See http://www.unicode.org/charts/PDF/U0D80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Sinhala
+ {
+ get
+ {
+ return GetFilter(ref _sinhala, first: '\u0D80', last: '\u0DFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _sinhala;
+
+ ///
+ /// A filter which allows characters in the 'Thai' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0E00 .. U+0E7F.
+ /// See http://www.unicode.org/charts/PDF/U0E00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Thai
+ {
+ get
+ {
+ return GetFilter(ref _thai, first: '\u0E00', last: '\u0E7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _thai;
+
+ ///
+ /// A filter which allows characters in the 'Lao' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0E80 .. U+0EFF.
+ /// See http://www.unicode.org/charts/PDF/U0E80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Lao
+ {
+ get
+ {
+ return GetFilter(ref _lao, first: '\u0E80', last: '\u0EFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _lao;
+
+ ///
+ /// A filter which allows characters in the 'Tibetan' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+0F00 .. U+0FFF.
+ /// See http://www.unicode.org/charts/PDF/U0F00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Tibetan
+ {
+ get
+ {
+ return GetFilter(ref _tibetan, first: '\u0F00', last: '\u0FFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _tibetan;
+
+ ///
+ /// A filter which allows characters in the 'Myanmar' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1000 .. U+109F.
+ /// See http://www.unicode.org/charts/PDF/U1000.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Myanmar
+ {
+ get
+ {
+ return GetFilter(ref _myanmar, first: '\u1000', last: '\u109F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _myanmar;
+
+ ///
+ /// A filter which allows characters in the 'Georgian' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+10A0 .. U+10FF.
+ /// See http://www.unicode.org/charts/PDF/U10A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Georgian
+ {
+ get
+ {
+ return GetFilter(ref _georgian, first: '\u10A0', last: '\u10FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _georgian;
+
+ ///
+ /// A filter which allows characters in the 'Hangul Jamo' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1100 .. U+11FF.
+ /// See http://www.unicode.org/charts/PDF/U1100.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter HangulJamo
+ {
+ get
+ {
+ return GetFilter(ref _hangulJamo, first: '\u1100', last: '\u11FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hangulJamo;
+
+ ///
+ /// A filter which allows characters in the 'Ethiopic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1200 .. U+137F.
+ /// See http://www.unicode.org/charts/PDF/U1200.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Ethiopic
+ {
+ get
+ {
+ return GetFilter(ref _ethiopic, first: '\u1200', last: '\u137F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ethiopic;
+
+ ///
+ /// A filter which allows characters in the 'Ethiopic Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1380 .. U+139F.
+ /// See http://www.unicode.org/charts/PDF/U1380.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter EthiopicSupplement
+ {
+ get
+ {
+ return GetFilter(ref _ethiopicSupplement, first: '\u1380', last: '\u139F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ethiopicSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Cherokee' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+13A0 .. U+13FF.
+ /// See http://www.unicode.org/charts/PDF/U13A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Cherokee
+ {
+ get
+ {
+ return GetFilter(ref _cherokee, first: '\u13A0', last: '\u13FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cherokee;
+
+ ///
+ /// A filter which allows characters in the 'Unified Canadian Aboriginal Syllabics' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1400 .. U+167F.
+ /// See http://www.unicode.org/charts/PDF/U1400.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter UnifiedCanadianAboriginalSyllabics
+ {
+ get
+ {
+ return GetFilter(ref _unifiedCanadianAboriginalSyllabics, first: '\u1400', last: '\u167F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _unifiedCanadianAboriginalSyllabics;
+
+ ///
+ /// A filter which allows characters in the 'Ogham' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1680 .. U+169F.
+ /// See http://www.unicode.org/charts/PDF/U1680.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Ogham
+ {
+ get
+ {
+ return GetFilter(ref _ogham, first: '\u1680', last: '\u169F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ogham;
+
+ ///
+ /// A filter which allows characters in the 'Runic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+16A0 .. U+16FF.
+ /// See http://www.unicode.org/charts/PDF/U16A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Runic
+ {
+ get
+ {
+ return GetFilter(ref _runic, first: '\u16A0', last: '\u16FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _runic;
+
+ ///
+ /// A filter which allows characters in the 'Tagalog' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1700 .. U+171F.
+ /// See http://www.unicode.org/charts/PDF/U1700.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Tagalog
+ {
+ get
+ {
+ return GetFilter(ref _tagalog, first: '\u1700', last: '\u171F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _tagalog;
+
+ ///
+ /// A filter which allows characters in the 'Hanunoo' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1720 .. U+173F.
+ /// See http://www.unicode.org/charts/PDF/U1720.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Hanunoo
+ {
+ get
+ {
+ return GetFilter(ref _hanunoo, first: '\u1720', last: '\u173F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hanunoo;
+
+ ///
+ /// A filter which allows characters in the 'Buhid' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1740 .. U+175F.
+ /// See http://www.unicode.org/charts/PDF/U1740.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Buhid
+ {
+ get
+ {
+ return GetFilter(ref _buhid, first: '\u1740', last: '\u175F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _buhid;
+
+ ///
+ /// A filter which allows characters in the 'Tagbanwa' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1760 .. U+177F.
+ /// See http://www.unicode.org/charts/PDF/U1760.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Tagbanwa
+ {
+ get
+ {
+ return GetFilter(ref _tagbanwa, first: '\u1760', last: '\u177F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _tagbanwa;
+
+ ///
+ /// A filter which allows characters in the 'Khmer' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1780 .. U+17FF.
+ /// See http://www.unicode.org/charts/PDF/U1780.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Khmer
+ {
+ get
+ {
+ return GetFilter(ref _khmer, first: '\u1780', last: '\u17FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _khmer;
+
+ ///
+ /// A filter which allows characters in the 'Mongolian' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1800 .. U+18AF.
+ /// See http://www.unicode.org/charts/PDF/U1800.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Mongolian
+ {
+ get
+ {
+ return GetFilter(ref _mongolian, first: '\u1800', last: '\u18AF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _mongolian;
+
+ ///
+ /// A filter which allows characters in the 'Unified Canadian Aboriginal Syllabics Extended' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+18B0 .. U+18FF.
+ /// See http://www.unicode.org/charts/PDF/U18B0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter UnifiedCanadianAboriginalSyllabicsExtended
+ {
+ get
+ {
+ return GetFilter(ref _unifiedCanadianAboriginalSyllabicsExtended, first: '\u18B0', last: '\u18FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _unifiedCanadianAboriginalSyllabicsExtended;
+
+ ///
+ /// A filter which allows characters in the 'Limbu' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1900 .. U+194F.
+ /// See http://www.unicode.org/charts/PDF/U1900.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Limbu
+ {
+ get
+ {
+ return GetFilter(ref _limbu, first: '\u1900', last: '\u194F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _limbu;
+
+ ///
+ /// A filter which allows characters in the 'Tai Le' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1950 .. U+197F.
+ /// See http://www.unicode.org/charts/PDF/U1950.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter TaiLe
+ {
+ get
+ {
+ return GetFilter(ref _taiLe, first: '\u1950', last: '\u197F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _taiLe;
+
+ ///
+ /// A filter which allows characters in the 'New Tai Lue' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1980 .. U+19DF.
+ /// See http://www.unicode.org/charts/PDF/U1980.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter NewTaiLue
+ {
+ get
+ {
+ return GetFilter(ref _newTaiLue, first: '\u1980', last: '\u19DF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _newTaiLue;
+
+ ///
+ /// A filter which allows characters in the 'Khmer Symbols' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+19E0 .. U+19FF.
+ /// See http://www.unicode.org/charts/PDF/U19E0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter KhmerSymbols
+ {
+ get
+ {
+ return GetFilter(ref _khmerSymbols, first: '\u19E0', last: '\u19FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _khmerSymbols;
+
+ ///
+ /// A filter which allows characters in the 'Buginese' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1A00 .. U+1A1F.
+ /// See http://www.unicode.org/charts/PDF/U1A00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Buginese
+ {
+ get
+ {
+ return GetFilter(ref _buginese, first: '\u1A00', last: '\u1A1F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _buginese;
+
+ ///
+ /// A filter which allows characters in the 'Tai Tham' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1A20 .. U+1AAF.
+ /// See http://www.unicode.org/charts/PDF/U1A20.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter TaiTham
+ {
+ get
+ {
+ return GetFilter(ref _taiTham, first: '\u1A20', last: '\u1AAF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _taiTham;
+
+ ///
+ /// A filter which allows characters in the 'Combining Diacritical Marks Extended' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1AB0 .. U+1AFF.
+ /// See http://www.unicode.org/charts/PDF/U1AB0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CombiningDiacriticalMarksExtended
+ {
+ get
+ {
+ return GetFilter(ref _combiningDiacriticalMarksExtended, first: '\u1AB0', last: '\u1AFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _combiningDiacriticalMarksExtended;
+
+ ///
+ /// A filter which allows characters in the 'Balinese' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1B00 .. U+1B7F.
+ /// See http://www.unicode.org/charts/PDF/U1B00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Balinese
+ {
+ get
+ {
+ return GetFilter(ref _balinese, first: '\u1B00', last: '\u1B7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _balinese;
+
+ ///
+ /// A filter which allows characters in the 'Sundanese' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1B80 .. U+1BBF.
+ /// See http://www.unicode.org/charts/PDF/U1B80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Sundanese
+ {
+ get
+ {
+ return GetFilter(ref _sundanese, first: '\u1B80', last: '\u1BBF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _sundanese;
+
+ ///
+ /// A filter which allows characters in the 'Batak' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1BC0 .. U+1BFF.
+ /// See http://www.unicode.org/charts/PDF/U1BC0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Batak
+ {
+ get
+ {
+ return GetFilter(ref _batak, first: '\u1BC0', last: '\u1BFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _batak;
+
+ ///
+ /// A filter which allows characters in the 'Lepcha' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1C00 .. U+1C4F.
+ /// See http://www.unicode.org/charts/PDF/U1C00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Lepcha
+ {
+ get
+ {
+ return GetFilter(ref _lepcha, first: '\u1C00', last: '\u1C4F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _lepcha;
+
+ ///
+ /// A filter which allows characters in the 'Ol Chiki' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1C50 .. U+1C7F.
+ /// See http://www.unicode.org/charts/PDF/U1C50.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter OlChiki
+ {
+ get
+ {
+ return GetFilter(ref _olChiki, first: '\u1C50', last: '\u1C7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _olChiki;
+
+ ///
+ /// A filter which allows characters in the 'Sundanese Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1CC0 .. U+1CCF.
+ /// See http://www.unicode.org/charts/PDF/U1CC0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SundaneseSupplement
+ {
+ get
+ {
+ return GetFilter(ref _sundaneseSupplement, first: '\u1CC0', last: '\u1CCF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _sundaneseSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Vedic Extensions' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1CD0 .. U+1CFF.
+ /// See http://www.unicode.org/charts/PDF/U1CD0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter VedicExtensions
+ {
+ get
+ {
+ return GetFilter(ref _vedicExtensions, first: '\u1CD0', last: '\u1CFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _vedicExtensions;
+
+ ///
+ /// A filter which allows characters in the 'Phonetic Extensions' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1D00 .. U+1D7F.
+ /// See http://www.unicode.org/charts/PDF/U1D00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter PhoneticExtensions
+ {
+ get
+ {
+ return GetFilter(ref _phoneticExtensions, first: '\u1D00', last: '\u1D7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _phoneticExtensions;
+
+ ///
+ /// A filter which allows characters in the 'Phonetic Extensions Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1D80 .. U+1DBF.
+ /// See http://www.unicode.org/charts/PDF/U1D80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter PhoneticExtensionsSupplement
+ {
+ get
+ {
+ return GetFilter(ref _phoneticExtensionsSupplement, first: '\u1D80', last: '\u1DBF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _phoneticExtensionsSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Combining Diacritical Marks Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1DC0 .. U+1DFF.
+ /// See http://www.unicode.org/charts/PDF/U1DC0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CombiningDiacriticalMarksSupplement
+ {
+ get
+ {
+ return GetFilter(ref _combiningDiacriticalMarksSupplement, first: '\u1DC0', last: '\u1DFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _combiningDiacriticalMarksSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Latin Extended Additional' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1E00 .. U+1EFF.
+ /// See http://www.unicode.org/charts/PDF/U1E00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LatinExtendedAdditional
+ {
+ get
+ {
+ return GetFilter(ref _latinExtendedAdditional, first: '\u1E00', last: '\u1EFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latinExtendedAdditional;
+
+ ///
+ /// A filter which allows characters in the 'Greek Extended' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+1F00 .. U+1FFF.
+ /// See http://www.unicode.org/charts/PDF/U1F00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter GreekExtended
+ {
+ get
+ {
+ return GetFilter(ref _greekExtended, first: '\u1F00', last: '\u1FFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _greekExtended;
+
+ ///
+ /// A filter which allows characters in the 'General Punctuation' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2000 .. U+206F.
+ /// See http://www.unicode.org/charts/PDF/U2000.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter GeneralPunctuation
+ {
+ get
+ {
+ return GetFilter(ref _generalPunctuation, first: '\u2000', last: '\u206F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _generalPunctuation;
+
+ ///
+ /// A filter which allows characters in the 'Superscripts and Subscripts' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2070 .. U+209F.
+ /// See http://www.unicode.org/charts/PDF/U2070.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SuperscriptsandSubscripts
+ {
+ get
+ {
+ return GetFilter(ref _superscriptsandSubscripts, first: '\u2070', last: '\u209F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _superscriptsandSubscripts;
+
+ ///
+ /// A filter which allows characters in the 'Currency Symbols' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+20A0 .. U+20CF.
+ /// See http://www.unicode.org/charts/PDF/U20A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CurrencySymbols
+ {
+ get
+ {
+ return GetFilter(ref _currencySymbols, first: '\u20A0', last: '\u20CF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _currencySymbols;
+
+ ///
+ /// A filter which allows characters in the 'Combining Diacritical Marks for Symbols' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+20D0 .. U+20FF.
+ /// See http://www.unicode.org/charts/PDF/U20D0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CombiningDiacriticalMarksforSymbols
+ {
+ get
+ {
+ return GetFilter(ref _combiningDiacriticalMarksforSymbols, first: '\u20D0', last: '\u20FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _combiningDiacriticalMarksforSymbols;
+
+ ///
+ /// A filter which allows characters in the 'Letterlike Symbols' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2100 .. U+214F.
+ /// See http://www.unicode.org/charts/PDF/U2100.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LetterlikeSymbols
+ {
+ get
+ {
+ return GetFilter(ref _letterlikeSymbols, first: '\u2100', last: '\u214F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _letterlikeSymbols;
+
+ ///
+ /// A filter which allows characters in the 'Number Forms' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2150 .. U+218F.
+ /// See http://www.unicode.org/charts/PDF/U2150.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter NumberForms
+ {
+ get
+ {
+ return GetFilter(ref _numberForms, first: '\u2150', last: '\u218F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _numberForms;
+
+ ///
+ /// A filter which allows characters in the 'Arrows' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2190 .. U+21FF.
+ /// See http://www.unicode.org/charts/PDF/U2190.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Arrows
+ {
+ get
+ {
+ return GetFilter(ref _arrows, first: '\u2190', last: '\u21FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _arrows;
+
+ ///
+ /// A filter which allows characters in the 'Mathematical Operators' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2200 .. U+22FF.
+ /// See http://www.unicode.org/charts/PDF/U2200.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MathematicalOperators
+ {
+ get
+ {
+ return GetFilter(ref _mathematicalOperators, first: '\u2200', last: '\u22FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _mathematicalOperators;
+
+ ///
+ /// A filter which allows characters in the 'Miscellaneous Technical' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2300 .. U+23FF.
+ /// See http://www.unicode.org/charts/PDF/U2300.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MiscellaneousTechnical
+ {
+ get
+ {
+ return GetFilter(ref _miscellaneousTechnical, first: '\u2300', last: '\u23FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _miscellaneousTechnical;
+
+ ///
+ /// A filter which allows characters in the 'Control Pictures' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2400 .. U+243F.
+ /// See http://www.unicode.org/charts/PDF/U2400.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter ControlPictures
+ {
+ get
+ {
+ return GetFilter(ref _controlPictures, first: '\u2400', last: '\u243F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _controlPictures;
+
+ ///
+ /// A filter which allows characters in the 'Optical Character Recognition' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2440 .. U+245F.
+ /// See http://www.unicode.org/charts/PDF/U2440.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter OpticalCharacterRecognition
+ {
+ get
+ {
+ return GetFilter(ref _opticalCharacterRecognition, first: '\u2440', last: '\u245F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _opticalCharacterRecognition;
+
+ ///
+ /// A filter which allows characters in the 'Enclosed Alphanumerics' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2460 .. U+24FF.
+ /// See http://www.unicode.org/charts/PDF/U2460.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter EnclosedAlphanumerics
+ {
+ get
+ {
+ return GetFilter(ref _enclosedAlphanumerics, first: '\u2460', last: '\u24FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _enclosedAlphanumerics;
+
+ ///
+ /// A filter which allows characters in the 'Box Drawing' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2500 .. U+257F.
+ /// See http://www.unicode.org/charts/PDF/U2500.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter BoxDrawing
+ {
+ get
+ {
+ return GetFilter(ref _boxDrawing, first: '\u2500', last: '\u257F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _boxDrawing;
+
+ ///
+ /// A filter which allows characters in the 'Block Elements' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2580 .. U+259F.
+ /// See http://www.unicode.org/charts/PDF/U2580.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter BlockElements
+ {
+ get
+ {
+ return GetFilter(ref _blockElements, first: '\u2580', last: '\u259F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _blockElements;
+
+ ///
+ /// A filter which allows characters in the 'Geometric Shapes' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+25A0 .. U+25FF.
+ /// See http://www.unicode.org/charts/PDF/U25A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter GeometricShapes
+ {
+ get
+ {
+ return GetFilter(ref _geometricShapes, first: '\u25A0', last: '\u25FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _geometricShapes;
+
+ ///
+ /// A filter which allows characters in the 'Miscellaneous Symbols' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2600 .. U+26FF.
+ /// See http://www.unicode.org/charts/PDF/U2600.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MiscellaneousSymbols
+ {
+ get
+ {
+ return GetFilter(ref _miscellaneousSymbols, first: '\u2600', last: '\u26FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _miscellaneousSymbols;
+
+ ///
+ /// A filter which allows characters in the 'Dingbats' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2700 .. U+27BF.
+ /// See http://www.unicode.org/charts/PDF/U2700.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Dingbats
+ {
+ get
+ {
+ return GetFilter(ref _dingbats, first: '\u2700', last: '\u27BF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _dingbats;
+
+ ///
+ /// A filter which allows characters in the 'Miscellaneous Mathematical Symbols-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+27C0 .. U+27EF.
+ /// See http://www.unicode.org/charts/PDF/U27C0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MiscellaneousMathematicalSymbolsA
+ {
+ get
+ {
+ return GetFilter(ref _miscellaneousMathematicalSymbolsA, first: '\u27C0', last: '\u27EF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _miscellaneousMathematicalSymbolsA;
+
+ ///
+ /// A filter which allows characters in the 'Supplemental Arrows-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+27F0 .. U+27FF.
+ /// See http://www.unicode.org/charts/PDF/U27F0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SupplementalArrowsA
+ {
+ get
+ {
+ return GetFilter(ref _supplementalArrowsA, first: '\u27F0', last: '\u27FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _supplementalArrowsA;
+
+ ///
+ /// A filter which allows characters in the 'Braille Patterns' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2800 .. U+28FF.
+ /// See http://www.unicode.org/charts/PDF/U2800.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter BraillePatterns
+ {
+ get
+ {
+ return GetFilter(ref _braillePatterns, first: '\u2800', last: '\u28FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _braillePatterns;
+
+ ///
+ /// A filter which allows characters in the 'Supplemental Arrows-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2900 .. U+297F.
+ /// See http://www.unicode.org/charts/PDF/U2900.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SupplementalArrowsB
+ {
+ get
+ {
+ return GetFilter(ref _supplementalArrowsB, first: '\u2900', last: '\u297F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _supplementalArrowsB;
+
+ ///
+ /// A filter which allows characters in the 'Miscellaneous Mathematical Symbols-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2980 .. U+29FF.
+ /// See http://www.unicode.org/charts/PDF/U2980.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MiscellaneousMathematicalSymbolsB
+ {
+ get
+ {
+ return GetFilter(ref _miscellaneousMathematicalSymbolsB, first: '\u2980', last: '\u29FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _miscellaneousMathematicalSymbolsB;
+
+ ///
+ /// A filter which allows characters in the 'Supplemental Mathematical Operators' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2A00 .. U+2AFF.
+ /// See http://www.unicode.org/charts/PDF/U2A00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SupplementalMathematicalOperators
+ {
+ get
+ {
+ return GetFilter(ref _supplementalMathematicalOperators, first: '\u2A00', last: '\u2AFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _supplementalMathematicalOperators;
+
+ ///
+ /// A filter which allows characters in the 'Miscellaneous Symbols and Arrows' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2B00 .. U+2BFF.
+ /// See http://www.unicode.org/charts/PDF/U2B00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MiscellaneousSymbolsandArrows
+ {
+ get
+ {
+ return GetFilter(ref _miscellaneousSymbolsandArrows, first: '\u2B00', last: '\u2BFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _miscellaneousSymbolsandArrows;
+
+ ///
+ /// A filter which allows characters in the 'Glagolitic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2C00 .. U+2C5F.
+ /// See http://www.unicode.org/charts/PDF/U2C00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Glagolitic
+ {
+ get
+ {
+ return GetFilter(ref _glagolitic, first: '\u2C00', last: '\u2C5F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _glagolitic;
+
+ ///
+ /// A filter which allows characters in the 'Latin Extended-C' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2C60 .. U+2C7F.
+ /// See http://www.unicode.org/charts/PDF/U2C60.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LatinExtendedC
+ {
+ get
+ {
+ return GetFilter(ref _latinExtendedC, first: '\u2C60', last: '\u2C7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latinExtendedC;
+
+ ///
+ /// A filter which allows characters in the 'Coptic' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2C80 .. U+2CFF.
+ /// See http://www.unicode.org/charts/PDF/U2C80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Coptic
+ {
+ get
+ {
+ return GetFilter(ref _coptic, first: '\u2C80', last: '\u2CFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _coptic;
+
+ ///
+ /// A filter which allows characters in the 'Georgian Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2D00 .. U+2D2F.
+ /// See http://www.unicode.org/charts/PDF/U2D00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter GeorgianSupplement
+ {
+ get
+ {
+ return GetFilter(ref _georgianSupplement, first: '\u2D00', last: '\u2D2F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _georgianSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Tifinagh' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2D30 .. U+2D7F.
+ /// See http://www.unicode.org/charts/PDF/U2D30.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Tifinagh
+ {
+ get
+ {
+ return GetFilter(ref _tifinagh, first: '\u2D30', last: '\u2D7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _tifinagh;
+
+ ///
+ /// A filter which allows characters in the 'Ethiopic Extended' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2D80 .. U+2DDF.
+ /// See http://www.unicode.org/charts/PDF/U2D80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter EthiopicExtended
+ {
+ get
+ {
+ return GetFilter(ref _ethiopicExtended, first: '\u2D80', last: '\u2DDF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ethiopicExtended;
+
+ ///
+ /// A filter which allows characters in the 'Cyrillic Extended-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2DE0 .. U+2DFF.
+ /// See http://www.unicode.org/charts/PDF/U2DE0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CyrillicExtendedA
+ {
+ get
+ {
+ return GetFilter(ref _cyrillicExtendedA, first: '\u2DE0', last: '\u2DFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cyrillicExtendedA;
+
+ ///
+ /// A filter which allows characters in the 'Supplemental Punctuation' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2E00 .. U+2E7F.
+ /// See http://www.unicode.org/charts/PDF/U2E00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SupplementalPunctuation
+ {
+ get
+ {
+ return GetFilter(ref _supplementalPunctuation, first: '\u2E00', last: '\u2E7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _supplementalPunctuation;
+
+ ///
+ /// A filter which allows characters in the 'CJK Radicals Supplement' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2E80 .. U+2EFF.
+ /// See http://www.unicode.org/charts/PDF/U2E80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKRadicalsSupplement
+ {
+ get
+ {
+ return GetFilter(ref _cjkRadicalsSupplement, first: '\u2E80', last: '\u2EFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkRadicalsSupplement;
+
+ ///
+ /// A filter which allows characters in the 'Kangxi Radicals' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2F00 .. U+2FDF.
+ /// See http://www.unicode.org/charts/PDF/U2F00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter KangxiRadicals
+ {
+ get
+ {
+ return GetFilter(ref _kangxiRadicals, first: '\u2F00', last: '\u2FDF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _kangxiRadicals;
+
+ ///
+ /// A filter which allows characters in the 'Ideographic Description Characters' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+2FF0 .. U+2FFF.
+ /// See http://www.unicode.org/charts/PDF/U2FF0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter IdeographicDescriptionCharacters
+ {
+ get
+ {
+ return GetFilter(ref _ideographicDescriptionCharacters, first: '\u2FF0', last: '\u2FFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ideographicDescriptionCharacters;
+
+ ///
+ /// A filter which allows characters in the 'CJK Symbols and Punctuation' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3000 .. U+303F.
+ /// See http://www.unicode.org/charts/PDF/U3000.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKSymbolsandPunctuation
+ {
+ get
+ {
+ return GetFilter(ref _cjkSymbolsandPunctuation, first: '\u3000', last: '\u303F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkSymbolsandPunctuation;
+
+ ///
+ /// A filter which allows characters in the 'Hiragana' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3040 .. U+309F.
+ /// See http://www.unicode.org/charts/PDF/U3040.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Hiragana
+ {
+ get
+ {
+ return GetFilter(ref _hiragana, first: '\u3040', last: '\u309F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hiragana;
+
+ ///
+ /// A filter which allows characters in the 'Katakana' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+30A0 .. U+30FF.
+ /// See http://www.unicode.org/charts/PDF/U30A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Katakana
+ {
+ get
+ {
+ return GetFilter(ref _katakana, first: '\u30A0', last: '\u30FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _katakana;
+
+ ///
+ /// A filter which allows characters in the 'Bopomofo' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3100 .. U+312F.
+ /// See http://www.unicode.org/charts/PDF/U3100.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Bopomofo
+ {
+ get
+ {
+ return GetFilter(ref _bopomofo, first: '\u3100', last: '\u312F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _bopomofo;
+
+ ///
+ /// A filter which allows characters in the 'Hangul Compatibility Jamo' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3130 .. U+318F.
+ /// See http://www.unicode.org/charts/PDF/U3130.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter HangulCompatibilityJamo
+ {
+ get
+ {
+ return GetFilter(ref _hangulCompatibilityJamo, first: '\u3130', last: '\u318F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hangulCompatibilityJamo;
+
+ ///
+ /// A filter which allows characters in the 'Kanbun' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3190 .. U+319F.
+ /// See http://www.unicode.org/charts/PDF/U3190.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Kanbun
+ {
+ get
+ {
+ return GetFilter(ref _kanbun, first: '\u3190', last: '\u319F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _kanbun;
+
+ ///
+ /// A filter which allows characters in the 'Bopomofo Extended' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+31A0 .. U+31BF.
+ /// See http://www.unicode.org/charts/PDF/U31A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter BopomofoExtended
+ {
+ get
+ {
+ return GetFilter(ref _bopomofoExtended, first: '\u31A0', last: '\u31BF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _bopomofoExtended;
+
+ ///
+ /// A filter which allows characters in the 'CJK Strokes' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+31C0 .. U+31EF.
+ /// See http://www.unicode.org/charts/PDF/U31C0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKStrokes
+ {
+ get
+ {
+ return GetFilter(ref _cjkStrokes, first: '\u31C0', last: '\u31EF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkStrokes;
+
+ ///
+ /// A filter which allows characters in the 'Katakana Phonetic Extensions' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+31F0 .. U+31FF.
+ /// See http://www.unicode.org/charts/PDF/U31F0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter KatakanaPhoneticExtensions
+ {
+ get
+ {
+ return GetFilter(ref _katakanaPhoneticExtensions, first: '\u31F0', last: '\u31FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _katakanaPhoneticExtensions;
+
+ ///
+ /// A filter which allows characters in the 'Enclosed CJK Letters and Months' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3200 .. U+32FF.
+ /// See http://www.unicode.org/charts/PDF/U3200.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter EnclosedCJKLettersandMonths
+ {
+ get
+ {
+ return GetFilter(ref _enclosedCJKLettersandMonths, first: '\u3200', last: '\u32FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _enclosedCJKLettersandMonths;
+
+ ///
+ /// A filter which allows characters in the 'CJK Compatibility' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3300 .. U+33FF.
+ /// See http://www.unicode.org/charts/PDF/U3300.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKCompatibility
+ {
+ get
+ {
+ return GetFilter(ref _cjkCompatibility, first: '\u3300', last: '\u33FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkCompatibility;
+
+ ///
+ /// A filter which allows characters in the 'CJK Unified Ideographs Extension A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+3400 .. U+4DBF.
+ /// See http://www.unicode.org/charts/PDF/U3400.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKUnifiedIdeographsExtensionA
+ {
+ get
+ {
+ return GetFilter(ref _cjkUnifiedIdeographsExtensionA, first: '\u3400', last: '\u4DBF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkUnifiedIdeographsExtensionA;
+
+ ///
+ /// A filter which allows characters in the 'Yijing Hexagram Symbols' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+4DC0 .. U+4DFF.
+ /// See http://www.unicode.org/charts/PDF/U4DC0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter YijingHexagramSymbols
+ {
+ get
+ {
+ return GetFilter(ref _yijingHexagramSymbols, first: '\u4DC0', last: '\u4DFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _yijingHexagramSymbols;
+
+ ///
+ /// A filter which allows characters in the 'CJK Unified Ideographs' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+4E00 .. U+9FFF.
+ /// See http://www.unicode.org/charts/PDF/U4E00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKUnifiedIdeographs
+ {
+ get
+ {
+ return GetFilter(ref _cjkUnifiedIdeographs, first: '\u4E00', last: '\u9FFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkUnifiedIdeographs;
+
+ ///
+ /// A filter which allows characters in the 'Yi Syllables' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A000 .. U+A48F.
+ /// See http://www.unicode.org/charts/PDF/UA000.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter YiSyllables
+ {
+ get
+ {
+ return GetFilter(ref _yiSyllables, first: '\uA000', last: '\uA48F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _yiSyllables;
+
+ ///
+ /// A filter which allows characters in the 'Yi Radicals' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A490 .. U+A4CF.
+ /// See http://www.unicode.org/charts/PDF/UA490.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter YiRadicals
+ {
+ get
+ {
+ return GetFilter(ref _yiRadicals, first: '\uA490', last: '\uA4CF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _yiRadicals;
+
+ ///
+ /// A filter which allows characters in the 'Lisu' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A4D0 .. U+A4FF.
+ /// See http://www.unicode.org/charts/PDF/UA4D0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Lisu
+ {
+ get
+ {
+ return GetFilter(ref _lisu, first: '\uA4D0', last: '\uA4FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _lisu;
+
+ ///
+ /// A filter which allows characters in the 'Vai' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A500 .. U+A63F.
+ /// See http://www.unicode.org/charts/PDF/UA500.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Vai
+ {
+ get
+ {
+ return GetFilter(ref _vai, first: '\uA500', last: '\uA63F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _vai;
+
+ ///
+ /// A filter which allows characters in the 'Cyrillic Extended-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A640 .. U+A69F.
+ /// See http://www.unicode.org/charts/PDF/UA640.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CyrillicExtendedB
+ {
+ get
+ {
+ return GetFilter(ref _cyrillicExtendedB, first: '\uA640', last: '\uA69F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cyrillicExtendedB;
+
+ ///
+ /// A filter which allows characters in the 'Bamum' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A6A0 .. U+A6FF.
+ /// See http://www.unicode.org/charts/PDF/UA6A0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Bamum
+ {
+ get
+ {
+ return GetFilter(ref _bamum, first: '\uA6A0', last: '\uA6FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _bamum;
+
+ ///
+ /// A filter which allows characters in the 'Modifier Tone Letters' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A700 .. U+A71F.
+ /// See http://www.unicode.org/charts/PDF/UA700.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter ModifierToneLetters
+ {
+ get
+ {
+ return GetFilter(ref _modifierToneLetters, first: '\uA700', last: '\uA71F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _modifierToneLetters;
+
+ ///
+ /// A filter which allows characters in the 'Latin Extended-D' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A720 .. U+A7FF.
+ /// See http://www.unicode.org/charts/PDF/UA720.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LatinExtendedD
+ {
+ get
+ {
+ return GetFilter(ref _latinExtendedD, first: '\uA720', last: '\uA7FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latinExtendedD;
+
+ ///
+ /// A filter which allows characters in the 'Syloti Nagri' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A800 .. U+A82F.
+ /// See http://www.unicode.org/charts/PDF/UA800.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SylotiNagri
+ {
+ get
+ {
+ return GetFilter(ref _sylotiNagri, first: '\uA800', last: '\uA82F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _sylotiNagri;
+
+ ///
+ /// A filter which allows characters in the 'Common Indic Number Forms' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A830 .. U+A83F.
+ /// See http://www.unicode.org/charts/PDF/UA830.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CommonIndicNumberForms
+ {
+ get
+ {
+ return GetFilter(ref _commonIndicNumberForms, first: '\uA830', last: '\uA83F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _commonIndicNumberForms;
+
+ ///
+ /// A filter which allows characters in the 'Phags-pa' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A840 .. U+A87F.
+ /// See http://www.unicode.org/charts/PDF/UA840.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Phagspa
+ {
+ get
+ {
+ return GetFilter(ref _phagspa, first: '\uA840', last: '\uA87F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _phagspa;
+
+ ///
+ /// A filter which allows characters in the 'Saurashtra' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A880 .. U+A8DF.
+ /// See http://www.unicode.org/charts/PDF/UA880.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Saurashtra
+ {
+ get
+ {
+ return GetFilter(ref _saurashtra, first: '\uA880', last: '\uA8DF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _saurashtra;
+
+ ///
+ /// A filter which allows characters in the 'Devanagari Extended' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A8E0 .. U+A8FF.
+ /// See http://www.unicode.org/charts/PDF/UA8E0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter DevanagariExtended
+ {
+ get
+ {
+ return GetFilter(ref _devanagariExtended, first: '\uA8E0', last: '\uA8FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _devanagariExtended;
+
+ ///
+ /// A filter which allows characters in the 'Kayah Li' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A900 .. U+A92F.
+ /// See http://www.unicode.org/charts/PDF/UA900.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter KayahLi
+ {
+ get
+ {
+ return GetFilter(ref _kayahLi, first: '\uA900', last: '\uA92F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _kayahLi;
+
+ ///
+ /// A filter which allows characters in the 'Rejang' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A930 .. U+A95F.
+ /// See http://www.unicode.org/charts/PDF/UA930.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Rejang
+ {
+ get
+ {
+ return GetFilter(ref _rejang, first: '\uA930', last: '\uA95F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _rejang;
+
+ ///
+ /// A filter which allows characters in the 'Hangul Jamo Extended-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A960 .. U+A97F.
+ /// See http://www.unicode.org/charts/PDF/UA960.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter HangulJamoExtendedA
+ {
+ get
+ {
+ return GetFilter(ref _hangulJamoExtendedA, first: '\uA960', last: '\uA97F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hangulJamoExtendedA;
+
+ ///
+ /// A filter which allows characters in the 'Javanese' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A980 .. U+A9DF.
+ /// See http://www.unicode.org/charts/PDF/UA980.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Javanese
+ {
+ get
+ {
+ return GetFilter(ref _javanese, first: '\uA980', last: '\uA9DF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _javanese;
+
+ ///
+ /// A filter which allows characters in the 'Myanmar Extended-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+A9E0 .. U+A9FF.
+ /// See http://www.unicode.org/charts/PDF/UA9E0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MyanmarExtendedB
+ {
+ get
+ {
+ return GetFilter(ref _myanmarExtendedB, first: '\uA9E0', last: '\uA9FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _myanmarExtendedB;
+
+ ///
+ /// A filter which allows characters in the 'Cham' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AA00 .. U+AA5F.
+ /// See http://www.unicode.org/charts/PDF/UAA00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Cham
+ {
+ get
+ {
+ return GetFilter(ref _cham, first: '\uAA00', last: '\uAA5F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cham;
+
+ ///
+ /// A filter which allows characters in the 'Myanmar Extended-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AA60 .. U+AA7F.
+ /// See http://www.unicode.org/charts/PDF/UAA60.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MyanmarExtendedA
+ {
+ get
+ {
+ return GetFilter(ref _myanmarExtendedA, first: '\uAA60', last: '\uAA7F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _myanmarExtendedA;
+
+ ///
+ /// A filter which allows characters in the 'Tai Viet' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AA80 .. U+AADF.
+ /// See http://www.unicode.org/charts/PDF/UAA80.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter TaiViet
+ {
+ get
+ {
+ return GetFilter(ref _taiViet, first: '\uAA80', last: '\uAADF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _taiViet;
+
+ ///
+ /// A filter which allows characters in the 'Meetei Mayek Extensions' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AAE0 .. U+AAFF.
+ /// See http://www.unicode.org/charts/PDF/UAAE0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MeeteiMayekExtensions
+ {
+ get
+ {
+ return GetFilter(ref _meeteiMayekExtensions, first: '\uAAE0', last: '\uAAFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _meeteiMayekExtensions;
+
+ ///
+ /// A filter which allows characters in the 'Ethiopic Extended-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AB00 .. U+AB2F.
+ /// See http://www.unicode.org/charts/PDF/UAB00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter EthiopicExtendedA
+ {
+ get
+ {
+ return GetFilter(ref _ethiopicExtendedA, first: '\uAB00', last: '\uAB2F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _ethiopicExtendedA;
+
+ ///
+ /// A filter which allows characters in the 'Latin Extended-E' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AB30 .. U+AB6F.
+ /// See http://www.unicode.org/charts/PDF/UAB30.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter LatinExtendedE
+ {
+ get
+ {
+ return GetFilter(ref _latinExtendedE, first: '\uAB30', last: '\uAB6F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _latinExtendedE;
+
+ ///
+ /// A filter which allows characters in the 'Meetei Mayek' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+ABC0 .. U+ABFF.
+ /// See http://www.unicode.org/charts/PDF/UABC0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter MeeteiMayek
+ {
+ get
+ {
+ return GetFilter(ref _meeteiMayek, first: '\uABC0', last: '\uABFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _meeteiMayek;
+
+ ///
+ /// A filter which allows characters in the 'Hangul Syllables' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+AC00 .. U+D7AF.
+ /// See http://www.unicode.org/charts/PDF/UAC00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter HangulSyllables
+ {
+ get
+ {
+ return GetFilter(ref _hangulSyllables, first: '\uAC00', last: '\uD7AF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hangulSyllables;
+
+ ///
+ /// A filter which allows characters in the 'Hangul Jamo Extended-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+D7B0 .. U+D7FF.
+ /// See http://www.unicode.org/charts/PDF/UD7B0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter HangulJamoExtendedB
+ {
+ get
+ {
+ return GetFilter(ref _hangulJamoExtendedB, first: '\uD7B0', last: '\uD7FF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _hangulJamoExtendedB;
+
+ ///
+ /// A filter which allows characters in the 'CJK Compatibility Ideographs' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+F900 .. U+FAFF.
+ /// See http://www.unicode.org/charts/PDF/UF900.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKCompatibilityIdeographs
+ {
+ get
+ {
+ return GetFilter(ref _cjkCompatibilityIdeographs, first: '\uF900', last: '\uFAFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkCompatibilityIdeographs;
+
+ ///
+ /// A filter which allows characters in the 'Alphabetic Presentation Forms' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FB00 .. U+FB4F.
+ /// See http://www.unicode.org/charts/PDF/UFB00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter AlphabeticPresentationForms
+ {
+ get
+ {
+ return GetFilter(ref _alphabeticPresentationForms, first: '\uFB00', last: '\uFB4F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _alphabeticPresentationForms;
+
+ ///
+ /// A filter which allows characters in the 'Arabic Presentation Forms-A' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FB50 .. U+FDFF.
+ /// See http://www.unicode.org/charts/PDF/UFB50.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter ArabicPresentationFormsA
+ {
+ get
+ {
+ return GetFilter(ref _arabicPresentationFormsA, first: '\uFB50', last: '\uFDFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _arabicPresentationFormsA;
+
+ ///
+ /// A filter which allows characters in the 'Variation Selectors' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FE00 .. U+FE0F.
+ /// See http://www.unicode.org/charts/PDF/UFE00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter VariationSelectors
+ {
+ get
+ {
+ return GetFilter(ref _variationSelectors, first: '\uFE00', last: '\uFE0F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _variationSelectors;
+
+ ///
+ /// A filter which allows characters in the 'Vertical Forms' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FE10 .. U+FE1F.
+ /// See http://www.unicode.org/charts/PDF/UFE10.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter VerticalForms
+ {
+ get
+ {
+ return GetFilter(ref _verticalForms, first: '\uFE10', last: '\uFE1F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _verticalForms;
+
+ ///
+ /// A filter which allows characters in the 'Combining Half Marks' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FE20 .. U+FE2F.
+ /// See http://www.unicode.org/charts/PDF/UFE20.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CombiningHalfMarks
+ {
+ get
+ {
+ return GetFilter(ref _combiningHalfMarks, first: '\uFE20', last: '\uFE2F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _combiningHalfMarks;
+
+ ///
+ /// A filter which allows characters in the 'CJK Compatibility Forms' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FE30 .. U+FE4F.
+ /// See http://www.unicode.org/charts/PDF/UFE30.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter CJKCompatibilityForms
+ {
+ get
+ {
+ return GetFilter(ref _cjkCompatibilityForms, first: '\uFE30', last: '\uFE4F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _cjkCompatibilityForms;
+
+ ///
+ /// A filter which allows characters in the 'Small Form Variants' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FE50 .. U+FE6F.
+ /// See http://www.unicode.org/charts/PDF/UFE50.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter SmallFormVariants
+ {
+ get
+ {
+ return GetFilter(ref _smallFormVariants, first: '\uFE50', last: '\uFE6F');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _smallFormVariants;
+
+ ///
+ /// A filter which allows characters in the 'Arabic Presentation Forms-B' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FE70 .. U+FEFF.
+ /// See http://www.unicode.org/charts/PDF/UFE70.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter ArabicPresentationFormsB
+ {
+ get
+ {
+ return GetFilter(ref _arabicPresentationFormsB, first: '\uFE70', last: '\uFEFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _arabicPresentationFormsB;
+
+ ///
+ /// A filter which allows characters in the 'Halfwidth and Fullwidth Forms' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FF00 .. U+FFEF.
+ /// See http://www.unicode.org/charts/PDF/UFF00.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter HalfwidthandFullwidthForms
+ {
+ get
+ {
+ return GetFilter(ref _halfwidthandFullwidthForms, first: '\uFF00', last: '\uFFEF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _halfwidthandFullwidthForms;
+
+ ///
+ /// A filter which allows characters in the 'Specials' Unicode range.
+ ///
+ ///
+ /// This range spans the code points U+FFF0 .. U+FFFF.
+ /// See http://www.unicode.org/charts/PDF/UFFF0.pdf for the full set of characters in this range.
+ ///
+ public static ICodePointFilter Specials
+ {
+ get
+ {
+ return GetFilter(ref _specials, first: '\uFFF0', last: '\uFFFF');
+ }
+ }
+ private static DefinedCharacterCodePointFilter _specials;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static ICodePointFilter GetFilter(ref DefinedCharacterCodePointFilter filter, char first, char last)
+ {
+ // Return an existing filter if it has already been created, otherwise
+ // create a new filter on-demand.
+ return Volatile.Read(ref filter) ?? GetFilterSlow(ref filter, first, last);
+ }
+
+ private static ICodePointFilter GetFilterSlow(ref DefinedCharacterCodePointFilter filter, char first, char last)
+ {
+ // If the filter hasn't been created, create it now.
+ // It's ok if two threads race and one overwrites the other's 'filter' value.
+ DefinedCharacterCodePointFilter newFilter = new DefinedCharacterCodePointFilter(first, last);
+ Volatile.Write(ref filter, newFilter);
+ return newFilter;
+ }
+
+ ///
+ /// A code point filter which returns only defined characters within a certain
+ /// range of the Unicode specification.
+ ///
+ private sealed class DefinedCharacterCodePointFilter : ICodePointFilter
+ {
+ private readonly int _count;
+ private readonly int _first;
+
+ public DefinedCharacterCodePointFilter(int first, int last)
+ {
+ Debug.Assert(0 <= first);
+ Debug.Assert(first <= last);
+ Debug.Assert(last <= 0xFFFF);
+
+ _first = first;
+ _count = last - first + 1;
+ }
+
+ public IEnumerable GetAllowedCodePoints()
+ {
+ for (int i = 0; i < _count; i++)
+ {
+ int thisCodePoint = _first + i;
+ if (UnicodeHelpers.IsCharacterDefined((char)thisCodePoint))
+ {
+ yield return thisCodePoint;
+ }
+ }
+ }
+ }
+
+ ///
+ /// A filter that allows no code points.
+ ///
+ private sealed class EmptyCodePointFilter : ICodePointFilter
+ {
+ public IEnumerable GetAllowedCodePoints()
+ {
+ return Enumerable.Empty();
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/EncoderCommon.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/EncoderCommon.cs
new file mode 100644
index 0000000000..a46ae99ed2
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/EncoderCommon.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ internal static class EncoderCommon
+ {
+ // Gets the optimal capacity of the StringBuilder that will be used to build the output
+ // given a specified number of input characters and the worst-case growth.
+ public static int GetCapacityOfOutputStringBuilder(int numCharsToEncode, int worstCaseOutputCharsPerInputChar)
+ {
+ // We treat 32KB byte size (16k chars) as a soft upper boundary for the length of any StringBuilder
+ // that we allocate. We'll try to avoid going above this boundary if we can avoid it so that we
+ // don't allocate objects on the LOH.
+ const int upperBound = 16 * 1024;
+
+ // Once we have chosen an initial value for the StringBuilder size, the StringBuilder type will
+ // efficiently allocate additionally blocks if necessary.
+
+ if (numCharsToEncode >= upperBound)
+ {
+ // We know that the output will contain at least as many characters as the input, so if the
+ // input length exceeds the soft upper boundary just preallocate the entire builder and hope for
+ // a best-case outcome.
+ return numCharsToEncode;
+ }
+ else
+ {
+ // Allocate the worst-case if we can, but don't exceed the soft upper boundary.
+ long worstCaseTotalChars = (long)numCharsToEncode * worstCaseOutputCharsPerInputChar;
+ return (int)Math.Min(upperBound, worstCaseTotalChars);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/HexUtil.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/HexUtil.cs
new file mode 100644
index 0000000000..05fa1c5882
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/HexUtil.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Contains helpers for dealing with byte-hex char conversions.
+ ///
+ internal static class HexUtil
+ {
+ ///
+ /// Converts a number 0 - 15 to its associated hex character '0' - 'F'.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static char IntToChar(uint i)
+ {
+ Debug.Assert(i < 16);
+ return (i < 10) ? (char)('0' + i) : (char)('A' + (i - 10));
+ }
+
+ ///
+ /// Returns the integral form of this hexadecimal character.
+ ///
+ /// 0 - 15 if the character is valid, -1 if the character is invalid.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int ParseHexCharacter(char c)
+ {
+ if ('0' <= c && c <= '9') { return c - '0'; }
+ else if ('A' <= c && c <= 'F') { return c - 'A' + 10; }
+ else if ('a' <= c && c <= 'f') { return c - 'a' + 10; }
+ else { return -1; }
+ }
+
+ ///
+ /// Gets the uppercase hex-encoded form of a byte.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void WriteHexEncodedByte(byte b, out char firstHexChar, out char secondHexChar)
+ {
+ firstHexChar = IntToChar((uint)b >> 4);
+ secondHexChar = IntToChar((uint)b & 0xFU);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/HtmlEncoder.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/HtmlEncoder.cs
new file mode 100644
index 0000000000..b0559d7219
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/HtmlEncoder.cs
@@ -0,0 +1,229 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// A class which can perform HTML encoding given an allow list of characters which
+ /// can be represented unencoded.
+ ///
+ ///
+ /// Once constructed, instances of this class are thread-safe for multiple callers.
+ ///
+ public unsafe sealed class HtmlEncoder : IHtmlEncoder
+ {
+ // The default HtmlEncoder (Basic Latin), instantiated on demand
+ private static HtmlEncoder _defaultEncoder;
+
+ // A bitmap of characters which are allowed to be returned unescaped.
+ private readonly uint[] _allowedCharsBitmap = new uint[0x10000 / 32];
+
+ ///
+ /// Instantiates an encoder using the 'Basic Latin' code table as the allow list.
+ ///
+ public HtmlEncoder()
+ : this(CodePointFilters.BasicLatin)
+ {
+ }
+
+ ///
+ /// Instantiates an encoder using a custom allow list of characters.
+ ///
+ public HtmlEncoder(params ICodePointFilter[] filters)
+ {
+ if (filters == null)
+ {
+ return; // no characters are allowed, just no-op immediately
+ }
+
+ // Punch a hole for each allowed code point across all filters (this is an OR).
+ // We don't allow supplementary (astral) characters for now.
+ foreach (var filter in filters)
+ {
+ foreach (var codePoint in filter.GetAllowedCodePoints())
+ {
+ if (!UnicodeHelpers.IsSupplementaryCodePoint(codePoint))
+ {
+ AllowCharacter((char)codePoint);
+ }
+ }
+ }
+
+ // Forbid characters that are special in HTML
+ ForbidCharacter('<');
+ ForbidCharacter('>');
+ ForbidCharacter('&');
+ ForbidCharacter('\''); // can be used to escape attributes
+ ForbidCharacter('\"'); // can be used to escape attributes
+ ForbidCharacter('+'); // technically not HTML-specific, but can be used to perform UTF7-based attacks
+
+ // Forbid codepoints which aren't mapped to characters or which are otherwise always disallowed
+ // (includes categories Cc, Cs, Co, Cn, Zl, Zp)
+ uint[] definedCharactersBitmap = UnicodeHelpers.GetDefinedCharacterBitmap();
+ Debug.Assert(definedCharactersBitmap.Length == _allowedCharsBitmap.Length);
+ for (int i = 0; i < _allowedCharsBitmap.Length; i++)
+ {
+ _allowedCharsBitmap[i] &= definedCharactersBitmap[i];
+ }
+ }
+
+ ///
+ /// A default instance of the HtmlEncoder, equivalent to allowing only
+ /// the 'Basic Latin' character range.
+ ///
+ public static HtmlEncoder Default
+ {
+ get
+ {
+ HtmlEncoder defaultEncoder = Volatile.Read(ref _defaultEncoder);
+ if (defaultEncoder == null)
+ {
+ defaultEncoder = new HtmlEncoder();
+ Volatile.Write(ref _defaultEncoder, defaultEncoder);
+ }
+ return defaultEncoder;
+ }
+ }
+
+ // Marks a character as allowed (can be returned unencoded)
+ private void AllowCharacter(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ _allowedCharsBitmap[index] |= 0x1U << offset;
+ }
+
+ // Marks a character as forbidden (must be returned encoded)
+ private void ForbidCharacter(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ _allowedCharsBitmap[index] &= ~(0x1U << offset);
+ }
+
+ ///
+ /// Everybody's favorite HtmlEncode routine.
+ ///
+ public string HtmlEncode(string value)
+ {
+ if (String.IsNullOrEmpty(value))
+ {
+ return value;
+ }
+
+ // Quick check: does the string need to be encoded at all?
+ // If not, just return the input string as-is.
+ for (int i = 0; i < value.Length; i++)
+ {
+ if (!IsCharacterAllowed(value[i]))
+ {
+ return HtmlEncodeImpl(value, i);
+ }
+ }
+ return value;
+ }
+
+ private string HtmlEncodeImpl(string input, int idxOfFirstCharWhichRequiresEncoding)
+ {
+ Debug.Assert(idxOfFirstCharWhichRequiresEncoding >= 0);
+ Debug.Assert(idxOfFirstCharWhichRequiresEncoding < input.Length);
+
+ // The worst case encoding is 8 output chars per input char: [input] U+FFFF -> [output] ""
+ // We don't need to worry about astral code points since they consume *two* input chars to
+ // generate at most 10 output chars (""), which equates to 5 output per input.
+ int numCharsWhichMayRequireEncoding = input.Length - idxOfFirstCharWhichRequiresEncoding;
+ int sbCapacity = checked(idxOfFirstCharWhichRequiresEncoding + EncoderCommon.GetCapacityOfOutputStringBuilder(numCharsWhichMayRequireEncoding, worstCaseOutputCharsPerInputChar: 8));
+ Debug.Assert(sbCapacity >= input.Length);
+
+ // Allocate the StringBuilder with the first (known to not require encoding) part of the input string,
+ // then begin encoding from the last (potentially requiring encoding) part of the input string.
+ StringBuilder builder = new StringBuilder(input, 0, idxOfFirstCharWhichRequiresEncoding, sbCapacity);
+ fixed (char* pInput = input)
+ {
+ return HtmlEncodeImpl2(builder, &pInput[idxOfFirstCharWhichRequiresEncoding], (uint)numCharsWhichMayRequireEncoding);
+ }
+ }
+
+ private string HtmlEncodeImpl2(StringBuilder builder, char* input, uint charsRemaining)
+ {
+ while (charsRemaining != 0)
+ {
+ int nextScalar = UnicodeHelpers.GetScalarValueFromUtf16(input, endOfString: (charsRemaining == 1));
+ if (UnicodeHelpers.IsSupplementaryCodePoint(nextScalar))
+ {
+ // Supplementary characters should always be encoded numerically.
+ WriteScalarAsHtmlEncodedEntity(builder, (uint)nextScalar);
+
+ // We consume two UTF-16 characters for a single supplementary character.
+ input += 2;
+ charsRemaining -= 2;
+ }
+ else
+ {
+ // Otherwise, this was a BMP character.
+ input++;
+ charsRemaining--;
+ char c = (char)nextScalar;
+ if (IsCharacterAllowed(c))
+ {
+ builder.Append(c);
+ }
+ else
+ {
+ if (c == '<') { builder.Append("<"); }
+ else if (c == '>') { builder.Append(">"); }
+ else if (c == '&') { builder.Append("&"); }
+ else if (c == '\"') { builder.Append("""); }
+ else { WriteScalarAsHtmlEncodedEntity(builder, (uint)nextScalar); }
+ }
+ }
+ }
+
+ return builder.ToString();
+ }
+
+ // Determines whether the given character can be returned unencoded.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool IsCharacterAllowed(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ return ((_allowedCharsBitmap[index] >> offset) & 0x1U) != 0;
+ }
+
+ // Writes a scalar value as ""
+ private static void WriteScalarAsHtmlEncodedEntity(StringBuilder builder, uint value)
+ {
+ // We're building the characters up in reverse
+ char* chars = stackalloc char[8 /* "FFFFFFFF" */];
+ int numCharsWritten = 0;
+ do
+ {
+ Debug.Assert(numCharsWritten < 8, "Couldn't have written 8 characters out by this point.");
+ // Pop off the last nibble
+ chars[numCharsWritten++] = HexUtil.IntToChar(value & 0xFU);
+ value >>= 4;
+ } while (value != 0);
+
+ // Finally, write out the HTML-encoded scalar value.
+ builder.Append('&');
+ builder.Append('#');
+ builder.Append('x');
+ Debug.Assert(numCharsWritten > 0, "At least one character should've been written.");
+ do
+ {
+ builder.Append(chars[--numCharsWritten]);
+ } while (numCharsWritten != 0);
+ builder.Append(';');
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/ICodePointFilter.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/ICodePointFilter.cs
new file mode 100644
index 0000000000..e57b6535d2
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/ICodePointFilter.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Represents a filter which allows only certain Unicode code points through.
+ ///
+ public interface ICodePointFilter
+ {
+ ///
+ /// Gets an enumeration of all allowed code points.
+ ///
+ IEnumerable GetAllowedCodePoints();
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/IHtmlEncoder.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/IHtmlEncoder.cs
new file mode 100644
index 0000000000..e80fb908a7
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/IHtmlEncoder.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Provides services for HTML-encoding input.
+ ///
+ public interface IHtmlEncoder
+ {
+ ///
+ /// HTML-encodes a given input string.
+ ///
+ ///
+ /// The HTML-encoded value, or null if the input string was null.
+ ///
+ ///
+ /// The return value is also safe for inclusion inside an HTML attribute
+ /// as long as the attribute value is surrounded by single or double quotes.
+ ///
+ string HtmlEncode(string value);
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/IJavaScriptStringEncoder.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/IJavaScriptStringEncoder.cs
new file mode 100644
index 0000000000..8a287548cf
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/IJavaScriptStringEncoder.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Provides services for JavaScript-escaping strings.
+ ///
+ public interface IJavaScriptStringEncoder
+ {
+ ///
+ /// JavaScript-escapes a given input string.
+ ///
+ ///
+ /// The JavaScript-escaped value, or null if the input string was null.
+ ///
+ string JavaScriptStringEncode(string value);
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/IUrlEncoder.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/IUrlEncoder.cs
new file mode 100644
index 0000000000..0806f5f971
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/IUrlEncoder.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Provides services for URL-escaping strings.
+ ///
+ public interface IUrlEncoder
+ {
+ ///
+ /// URL-escapes a given input string.
+ ///
+ ///
+ /// The URL-escaped value, or null if the input string was null.
+ ///
+ ///
+ /// The return value is safe for use in the segment, query, or
+ /// fragment portion of a URI.
+ ///
+ string UrlEncode(string value);
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/JavaScriptStringEncoder.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/JavaScriptStringEncoder.cs
new file mode 100644
index 0000000000..671d2081b3
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/JavaScriptStringEncoder.cs
@@ -0,0 +1,163 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// A class which can perform JavaScript string escaping given an allow list of characters which
+ /// can be represented unescaped.
+ ///
+ ///
+ /// Once constructed, instances of this class are thread-safe for multiple callers.
+ ///
+ public sealed class JavaScriptStringEncoder : IJavaScriptStringEncoder
+ {
+ // The default JavaScript string encoder (Basic Latin), instantiated on demand
+ private static JavaScriptStringEncoder _defaultEncoder;
+
+ // The inner encoder, responsible for the actual encoding routines
+ private readonly JavaScriptStringUnicodeEncoder _innerUnicodeEncoder;
+
+ ///
+ /// Instantiates an encoder using the 'Basic Latin' code table as the allow list.
+ ///
+ public JavaScriptStringEncoder()
+ : this(JavaScriptStringUnicodeEncoder.BasicLatin)
+ {
+ }
+
+ ///
+ /// Instantiates an encoder using a custom allow list of characters.
+ ///
+ public JavaScriptStringEncoder(params ICodePointFilter[] filters)
+ : this(new JavaScriptStringUnicodeEncoder(filters))
+ {
+ }
+
+ private JavaScriptStringEncoder(JavaScriptStringUnicodeEncoder innerEncoder)
+ {
+ Debug.Assert(innerEncoder != null);
+ _innerUnicodeEncoder = innerEncoder;
+ }
+
+ ///
+ /// A default instance of the JavaScriptStringEncoder, equivalent to allowing only
+ /// the 'Basic Latin' character range.
+ ///
+ public static JavaScriptStringEncoder Default
+ {
+ get
+ {
+ JavaScriptStringEncoder defaultEncoder = Volatile.Read(ref _defaultEncoder);
+ if (defaultEncoder == null)
+ {
+ defaultEncoder = new JavaScriptStringEncoder();
+ Volatile.Write(ref _defaultEncoder, defaultEncoder);
+ }
+ return defaultEncoder;
+ }
+ }
+
+ ///
+ /// Everybody's favorite JavaScriptStringEncode routine.
+ ///
+ public string JavaScriptStringEncode(string value)
+ {
+ return _innerUnicodeEncoder.Encode(value);
+ }
+
+ private sealed class JavaScriptStringUnicodeEncoder : UnicodeEncoderBase
+ {
+ // A singleton instance of the basic latin encoder.
+ private static JavaScriptStringUnicodeEncoder _basicLatinSingleton;
+
+ // The worst case encoding is 6 output chars per input char: [input] U+FFFF -> [output] "\uFFFF"
+ // We don't need to worry about astral code points since they're represented as encoded
+ // surrogate pairs in the output.
+ private const int MaxOutputCharsPerInputChar = 6;
+
+ internal JavaScriptStringUnicodeEncoder(ICodePointFilter[] filters)
+ : base(filters, MaxOutputCharsPerInputChar)
+ {
+ // The only interesting characters above and beyond what the base encoder
+ // already covers are the solidus and reverse solidus.
+ ForbidCharacter('\\');
+ ForbidCharacter('/');
+ }
+
+ internal static JavaScriptStringUnicodeEncoder BasicLatin
+ {
+ get
+ {
+ JavaScriptStringUnicodeEncoder encoder = Volatile.Read(ref _basicLatinSingleton);
+ if (encoder == null)
+ {
+ encoder = new JavaScriptStringUnicodeEncoder(new[] { CodePointFilters.BasicLatin });
+ Volatile.Write(ref _basicLatinSingleton, encoder);
+ }
+ return encoder;
+ }
+ }
+
+ // Writes a scalar value as a JavaScript-escaped character (or sequence of characters).
+ // See ECMA-262, Sec. 7.8.4, and ECMA-404, Sec. 9
+ // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
+ // http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
+ protected override void WriteEncodedScalar(StringBuilder builder, uint value)
+ {
+ // ECMA-262 allows encoding U+000B as "\v", but ECMA-404 does not.
+ // Both ECMA-262 and ECMA-404 allow encoding U+002F SOLIDUS as "\/".
+ // (In ECMA-262 this character is a NonEscape character.)
+ // HTML-specific characters (including apostrophe and quotes) will
+ // be written out as numeric entities for defense-in-depth.
+ // See UnicodeEncoderBase ctor comments for more info.
+
+ if (value == (uint)'\b') { builder.Append(@"\b"); }
+ else if (value == (uint)'\t') { builder.Append(@"\t"); }
+ else if (value == (uint)'\n') { builder.Append(@"\n"); }
+ else if (value == (uint)'\f') { builder.Append(@"\f"); }
+ else if (value == (uint)'\r') { builder.Append(@"\r"); }
+ else if (value == (uint)'/') { builder.Append(@"\/"); }
+ else if (value == (uint)'\\') { builder.Append(@"\\"); }
+ else { WriteEncodedScalarAsNumericEntity(builder, value); }
+ }
+
+ // Writes a scalar value as an JavaScript-escaped character (or sequence of characters).
+ private static void WriteEncodedScalarAsNumericEntity(StringBuilder builder, uint value)
+ {
+ if (UnicodeHelpers.IsSupplementaryCodePoint((int)value))
+ {
+ // Convert this back to UTF-16 and write out both characters.
+ char leadingSurrogate, trailingSurrogate;
+ UnicodeHelpers.GetUtf16SurrogatePairFromAstralScalarValue((int)value, out leadingSurrogate, out trailingSurrogate);
+ WriteEncodedSingleCharacter(builder, leadingSurrogate);
+ WriteEncodedSingleCharacter(builder, trailingSurrogate);
+ }
+ else
+ {
+ // This is only a single character.
+ WriteEncodedSingleCharacter(builder, value);
+ }
+ }
+
+ // Writes an encoded scalar value (in the BMP) as a JavaScript-escaped character.
+ private static void WriteEncodedSingleCharacter(StringBuilder builder, uint value)
+ {
+ Debug.Assert(!UnicodeHelpers.IsSupplementaryCodePoint((int)value), "The incoming value should've been in the BMP.");
+
+ // Encode this as 6 chars "\uFFFF".
+ builder.Append('\\');
+ builder.Append('u');
+ builder.Append(HexUtil.IntToChar(value >> 12));
+ builder.Append(HexUtil.IntToChar((value >> 8) & 0xFU));
+ builder.Append(HexUtil.IntToChar((value >> 4) & 0xFU));
+ builder.Append(HexUtil.IntToChar(value & 0xFU));
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/UnicodeEncoderBase.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/UnicodeEncoderBase.cs
new file mode 100644
index 0000000000..2f04910b30
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/UnicodeEncoderBase.cs
@@ -0,0 +1,171 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ internal unsafe abstract class UnicodeEncoderBase
+ {
+ // A bitmap of characters which are allowed to be returned unescaped.
+ private readonly uint[] _allowedCharsBitmap = new uint[0x10000 / 32];
+
+ // The worst-case number of output chars generated for any input char.
+ private readonly int _maxOutputCharsPerInputChar;
+
+ ///
+ /// Instantiates an encoder using a custom allow list of characters.
+ ///
+ protected UnicodeEncoderBase(ICodePointFilter[] filters, int maxOutputCharsPerInputChar)
+ {
+ _maxOutputCharsPerInputChar = maxOutputCharsPerInputChar;
+
+ if (filters != null)
+ {
+ // Punch a hole for each allowed code point across all filters (this is an OR).
+ // We don't allow supplementary (astral) characters for now.
+ foreach (var filter in filters)
+ {
+ foreach (var codePoint in filter.GetAllowedCodePoints())
+ {
+ if (!UnicodeHelpers.IsSupplementaryCodePoint(codePoint))
+ {
+ AllowCharacter((char)codePoint);
+ }
+ }
+ }
+ }
+
+ // Forbid characters that are special in HTML.
+ // Even though this is a common encoder used by everybody (including URL
+ // and JavaScript strings), it's unfortunately common for developers to
+ // forget to HTML-encode a string once it has been URL-encoded or
+ // JavaScript string-escaped, so this offers extra protection.
+ ForbidCharacter('<');
+ ForbidCharacter('>');
+ ForbidCharacter('&');
+ ForbidCharacter('\''); // can be used to escape attributes
+ ForbidCharacter('\"'); // can be used to escape attributes
+ ForbidCharacter('+'); // technically not HTML-specific, but can be used to perform UTF7-based attacks
+
+ // Forbid codepoints which aren't mapped to characters or which are otherwise always disallowed
+ // (includes categories Cc, Cs, Co, Cn, Zl, Zp)
+ uint[] definedCharactersBitmap = UnicodeHelpers.GetDefinedCharacterBitmap();
+ Debug.Assert(definedCharactersBitmap.Length == _allowedCharsBitmap.Length);
+ for (int i = 0; i < _allowedCharsBitmap.Length; i++)
+ {
+ _allowedCharsBitmap[i] &= definedCharactersBitmap[i];
+ }
+ }
+
+ // Marks a character as allowed (can be returned unencoded)
+ private void AllowCharacter(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ _allowedCharsBitmap[index] |= 0x1U << offset;
+ }
+
+ // Marks a character as forbidden (must be returned encoded)
+ protected void ForbidCharacter(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ _allowedCharsBitmap[index] &= ~(0x1U << offset);
+ }
+
+ ///
+ /// Entry point to the encoder.
+ ///
+ public string Encode(string value)
+ {
+ if (String.IsNullOrEmpty(value))
+ {
+ return value;
+ }
+
+ // Quick check: does the string need to be encoded at all?
+ // If not, just return the input string as-is.
+ for (int i = 0; i < value.Length; i++)
+ {
+ if (!IsCharacterAllowed(value[i]))
+ {
+ return EncodeCore(value, i);
+ }
+ }
+ return value;
+ }
+
+ private string EncodeCore(string input, int idxOfFirstCharWhichRequiresEncoding)
+ {
+ Debug.Assert(idxOfFirstCharWhichRequiresEncoding >= 0);
+ Debug.Assert(idxOfFirstCharWhichRequiresEncoding < input.Length);
+
+ // The worst case encoding is 8 output chars per input char: [input] U+FFFF -> [output] ""
+ // We don't need to worry about astral code points since they consume *two* input chars to
+ // generate at most 10 output chars (""), which equates to 5 output per input.
+ int numCharsWhichMayRequireEncoding = input.Length - idxOfFirstCharWhichRequiresEncoding;
+ int sbCapacity = checked(idxOfFirstCharWhichRequiresEncoding + EncoderCommon.GetCapacityOfOutputStringBuilder(numCharsWhichMayRequireEncoding, worstCaseOutputCharsPerInputChar: 8));
+ Debug.Assert(sbCapacity >= input.Length);
+
+ // Allocate the StringBuilder with the first (known to not require encoding) part of the input string,
+ // then begin encoding from the last (potentially requiring encoding) part of the input string.
+ StringBuilder builder = new StringBuilder(input, 0, idxOfFirstCharWhichRequiresEncoding, sbCapacity);
+ fixed (char* pInput = input)
+ {
+ return EncodeCore2(builder, &pInput[idxOfFirstCharWhichRequiresEncoding], (uint)numCharsWhichMayRequireEncoding);
+ }
+ }
+
+ private string EncodeCore2(StringBuilder builder, char* input, uint charsRemaining)
+ {
+ while (charsRemaining != 0)
+ {
+ int nextScalar = UnicodeHelpers.GetScalarValueFromUtf16(input, endOfString: (charsRemaining == 1));
+ if (UnicodeHelpers.IsSupplementaryCodePoint(nextScalar))
+ {
+ // Supplementary characters should always be encoded numerically.
+ WriteEncodedScalar(builder, (uint)nextScalar);
+
+ // We consume two UTF-16 characters for a single supplementary character.
+ input += 2;
+ charsRemaining -= 2;
+ }
+ else
+ {
+ // Otherwise, this was a BMP character.
+ input++;
+ charsRemaining--;
+ char c = (char)nextScalar;
+ if (IsCharacterAllowed(c))
+ {
+ builder.Append(c);
+ }
+ else
+ {
+ WriteEncodedScalar(builder, (uint)nextScalar);
+ }
+ }
+ }
+
+ return builder.ToString();
+ }
+
+ // Determines whether the given character can be returned unencoded.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool IsCharacterAllowed(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ return ((_allowedCharsBitmap[index] >> offset) & 0x1U) != 0;
+ }
+
+ protected abstract void WriteEncodedScalar(StringBuilder builder, uint value);
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/UnicodeHelpers.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/UnicodeHelpers.cs
new file mode 100644
index 0000000000..89424a2612
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/UnicodeHelpers.cs
@@ -0,0 +1,228 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// Contains helpers for dealing with Unicode code points.
+ ///
+ internal unsafe static class UnicodeHelpers
+ {
+ ///
+ /// Used for invalid Unicode sequences or other unrepresentable values.
+ ///
+ private const char UNICODE_REPLACEMENT_CHAR = '\uFFFD';
+
+ ///
+ /// The last code point defined by the Unicode specification.
+ ///
+ internal const int UNICODE_LAST_CODEPOINT = 0x10FFFF;
+
+ private static uint[] _definedCharacterBitmap;
+
+ ///
+ /// Helper method which creates a bitmap of all characters which are
+ /// defined per version 7.0.0 of the Unicode specification.
+ ///
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static uint[] CreateDefinedCharacterBitmap()
+ {
+ // The stream should be exactly 8KB in size.
+ var stream = typeof(UnicodeHelpers).GetTypeInfo().Assembly.GetManifestResourceStream("compiler/resources/unicode-7.0.0-defined-characters.bin");
+ if (stream.Length != 8 * 1024)
+ {
+ Environment.FailFast("Corrupt data detected.");
+ }
+
+ // Read everything in as raw bytes.
+ byte[] rawData = new byte[8 * 1024];
+ for (int numBytesReadTotal = 0; numBytesReadTotal < rawData.Length;)
+ {
+ int numBytesReadThisIteration = stream.Read(rawData, numBytesReadTotal, rawData.Length - numBytesReadTotal);
+ if (numBytesReadThisIteration == 0)
+ {
+ Environment.FailFast("Corrupt data detected.");
+ }
+ numBytesReadTotal += numBytesReadThisIteration;
+ }
+
+ // Finally, convert the byte[] to a uint[].
+ // The incoming bytes are little-endian.
+ uint[] retVal = new uint[2 * 1024];
+ for (int i = 0; i < retVal.Length; i++)
+ {
+ retVal[i] = (((uint)rawData[4 * i + 3]) << 24)
+ | (((uint)rawData[4 * i + 2]) << 16)
+ | (((uint)rawData[4 * i + 1]) << 8)
+ | (uint)rawData[4 * i];
+ }
+
+ // And we're done!
+ Volatile.Write(ref _definedCharacterBitmap, retVal);
+ return retVal;
+ }
+
+ ///
+ /// Returns a bitmap of all characters which are defined per version 7.0.0
+ /// of the Unicode specification.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static uint[] GetDefinedCharacterBitmap()
+ {
+ return Volatile.Read(ref _definedCharacterBitmap) ?? CreateDefinedCharacterBitmap();
+ }
+
+ ///
+ /// Given a UTF-16 character stream, reads the next scalar value from the stream.
+ /// Set 'endOfString' to true if 'pChar' points to the last character in the stream.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int GetScalarValueFromUtf16(char* pChar, bool endOfString)
+ {
+ // This method is marked as AggressiveInlining to handle the common case of a non-surrogate
+ // character. The surrogate case is handled in the slower fallback code path.
+ char thisChar = *pChar;
+ return (Char.IsSurrogate(thisChar)) ? GetScalarValueFromUtf16Slow(pChar, endOfString) : thisChar;
+ }
+
+ private static int GetScalarValueFromUtf16Slow(char* pChar, bool endOfString)
+ {
+ char firstChar = pChar[0];
+
+ if (!Char.IsSurrogate(firstChar))
+ {
+ Debug.Fail("This case should've been handled by the fast path.");
+ return firstChar;
+ }
+ else if (Char.IsHighSurrogate(firstChar))
+ {
+ if (endOfString)
+ {
+ // unmatched surrogate - substitute
+ return UNICODE_REPLACEMENT_CHAR;
+ }
+ else
+ {
+ char secondChar = pChar[1];
+ if (Char.IsLowSurrogate(secondChar))
+ {
+ // valid surrogate pair - extract codepoint
+ return GetScalarValueFromUtf16SurrogatePair(firstChar, secondChar);
+ }
+ else
+ {
+ // unmatched surrogate - substitute
+ return UNICODE_REPLACEMENT_CHAR;
+ }
+ }
+ }
+ else
+ {
+ // unmatched surrogate - substitute
+ Debug.Assert(Char.IsLowSurrogate(firstChar));
+ return UNICODE_REPLACEMENT_CHAR;
+ }
+ }
+
+ private static int GetScalarValueFromUtf16SurrogatePair(char highSurrogate, char lowSurrogate)
+ {
+ Debug.Assert(Char.IsHighSurrogate(highSurrogate));
+ Debug.Assert(Char.IsLowSurrogate(lowSurrogate));
+
+ // See http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf, Table 3.5 for the
+ // details of this conversion. We don't use Char.ConvertToUtf32 because its exception
+ // handling shows up on the hot path, and our caller has already sanitized the inputs.
+ return (lowSurrogate & 0x3ff) | (((highSurrogate & 0x3ff) + (1 << 6)) << 10);
+ }
+
+ internal static void GetUtf16SurrogatePairFromAstralScalarValue(int scalar, out char highSurrogate, out char lowSurrogate)
+ {
+ Debug.Assert(0x10000 <= scalar && scalar <= UNICODE_LAST_CODEPOINT);
+
+ // See http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf, Table 3.5 for the
+ // details of this conversion. We don't use Char.ConvertFromUtf32 because its exception
+ // handling shows up on the hot path, it allocates temporary strings (which we don't want),
+ // and our caller has already sanitized the inputs.
+
+ int x = scalar & 0xFFFF;
+ int u = scalar >> 16;
+ int w = u - 1;
+ highSurrogate = (char)(0xD800 | (w << 6) | (x >> 10));
+ lowSurrogate = (char)(0xDC00 | (x & 0x3FF));
+ }
+
+ ///
+ /// Given a Unicode scalar value, returns the UTF-8 representation of the value.
+ /// The return value's bytes should be popped from the LSB.
+ ///
+ internal static int GetUtf8RepresentationForScalarValue(uint scalar)
+ {
+ Debug.Assert(scalar <= UNICODE_LAST_CODEPOINT);
+
+ // See http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf, Table 3.6 for the
+ // details of this conversion. We don't use UTF8Encoding since we're encoding
+ // a scalar code point, not a UTF16 character sequence.
+ if (scalar <= 0x7f)
+ {
+ // one byte used: scalar 00000000 0xxxxxxx -> byte sequence 0xxxxxxx
+ byte firstByte = (byte)scalar;
+ return firstByte;
+ }
+ else if (scalar <= 0x7ff)
+ {
+ // two bytes used: scalar 00000yyy yyxxxxxx -> byte sequence 110yyyyy 10xxxxxx
+ byte firstByte = (byte)(0xc0 | (scalar >> 6));
+ byte secondByteByte = (byte)(0x80 | (scalar & 0x3f));
+ return ((secondByteByte << 8) | firstByte);
+ }
+ else if (scalar <= 0xffff)
+ {
+ // three bytes used: scalar zzzzyyyy yyxxxxxx -> byte sequence 1110zzzz 10yyyyyy 10xxxxxx
+ byte firstByte = (byte)(0xe0 | (scalar >> 12));
+ byte secondByte = (byte)(0x80 | ((scalar >> 6) & 0x3f));
+ byte thirdByte = (byte)(0x80 | (scalar & 0x3f));
+ return ((((thirdByte << 8) | secondByte) << 8) | firstByte);
+ }
+ else
+ {
+ // four bytes used: scalar 000uuuuu zzzzyyyy yyxxxxxx -> byte sequence 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+ byte firstByte = (byte)(0xf0 | (scalar >> 18));
+ byte secondByte = (byte)(0x80 | ((scalar >> 12) & 0x3f));
+ byte thirdByte = (byte)(0x80 | ((scalar >> 6) & 0x3f));
+ byte fourthByte = (byte)(0x80 | (scalar & 0x3f));
+ return ((((((fourthByte << 8) | thirdByte) << 8) | secondByte) << 8) | firstByte);
+ }
+ }
+
+ ///
+ /// Returns a value stating whether a character is defined per version 7.0.0
+ /// of the Unicode specification. Certain classes of characters (control chars,
+ /// private use, surrogates, some whitespace) are considered "undefined" for
+ /// our purposes.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static bool IsCharacterDefined(char c)
+ {
+ uint codePoint = (uint)c;
+ int index = (int)(codePoint >> 5);
+ int offset = (int)(codePoint & 0x1FU);
+ return ((GetDefinedCharacterBitmap()[index] >> offset) & 0x1U) != 0;
+ }
+
+ ///
+ /// Determines whether the given scalar value is in the supplementary plane and thus
+ /// requires 2 characters to be represented in UTF-16 (as a surrogate pair).
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static bool IsSupplementaryCodePoint(int scalar)
+ {
+ return ((scalar & ~((int)Char.MaxValue)) != 0);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/Encoders/UrlEncoder.cs b/src/Microsoft.AspNet.WebUtilities/Encoders/UrlEncoder.cs
new file mode 100644
index 0000000000..81706559ff
--- /dev/null
+++ b/src/Microsoft.AspNet.WebUtilities/Encoders/UrlEncoder.cs
@@ -0,0 +1,161 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+
+namespace Microsoft.AspNet.WebUtilities.Encoders
+{
+ ///
+ /// A class which can perform URL string escaping given an allow list of characters which
+ /// can be represented unescaped.
+ ///
+ ///
+ /// Once constructed, instances of this class are thread-safe for multiple callers.
+ ///
+ public sealed class UrlEncoder : IUrlEncoder
+ {
+ // The default URL string encoder (Basic Latin), instantiated on demand
+ private static UrlEncoder _defaultEncoder;
+
+ // The inner encoder, responsible for the actual encoding routines
+ private readonly UrlUnicodeEncoder _innerUnicodeEncoder;
+
+ ///
+ /// Instantiates an encoder using the 'Basic Latin' code table as the allow list.
+ ///
+ public UrlEncoder()
+ : this(UrlUnicodeEncoder.BasicLatin)
+ {
+ }
+
+ ///
+ /// Instantiates an encoder using a custom allow list of characters.
+ ///
+ public UrlEncoder(params ICodePointFilter[] filters)
+ : this(new UrlUnicodeEncoder(filters))
+ {
+ }
+
+ private UrlEncoder(UrlUnicodeEncoder innerEncoder)
+ {
+ Debug.Assert(innerEncoder != null);
+ _innerUnicodeEncoder = innerEncoder;
+ }
+
+ ///
+ /// A default instance of the UrlEncoder, equivalent to allowing only
+ /// the 'Basic Latin' character range.
+ ///
+ public static UrlEncoder Default
+ {
+ get
+ {
+ UrlEncoder defaultEncoder = Volatile.Read(ref _defaultEncoder);
+ if (defaultEncoder == null)
+ {
+ defaultEncoder = new UrlEncoder();
+ Volatile.Write(ref _defaultEncoder, defaultEncoder);
+ }
+ return defaultEncoder;
+ }
+ }
+
+ ///
+ /// Everybody's favorite UrlEncode routine.
+ ///
+ public string UrlEncode(string value)
+ {
+ return _innerUnicodeEncoder.Encode(value);
+ }
+
+ private sealed class UrlUnicodeEncoder : UnicodeEncoderBase
+ {
+ // A singleton instance of the basic latin encoder.
+ private static UrlUnicodeEncoder _basicLatinSingleton;
+
+ // We perform UTF8 conversion of input, which means that the worst case is
+ // 9 output chars per input char: [input] U+FFFF -> [output] "%XX%YY%ZZ".
+ // We don't need to worry about astral code points since they consume 2 input
+ // chars to produce 12 output chars "%XX%YY%ZZ%WW", which is 6 output chars per input char.
+ private const int MaxOutputCharsPerInputChar = 9;
+
+ internal UrlUnicodeEncoder(ICodePointFilter[] filters)
+ : base(filters, MaxOutputCharsPerInputChar)
+ {
+ // Per RFC 3987, Sec. 2.2, we want encodings that are safe for
+ // 'isegment', 'iquery', and 'ifragment'. The only thing these
+ // all have in common is 'ipchar', which is defined as such:
+ //
+ // ipchar = iunreserved / pct-encoded / sub-delims / ":"
+ // / "@"
+ //
+ // iunreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" / ucschar
+ //
+ // ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
+ // / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
+ // / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
+ // / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
+ // / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
+ // / %xD0000-DFFFD / %xE1000-EFFFD
+ //
+ // pct-encoded = "%" HEXDIG HEXDIG
+ //
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ //
+ // From this list, the base encoder blocks "&", "'", "+",
+ // and we'll additionally block "=" since it has special meaning
+ // in x-www-form-urlencoded representations.
+ //
+ // This means that the full list of allowed characters from the
+ // Basic Latin set is:
+ // ALPHA / DIGIT / "-" / "." / "_" / "~" / "!" / "$" / "(" / ")" / "*" / "," / ";" / ":" / "@"
+
+ const string forbiddenChars = @" #%/=?[\]^`{|}"; // chars from Basic Latin which aren't already disallowed by the base encoder
+ foreach (char c in forbiddenChars)
+ {
+ ForbidCharacter(c);
+ }
+
+ // Specials (U+FFF0 .. U+FFFF) are forbidden by the definition of 'ucschar' above
+ for (int i = 0; i < 16; i++)
+ {
+ ForbidCharacter((char)(0xFFF0 | i));
+ }
+
+ // Supplementary characters are forbidden anyway by the base encoder
+ }
+
+ internal static UrlUnicodeEncoder BasicLatin
+ {
+ get
+ {
+ UrlUnicodeEncoder encoder = Volatile.Read(ref _basicLatinSingleton);
+ if (encoder == null)
+ {
+ encoder = new UrlUnicodeEncoder(new[] { CodePointFilters.BasicLatin });
+ Volatile.Write(ref _basicLatinSingleton, encoder);
+ }
+ return encoder;
+ }
+ }
+
+ // Writes a scalar value as a percent-encoded sequence of UTF8 bytes, per RFC 3987.
+ protected override void WriteEncodedScalar(StringBuilder builder, uint value)
+ {
+ uint asUtf8 = (uint)UnicodeHelpers.GetUtf8RepresentationForScalarValue(value);
+ do
+ {
+ char highNibble, lowNibble;
+ HexUtil.WriteHexEncodedByte((byte)asUtf8, out highNibble, out lowNibble);
+ builder.Append('%');
+ builder.Append(highNibble);
+ builder.Append(lowNibble);
+ } while ((asUtf8 >>= 8) != 0);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.WebUtilities/compiler/resources/unicode-7.0.0-defined-characters.bin b/src/Microsoft.AspNet.WebUtilities/compiler/resources/unicode-7.0.0-defined-characters.bin
new file mode 100644
index 0000000000..61406a9b82
Binary files /dev/null and b/src/Microsoft.AspNet.WebUtilities/compiler/resources/unicode-7.0.0-defined-characters.bin differ
diff --git a/src/Microsoft.AspNet.WebUtilities/project.json b/src/Microsoft.AspNet.WebUtilities/project.json
index e4e0e0cb08..57c6db035f 100644
--- a/src/Microsoft.AspNet.WebUtilities/project.json
+++ b/src/Microsoft.AspNet.WebUtilities/project.json
@@ -1,6 +1,9 @@
{
"version": "1.0.0-*",
"description": "ASP.NET 5 common helper methods such as URL encoding.",
+ "compilationOptions": {
+ "allowUnsafe": true
+ },
"dependencies": {
},
"frameworks": {
@@ -11,8 +14,11 @@
"System.Diagnostics.Debug": "4.0.10-beta-*",
"System.IO": "4.0.10-beta-*",
"System.IO.FileSystem": "4.0.0-beta-*",
+ "System.Linq": "4.0.0-beta-*",
+ "System.Reflection.TypeExtensions": "4.0.0-beta-*",
"System.Runtime": "4.0.20-beta-*",
- "System.Runtime.Extensions": "4.0.10-beta-*"
+ "System.Runtime.Extensions": "4.0.10-beta-*",
+ "System.Threading": "4.0.10-beta-*"
}
}
}