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-*" } } }