Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3abba328ee | |||
| 38a9d989ff | |||
| f8d468bc94 | |||
| 0d3239d700 | |||
| 84e1a40612 | |||
| 78baae7ff2 | |||
| 475e9c5e44 | |||
| 76e5b5f0ba | |||
| 2fd517a286 | |||
| 4f03ba85d9 | |||
| 95fd83cb6d | |||
| 21253a170e | |||
| ee8c1b1f6e | |||
| 2324d2c272 | |||
| b148e69ca0 | |||
| d5131ef008 | |||
| 343dc823cf | |||
| 4119824ffc | |||
| 83fb677dc2 | |||
| c895b2e627 | |||
| 694a749046 | |||
| 5c47c98b18 | |||
| 3893b22fc0 | |||
| ea1a498aff | |||
| 11f2619411 | |||
| 9c3cd4207b |
@@ -0,0 +1,19 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if DEBUG
|
||||
[assembly: AssemblyConfiguration("Debug")]
|
||||
#else
|
||||
[assembly: AssemblyConfiguration("Release")]
|
||||
#endif
|
||||
[assembly: AssemblyCompany("Fabien Barbier")]
|
||||
[assembly: AssemblyProduct(".NET Unicode Information")]
|
||||
[assembly: AssemblyCopyright("Copyright © Fabien Barbier 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,15 +1,23 @@
|
||||
.NET Unicode Information Library
|
||||
========================
|
||||
Unicode Character Inspector & .NET Unicode Information Library
|
||||
==============================================================
|
||||
|
||||
Summary
|
||||
-------
|
||||
This projects provides access to some of the data contained in the Unicode Character Database by the means of a portable .NET assembly.
|
||||
Included, is a small WPF application allowing to inspect the Unicode code points composing a specified text.
|
||||
This projects has two parts.
|
||||
One is a library, providing access to some of the data contained in the Unicode Character Database by the means of a portable .NET assembly.
|
||||
The other, is a small WPF application allowing to inspect the Unicode code points composing a specified text.
|
||||
|
||||
Using the Unicode Character Inspector application
|
||||
-------------------------------------------------
|
||||
Simply launch the application, then type or paste some text in the text box on the top of the window.
|
||||
The code points will be displayed in the list on the left side. Select one of them to display the associated information in the bottom-right pane.
|
||||

|
||||
|
||||
Compiling and using the project
|
||||
-------------------------------
|
||||
### Using the UnicodeInformation library
|
||||
Using the library is as easy as including it in your project. You will find all the good stuff in the System.Unicode namespace.
|
||||
Grab the latest version of the package on NuGet: https://www.nuget.org/packages/UnicodeInformation/.
|
||||
Once the library is installed in your project, you will find everything you need in the System.Unicode namespace.
|
||||
|
||||
Let's see a simple example:
|
||||
|
||||
@@ -56,13 +64,14 @@ This library includes a subset of the official [Unicode Character Database](http
|
||||
* Bidi_Class
|
||||
* Decomposition_Type
|
||||
* Decomposition_Mapping
|
||||
* Numeric_Type (*)
|
||||
* Numeric_Type (See also kAccountingNumeric/kOtherNumeric/kPrimaryNumeric. Those will set Numeric_Type to Numeric.)
|
||||
* Numeric_Value
|
||||
* Bidi_Mirrored
|
||||
* Unicode_1_Name
|
||||
* Simple_Uppercase_Maping
|
||||
* Simple_Lowercase_Mapping
|
||||
* Simple_Titlecase_Mapping
|
||||
* Name_Alias
|
||||
* Block
|
||||
* ASCII_Hex_Digit
|
||||
* Bidi_Control
|
||||
@@ -115,6 +124,8 @@ This library includes a subset of the official [Unicode Character Database](http
|
||||
* ID_Continue
|
||||
* XID_Start
|
||||
* XID_Continue
|
||||
* Unicode_Radical_Stroke (This is actually kRSUnicode from the Unihan database)
|
||||
* Code point cross references extracted from NamesList.txt
|
||||
|
||||
NB: The UCD property ISO_Comment will never be included since this one is empty in all new Unicode versions.
|
||||
|
||||
@@ -122,6 +133,7 @@ NB: The UCD property ISO_Comment will never be included since this one is empty
|
||||
* kAccountingNumeric
|
||||
* kOtherNumeric
|
||||
* kPrimaryNumeric
|
||||
* kRSUnicode
|
||||
* kDefinition
|
||||
* kMandarin
|
||||
* kCantonese
|
||||
|
||||
@@ -7,5 +7,9 @@
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<local:ZeroToVisibilityConverter x:Key="ZeroToVisibilityConverter" />
|
||||
<local:Utf32ToDisplayTextConverter x:Key="Utf32ToDisplayTextConverter" />
|
||||
<local:Utf32ToNameConverter x:Key="Utf32ToNameConverter" />
|
||||
<local:StringToUtf32Converter x:Key="StringToUtf32Converter" />
|
||||
<local:RadicalStrokeCountToCharConverter x:Key="RadicalStrokeCountToCharConverter" />
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
@@ -38,7 +35,7 @@ namespace UnicodeCharacterInspector
|
||||
storage = value;
|
||||
NotifyPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,12 +47,13 @@ namespace UnicodeCharacterInspector
|
||||
{
|
||||
codePoint = 0;
|
||||
characterInfo = UnicodeInfo.GetCharInfo(0);
|
||||
}
|
||||
}
|
||||
|
||||
NotifyPropertyChanged();
|
||||
UpdateDisplayText();
|
||||
NotifyPropertyChanged(nameof(CodePoint));
|
||||
NotifyPropertyChanged(nameof(Name));
|
||||
NotifyPropertyChanged(nameof(NameAliases));
|
||||
NotifyPropertyChanged(nameof(OldName));
|
||||
NotifyPropertyChanged(nameof(Definition));
|
||||
NotifyPropertyChanged(nameof(Category));
|
||||
@@ -66,6 +67,8 @@ namespace UnicodeCharacterInspector
|
||||
NotifyPropertyChanged(nameof(NumericValue));
|
||||
NotifyPropertyChanged(nameof(ContributoryProperties));
|
||||
NotifyPropertyChanged(nameof(CoreProperties));
|
||||
NotifyPropertyChanged(nameof(RadicalStrokeCounts));
|
||||
NotifyPropertyChanged(nameof(CrossReferences));
|
||||
NotifyPropertyChanged(nameof(MandarinReading));
|
||||
NotifyPropertyChanged(nameof(CantoneseReading));
|
||||
NotifyPropertyChanged(nameof(JapaneseKunReading));
|
||||
@@ -101,6 +104,11 @@ namespace UnicodeCharacterInspector
|
||||
get { return character != null ? characterInfo.Name : null; }
|
||||
}
|
||||
|
||||
public UnicodeNameAliasCollection NameAliases
|
||||
{
|
||||
get { return character != null ? characterInfo.NameAliases : new UnicodeNameAliasCollection(); }
|
||||
}
|
||||
|
||||
public string OldName
|
||||
{
|
||||
get { return character != null ? characterInfo.OldName : null; }
|
||||
@@ -166,6 +174,16 @@ namespace UnicodeCharacterInspector
|
||||
get { return character != null ? characterInfo.CoreProperties : null as CoreProperties?; }
|
||||
}
|
||||
|
||||
public UnicodeRadicalStrokeCountCollection RadicalStrokeCounts
|
||||
{
|
||||
get { return character != null ? characterInfo.UnicodeRadicalStrokeCounts : new UnicodeRadicalStrokeCountCollection(); }
|
||||
}
|
||||
|
||||
public UnicodeCrossReferenceCollection CrossReferences
|
||||
{
|
||||
get { return character != null ? characterInfo.CrossRerefences : new UnicodeCrossReferenceCollection(); }
|
||||
}
|
||||
|
||||
public string MandarinReading
|
||||
{
|
||||
get { return character != null ? characterInfo.MandarinReading : null; }
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Unicode;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
@@ -23,7 +19,7 @@ namespace UnicodeCharacterInspector
|
||||
CodePoint = codePoint;
|
||||
Character = char.ConvertFromUtf32(codePoint);
|
||||
DisplayText = UnicodeInfo.GetDisplayText(codePoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CharacterCollection : INotifyCollectionChanged, IList<CharacterViewModel>
|
||||
@@ -74,8 +70,8 @@ namespace UnicodeCharacterInspector
|
||||
|
||||
public void CopyTo(CharacterViewModel[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException("array");
|
||||
if (arrayIndex < 0) throw new ArgumentOutOfRangeException("arrayIndex");
|
||||
if (array == null) throw new ArgumentNullException(nameof(array));
|
||||
if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
if (array.Length < arrayIndex + owner.codePoints.Length) throw new ArgumentException();
|
||||
|
||||
for (int i = 0, j = arrayIndex; i < owner.codePoints.Length; ++i, ++j)
|
||||
@@ -108,7 +104,7 @@ namespace UnicodeCharacterInspector
|
||||
public CharacterInspectorViewModel()
|
||||
{
|
||||
characterCollection = new CharacterCollection(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyCollectionChanged(NotifyCollectionChangedAction action)
|
||||
{
|
||||
@@ -164,7 +160,7 @@ namespace UnicodeCharacterInspector
|
||||
NotifyPropertyChanged(nameof(SelectedCharacter));
|
||||
selectedCharacterInfo.Character = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<CharacterViewModel> Characters { get { return characterCollection; } }
|
||||
@@ -175,7 +171,7 @@ namespace UnicodeCharacterInspector
|
||||
set
|
||||
{
|
||||
if (selectedCharacterIndex < -1 || selectedCharacterIndex >= codePoints.Length)
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
if (value != selectedCharacterIndex)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<Window.DataContext>
|
||||
<local:CharacterInspectorViewModel />
|
||||
</Window.DataContext>
|
||||
<Grid Margin="10">
|
||||
<Grid Margin="10">
|
||||
<Grid.Resources>
|
||||
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource ResourceKey={x:Type Label}}">
|
||||
<Setter Property="Margin" Value="3" />
|
||||
@@ -37,7 +37,7 @@
|
||||
<ColumnDefinition Width="120" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Auto" MinLines="1" MaxLines="5" AcceptsReturn="True" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Auto" MinLines="1" MaxLines="5" AcceptsTab="True" AcceptsReturn="True" local:Placeholder.Text="Text to analyse" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ListBox Grid.Row="1" Grid.RowSpan="3" ItemsSource="{Binding Characters}" SelectedIndex="{Binding SelectedCharacterIndex}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -45,7 +45,7 @@
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" TextOptions.TextFormattingMode="Ideal" TextOptions.TextRenderingMode="Grayscale" Text="{Binding SelectedCharacterInfo.DisplayText}" FontSize="96" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" TextOptions.TextHintingMode="Fixed" TextOptions.TextFormattingMode="Ideal" TextOptions.TextRenderingMode="Grayscale" Text="{Binding SelectedCharacterInfo.DisplayText}" FontSize="96" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<ScrollViewer Grid.Row="2" Grid.Column="1" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
@@ -53,6 +53,9 @@
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Margin" Value="6" />
|
||||
</Style>
|
||||
<Style TargetType="{x:Type ItemsControl}" BasedOn="{StaticResource ResourceKey={x:Type ItemsControl}}">
|
||||
<Setter Property="Margin" Value="6" />
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width ="Auto" />
|
||||
@@ -82,6 +85,9 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CodePoint, Converter={StaticResource NullToVisibilityConverter}}" Text="Code Point" />
|
||||
@@ -90,47 +96,79 @@
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Name, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Name}" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.OldName, Converter={StaticResource NullToVisibilityConverter}}" Text="Old Name" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.OldName, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.OldName}" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Simplified Variant" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.SimplifiedVariant}" />
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Traditional Variant" />
|
||||
<TextBlock Grid.Row="4" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.TraditionalVariant}" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="Unihan Definition" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Definition}" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Mandarin Reading" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.MandarinReading}" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Cantonese Reading" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CantoneseReading}" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese Kun Reading" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseKunReading}" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese On Reading" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseOnReading}" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Korean Reading" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.KoreanReading}" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Hangul Reading" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.HangulReading}" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="Category" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Category}" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="Block" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Block}" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Canonical Combining Class" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CanonicalCombiningClass}" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Bidirectional Class" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.BidirectionalClass}" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Type" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionType}" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Mapping" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionMapping}" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericType}" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type (Unihan)" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.UnihanNumericType}" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="Numeric Value" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericValue}" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="Contributory Properties" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.ContributoryProperties}" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="Core Properties" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CoreProperties}" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NameAliases.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Aliases" />
|
||||
<ItemsControl Grid.Row="3" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NameAliases.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.NameAliases}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="WrapWithOverflow">
|
||||
<Run Text="{Binding Name, Mode=OneTime}" /> (<Run Text="{Binding Kind, Mode=OneTime}" />)
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.RadicalStrokeCounts.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Radical & Stroke Count" />
|
||||
<ItemsControl Grid.Row="4" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.RadicalStrokeCounts.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.RadicalStrokeCounts}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="WrapWithOverflow">
|
||||
Radical <Run Text="{Binding Radical, Mode=OneTime}" /> (<Run Text="{Binding Mode=OneTime, Converter={StaticResource RadicalStrokeCountToCharConverter}}" />), <Run Text="{Binding StrokeCount, Mode=OneTime}" /> strokes
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Simplified Variant" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
“<Run Text="{Binding SelectedCharacterInfo.SimplifiedVariant, Mode=OneWay}" />” U+<Run Text="{Binding SelectedCharacterInfo.SimplifiedVariant, Mode=OneWay, Converter={StaticResource StringToUtf32Converter}, StringFormat=X4}" />
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Traditional Variant" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.TraditionalVariant}" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="Unihan Definition" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Definition}" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Mandarin Reading" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.MandarinReading}" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Cantonese Reading" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CantoneseReading}" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese Kun Reading" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseKunReading}" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese On Reading" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseOnReading}" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Korean Reading" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.KoreanReading}" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Hangul Reading" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.HangulReading}" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="Category" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Category}" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="Block" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Block}" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Canonical Combining Class" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CanonicalCombiningClass}" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Bidirectional Class" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.BidirectionalClass}" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Type" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionType}" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Mapping" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionMapping}" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericType}" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type (Unihan)" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.UnihanNumericType}" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="Numeric Value" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericValue}" />
|
||||
<TextBlock Grid.Row="23" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Contributory Properties" />
|
||||
<TextBlock Grid.Row="23" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.ContributoryProperties}" />
|
||||
<TextBlock Grid.Row="24" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Core Properties" />
|
||||
<TextBlock Grid.Row="24" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CoreProperties}" />
|
||||
<TextBlock Grid.Row="25" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CrossReferences.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Cross-References" />
|
||||
<ItemsControl Grid.Row="25" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CrossReferences.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.CrossReferences}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="WrapWithOverflow">
|
||||
“<Run Text="{Binding Mode=OneTime, Converter={StaticResource Utf32ToDisplayTextConverter}}" />” U+<Run Text="{Binding Mode=OneTime, StringFormat=X4}" /> <Run Text="{Binding Mode=OneTime, Converter={StaticResource Utf32ToNameConverter}}" />
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
// Inspired by http://stackoverflow.com/questions/833943/watermark-hint-text-placeholder-textbox-in-wpf
|
||||
internal static partial class Placeholder
|
||||
{
|
||||
public static string GetText(DependencyObject obj)
|
||||
{
|
||||
return (string)obj.GetValue(TextProperty);
|
||||
}
|
||||
|
||||
public static void SetText(DependencyObject obj, string value)
|
||||
{
|
||||
obj.SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(Placeholder), new PropertyMetadata(OnTextChanged));
|
||||
|
||||
private static readonly HashSet<Control> handledControls = new HashSet<Control>();
|
||||
|
||||
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = d as TextBoxBase;
|
||||
|
||||
if (d == null) return;
|
||||
|
||||
if (e.NewValue == null || "".Equals(e.NewValue)) UnregisterControl(control);
|
||||
else UpdateControl(control, (string)e.NewValue);
|
||||
}
|
||||
|
||||
private static void OnControlLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var control = (Control)sender;
|
||||
UpdateControl(control, GetText(control));
|
||||
}
|
||||
|
||||
private static void OnTextBoxGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
|
||||
{
|
||||
var control = (Control)sender;
|
||||
RemoveAdorner(control);
|
||||
}
|
||||
|
||||
private static void UpdateControl(Control control, string placeholderText)
|
||||
{
|
||||
if (handledControls.Add(control))
|
||||
{
|
||||
RegisterControl(control);
|
||||
}
|
||||
|
||||
if (IsEmpty(control))
|
||||
{
|
||||
var adorner = GetAdorner(control) ?? AddAdorner(control);
|
||||
if (adorner != null) adorner.Text = placeholderText;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveAdorner(control);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterControl(Control control)
|
||||
{
|
||||
control.Loaded += OnControlLoaded;
|
||||
|
||||
var textBox = control as TextBoxBase;
|
||||
if (textBox != null) RegisterTextBox(textBox);
|
||||
}
|
||||
|
||||
private static void RegisterTextBox(TextBoxBase textBox)
|
||||
{
|
||||
textBox.GotKeyboardFocus += OnTextBoxGotKeyboardFocus;
|
||||
textBox.LostKeyboardFocus += OnControlLoaded;
|
||||
}
|
||||
|
||||
private static void UnregisterControl(Control control)
|
||||
{
|
||||
if (handledControls.Remove(control))
|
||||
{
|
||||
control.Loaded -= OnControlLoaded;
|
||||
|
||||
var textBox = control as TextBoxBase;
|
||||
if (textBox != null) UnregisterTextBox(textBox);
|
||||
|
||||
RemoveAdorner(control);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnregisterTextBox(TextBoxBase textBox)
|
||||
{
|
||||
textBox.GotKeyboardFocus -= OnTextBoxGotKeyboardFocus;
|
||||
textBox.LostKeyboardFocus -= OnControlLoaded;
|
||||
}
|
||||
|
||||
private static bool IsEmpty(Control control)
|
||||
{
|
||||
var textBox = control as TextBox;
|
||||
|
||||
if (textBox != null) return string.IsNullOrEmpty(textBox.Text);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static PlaceholderAdorner GetAdorner(Control control)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(control);
|
||||
|
||||
if (layer != null)
|
||||
{
|
||||
var adorners = layer.GetAdorners(control);
|
||||
|
||||
if (adorners != null)
|
||||
{
|
||||
foreach (var adorner in adorners)
|
||||
{
|
||||
var placeholder = adorner as PlaceholderAdorner;
|
||||
|
||||
if (placeholder != null) return placeholder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PlaceholderAdorner AddAdorner(Control control)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(control);
|
||||
|
||||
if (layer == null) return null;
|
||||
|
||||
var placeholder = new PlaceholderAdorner(control);
|
||||
|
||||
layer.Add(placeholder);
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
private static void RemoveAdorner(Control control)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(control);
|
||||
|
||||
if (layer == null) return;
|
||||
|
||||
var adorners = layer.GetAdorners(control);
|
||||
|
||||
if (adorners == null) return;
|
||||
|
||||
foreach (var adorner in adorners)
|
||||
{
|
||||
var placeholder = adorner as PlaceholderAdorner;
|
||||
|
||||
if (placeholder != null)
|
||||
{
|
||||
layer.Remove(placeholder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal static partial class Placeholder
|
||||
{
|
||||
private sealed class PlaceholderAdorner : Adorner
|
||||
{
|
||||
public string Text { get; set; }
|
||||
|
||||
public PlaceholderAdorner(UIElement adornedElement)
|
||||
: base(adornedElement)
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
}
|
||||
|
||||
protected override Visual GetVisualChild(int index) { throw new InvalidOperationException(); }
|
||||
|
||||
protected override int VisualChildrenCount { get { return 0; } }
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
var control = ((Control)AdornedElement);
|
||||
|
||||
Rect adornedElementRect = new Rect(AdornedElement.RenderSize);
|
||||
drawingContext.DrawText
|
||||
(
|
||||
new FormattedText
|
||||
(
|
||||
Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface
|
||||
(
|
||||
control.FontFamily,
|
||||
control.FontStyle,
|
||||
control.FontWeight,
|
||||
control.FontStretch,
|
||||
SystemFonts.MessageFontFamily
|
||||
),
|
||||
control.FontSize,
|
||||
SystemColors.GrayTextBrush
|
||||
),
|
||||
// The offsets where experimentally determined on a Windows 8.1 machine. I'm willing to accept anything better. 😉
|
||||
new Point(control.BorderThickness.Left + control.Padding.Left + 5, control.BorderThickness.Top + control.Padding.Top + 3)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,11 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeCharacterInspector")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeCharacterInspector")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
[assembly: AssemblyTitle("Unicode Character Inspector")]
|
||||
[assembly: AssemblyDescription("A character inspector for Unicode text.")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
@@ -39,17 +15,3 @@ using System.Windows;
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Unicode;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal sealed class RadicalStrokeCountToCharConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null) return null;
|
||||
|
||||
var radicalStrokeCount = (UnicodeRadicalStrokeCount)value;
|
||||
var radical = UnicodeInfo.GetCjkRadicalInfo(radicalStrokeCount.Radical);
|
||||
|
||||
return radicalStrokeCount.IsSimplified ? radical.TraditionalRadicalCodePoint : radical.SimplifiedRadicalCodePoint;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal class StringToUtf32Converter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
string text = value as string;
|
||||
|
||||
if (!string.IsNullOrEmpty(text)) return char.ConvertToUtf32(text, 0);
|
||||
else return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{04E97F21-EF04-441F-83CF-2E71F3AAB089}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
@@ -39,6 +39,12 @@
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>UnicodeCharacterInspector.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<UICulture>en-US</UICulture>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
@@ -63,6 +69,9 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="..\AssemblyInfo.Common.cs">
|
||||
<Link>Properties\AssemblyInfo.Common.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -70,6 +79,14 @@
|
||||
<Compile Include="BindableObject.cs" />
|
||||
<Compile Include="CharacterInfoViewModel.cs" />
|
||||
<Compile Include="CharacterInspectorViewModel.cs" />
|
||||
<Compile Include="Placeholder.cs" />
|
||||
<Compile Include="PlaceholderAdorner.cs">
|
||||
<DependentUpon>Placeholder.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="RadicalStrokeCountToCharConverter.cs" />
|
||||
<Compile Include="StringToUtf32Converter.cs" />
|
||||
<Compile Include="Utf32ToNameConverter.cs" />
|
||||
<Compile Include="Utf32ToDisplayTextConverter.cs" />
|
||||
<Compile Include="ZeroToVisibilityConverter.cs" />
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
@@ -93,6 +110,9 @@
|
||||
<Name>UnicodeInformation</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="UnicodeCharacterInspector.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-1036.3622)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 2.5,1.5 2,2"
|
||||
transform="translate(0,1036.3622)"
|
||||
id="path3763"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 1.5,1039.8622 5,0 c -1,2 -3,5 -5,6"
|
||||
id="path3765"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 4.5,14.5 0,-7.5 2,3.5"
|
||||
transform="translate(0,1036.3622)"
|
||||
id="path3767"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 8.5,1037.8622 0,9 5,0 0,-9 z"
|
||||
id="path3769"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 8.5,1040.8622 5,0"
|
||||
id="path3771"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 8.5,1043.8622 5,0"
|
||||
id="path3773"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 9.5,1046.8622 c 0,0 1,4 -3,4"
|
||||
id="path3775"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 11.5,1046.8622 0,2 c 0,2 0.5,2 1.5,2 1.5,0 1.5,-1 1.5,-2"
|
||||
id="path3777"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Unicode;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal sealed class Utf32ToDisplayTextConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null ? UnicodeInfo.GetDisplayText((int)value) : null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Unicode;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal sealed class Utf32ToNameConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null ? UnicodeInfo.GetName((int)value) : null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
public static void WriteUInt24(this BinaryWriter writer, int value)
|
||||
{
|
||||
if (value < 0 || value > 0xFFFFFF) throw new ArgumentOutOfRangeException("value");
|
||||
if (value < 0 || value > 0xFFFFFF) throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
writer.Write((byte)(value));
|
||||
writer.Write((byte)(value >> 8));
|
||||
@@ -27,7 +27,7 @@ namespace System.Unicode.Builder
|
||||
/// <param name="value">The value to write</param>
|
||||
public static void WriteCodePoint(this BinaryWriter writer, int value)
|
||||
{
|
||||
if (value < 0 || value > 0x40407F) throw new ArgumentOutOfRangeException("value");
|
||||
if (value < 0 || value > 0x40407F) throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
if (value < 0xA0) writer.Write((byte)value);
|
||||
else if (value < 0x20A0)
|
||||
@@ -50,5 +50,40 @@ namespace System.Unicode.Builder
|
||||
writer.Write((byte)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Writes a character name alias.</summary>
|
||||
/// <remarks>We assume that character names will not exceed 64 bytes in length.</remarks>
|
||||
/// <param name="writer">The writer to use.</param>
|
||||
/// <param name="nameAlias">The name alias value to write.</param>
|
||||
public static void WriteNameAliasToFile(this BinaryWriter writer, UnicodeNameAlias nameAlias)
|
||||
{
|
||||
writer.Write(nameAlias.Name);
|
||||
writer.Write((byte)nameAlias.Kind);
|
||||
}
|
||||
|
||||
/// <summary>Writes a character name, packing two information bits along with the length.</summary>
|
||||
/// <remarks>We assume that character names will not exceed 128 bytes in length.</remarks>
|
||||
/// <param name="writer">The writer to use.</param>
|
||||
/// <param name="name">The name to write.</param>
|
||||
public static void WriteNamePropertyToFile(this BinaryWriter writer, string name)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(name);
|
||||
if (bytes.Length > 128) throw new InvalidOperationException("Did not expect UTF-8 encoded name to be longer than 128 bytes.");
|
||||
writer.Write((byte)(name.Length - 1)); // The most significant bit will always be cleared, because it will be used for other cases.
|
||||
writer.Write(bytes);
|
||||
}
|
||||
|
||||
/// <summary>Writes a 6 bits length packed with two extra bits.</summary>
|
||||
/// <remarks>The parameters have a restricted range, which must be respected.</remarks>
|
||||
/// <param name="writer">The writer used to perform the operation.</param>
|
||||
/// <param name="extraBits">The value of the two extra bits.</param>
|
||||
/// <param name="length">The length to write.</param>
|
||||
public static void WritePackedLength(this BinaryWriter writer, byte extraBits, int length)
|
||||
{
|
||||
if (extraBits > 3) throw new ArgumentOutOfRangeException(nameof(extraBits));
|
||||
if (length < 1 || length > 64) throw new ArgumentOutOfRangeException(nameof(length));
|
||||
|
||||
writer.Write((byte)((extraBits << 6) | (length - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode.Builder
|
||||
{
|
||||
public static class CharExtensions
|
||||
{
|
||||
public static bool IsHexDigit(this char c)
|
||||
{
|
||||
return c >= '0' && c <= 'f' && (c <= '9' || c <= 'F' && c >= 'A' || c >= 'a');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace System.Unicode.Builder
|
||||
index = 0;
|
||||
}
|
||||
|
||||
var buffer = stackalloc char[36]; // From the Unicode docs, a decomposition cannot have more than 18 code points.
|
||||
var buffer = stackalloc char[36]; // From the Unicode docs, a decomposition cannot have more than 18 code points.
|
||||
int charIndex = 0;
|
||||
|
||||
while (index < s.Length && charIndex < 35)
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
this.httpClient = new HttpClient();
|
||||
this.baseUri = baseUri;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
public const string UnihanDirectoryName = "Unihan";
|
||||
public const string UnihanArchiveName = "Unihan.zip";
|
||||
public const string directoryName = "UCD";
|
||||
public const string UcdDirectoryName = "UCD";
|
||||
public const string UcdArchiveName = "UCD.zip";
|
||||
|
||||
public static readonly string[] ucdRequiredFiles = new[]
|
||||
@@ -21,8 +21,11 @@ namespace System.Unicode.Builder
|
||||
"UnicodeData.txt",
|
||||
"PropList.txt",
|
||||
"DerivedCoreProperties.txt",
|
||||
"Blocks.txt",
|
||||
"Jamo.txt",
|
||||
"CJKRadicals.txt",
|
||||
//"Jamo.txt", // Not used right now, as the hangul syllable algorithm implementation takes care of this.
|
||||
"NameAliases.txt",
|
||||
"NamesList.txt",
|
||||
"Blocks.txt",
|
||||
};
|
||||
|
||||
public static readonly string[] unihanRequiredFiles = new[]
|
||||
@@ -30,20 +33,30 @@ namespace System.Unicode.Builder
|
||||
"Unihan_NumericValues.txt",
|
||||
"Unihan_Readings.txt",
|
||||
"Unihan_Variants.txt",
|
||||
"Unihan_IRGSources.txt",
|
||||
};
|
||||
|
||||
private static HttpMessageHandler httpMessageHandler;
|
||||
|
||||
// The only purpose of this is for tests…
|
||||
internal static HttpMessageHandler HttpMessageHandler
|
||||
{
|
||||
get { return httpMessageHandler ?? (httpMessageHandler = new HttpClientHandler()); }
|
||||
set { httpMessageHandler = value != null ? value : new HttpClientHandler(); }
|
||||
}
|
||||
|
||||
private static byte[] DownloadDataArchive(string archiveName)
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
using (var httpClient = new HttpClient(HttpMessageHandler))
|
||||
{
|
||||
return httpClient.GetByteArrayAsync(HttpDataSource.UnicodeCharacterDataUri + archiveName).Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static IDataSource GetDataSource(string archiveName, string directoryName, string[] requiredFiles, bool? shouldDownload, bool? shouldSaveArchive, bool? shouldExtract)
|
||||
{
|
||||
string baseDirectory = Environment.CurrentDirectory;
|
||||
string dataDirectory = Path.Combine(baseDirectory, Program.directoryName);
|
||||
string dataDirectory = Path.Combine(baseDirectory, UcdDirectoryName);
|
||||
string dataArchiveFileName = Path.Combine(baseDirectory, archiveName);
|
||||
|
||||
if (shouldDownload != true)
|
||||
@@ -79,7 +92,7 @@ namespace System.Unicode.Builder
|
||||
return new ZipDataSource(File.OpenRead(dataArchiveFileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldDownload != false)
|
||||
{
|
||||
@@ -91,7 +104,7 @@ namespace System.Unicode.Builder
|
||||
try
|
||||
{
|
||||
stream.Write(dataArchiveData, 0, dataArchiveData.Length);
|
||||
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
|
||||
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
|
||||
|
||||
if (shouldExtract == true)
|
||||
{
|
||||
@@ -120,13 +133,13 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
UnicodeInfoBuilder data;
|
||||
|
||||
using (var ucdSource = GetDataSource(UcdArchiveName, directoryName, ucdRequiredFiles, null, null, null))
|
||||
using (var ucdSource = GetDataSource(UcdArchiveName, UcdDirectoryName, ucdRequiredFiles, null, null, null))
|
||||
using (var unihanSource = GetDataSource(UnihanArchiveName, UnihanDirectoryName, unihanRequiredFiles, null, null, null))
|
||||
{
|
||||
data = UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource).Result;
|
||||
@@ -134,6 +147,6 @@ namespace System.Unicode.Builder
|
||||
|
||||
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
|
||||
data.WriteToStream(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,8 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeInformation.Builder")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeInformation.Builder")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8dfdee6c-4f0d-4de1-b346-574cb56d2b8b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyDescription("Data file builder for the .NET Unicode Information Library.")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
@@ -10,7 +10,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
public sealed class UnicodeCharacterDataBuilder
|
||||
{
|
||||
private readonly UnicodeCharacterRange codePointRange;
|
||||
private readonly UnicodeCodePointRange codePointRange;
|
||||
private string name;
|
||||
private UnicodeCategory category = UnicodeCategory.OtherNotAssigned;
|
||||
private CanonicalCombiningClass canonicalCombiningClass;
|
||||
@@ -26,9 +26,10 @@ namespace System.Unicode.Builder
|
||||
private ContributoryProperties contributoryProperties;
|
||||
private CoreProperties coreProperties;
|
||||
|
||||
private List<int> relatedCodePoints = new List<int>();
|
||||
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
|
||||
private readonly List<int> crossRerefences = new List<int>();
|
||||
|
||||
public UnicodeCharacterRange CodePointRange { get { return codePointRange; } }
|
||||
public UnicodeCodePointRange CodePointRange { get { return codePointRange; } }
|
||||
|
||||
public string Name
|
||||
{
|
||||
@@ -36,6 +37,8 @@ namespace System.Unicode.Builder
|
||||
set { name = value; }
|
||||
}
|
||||
|
||||
public IList<UnicodeNameAlias> NameAliases { get { return nameAliases; } }
|
||||
|
||||
public UnicodeCategory Category
|
||||
{
|
||||
get { return category; }
|
||||
@@ -43,7 +46,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(UnicodeCategory), value))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
category = value;
|
||||
}
|
||||
@@ -121,14 +124,14 @@ namespace System.Unicode.Builder
|
||||
set { coreProperties = value; }
|
||||
}
|
||||
|
||||
public ICollection<int> RelatedCodePoints { get { return relatedCodePoints; } }
|
||||
public IList<int> CrossRerefences { get { return crossRerefences; } }
|
||||
|
||||
public UnicodeCharacterDataBuilder(int codePoint)
|
||||
: this(new UnicodeCharacterRange(codePoint))
|
||||
: this(new UnicodeCodePointRange(codePoint))
|
||||
{
|
||||
}
|
||||
|
||||
public UnicodeCharacterDataBuilder(UnicodeCharacterRange codePointRange)
|
||||
public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange)
|
||||
{
|
||||
this.codePointRange = codePointRange;
|
||||
this.category = UnicodeCategory.OtherNotAssigned;
|
||||
@@ -138,36 +141,40 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
return new UnicodeCharacterData
|
||||
(
|
||||
codePointRange,
|
||||
CodePointRange,
|
||||
Name,
|
||||
category,
|
||||
canonicalCombiningClass,
|
||||
bidirectionalClass,
|
||||
characterDecompositionMapping.DecompositionType,
|
||||
characterDecompositionMapping.DecompositionMapping,
|
||||
numericType,
|
||||
numericValue,
|
||||
bidirectionalMirrored,
|
||||
oldName,
|
||||
simpleUpperCaseMapping,
|
||||
simpleLowerCaseMapping,
|
||||
simpleTitleCaseMapping,
|
||||
contributoryProperties,
|
||||
coreProperties,
|
||||
relatedCodePoints.Count > 0 ? relatedCodePoints.ToArray() : null
|
||||
NameAliases.Count > 0 ? NameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
|
||||
Category,
|
||||
CanonicalCombiningClass,
|
||||
BidirectionalClass,
|
||||
CharacterDecompositionMapping.DecompositionType,
|
||||
CharacterDecompositionMapping.DecompositionMapping,
|
||||
NumericType,
|
||||
NumericValue,
|
||||
BidirectionalMirrored,
|
||||
OldName,
|
||||
SimpleUpperCaseMapping,
|
||||
SimpleLowerCaseMapping,
|
||||
SimpleTitleCaseMapping,
|
||||
ContributoryProperties,
|
||||
CoreProperties,
|
||||
CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null
|
||||
);
|
||||
}
|
||||
|
||||
internal void WriteToFile(BinaryWriter writer)
|
||||
{
|
||||
if (nameAliases.Count > 64) throw new InvalidDataException("Cannot handle more than 64 name aliases.");
|
||||
|
||||
UcdFields fields = default(UcdFields);
|
||||
|
||||
if (!codePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
|
||||
|
||||
if (name != null) fields |= UcdFields.Name;
|
||||
if (name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias.
|
||||
if (category != UnicodeCategory.OtherNotAssigned) fields |= UcdFields.Category;
|
||||
if (canonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass;
|
||||
/*if (bidirectionalClass != 0)*/fields |= UcdFields.BidirectionalClass;
|
||||
/*if (bidirectionalClass != 0)*/
|
||||
fields |= UcdFields.BidirectionalClass;
|
||||
if (characterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping;
|
||||
fields |= (UcdFields)((int)numericType << 6);
|
||||
if (bidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored;
|
||||
@@ -177,13 +184,35 @@ namespace System.Unicode.Builder
|
||||
if (simpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping;
|
||||
if (contributoryProperties != 0) fields |= UcdFields.ContributoryProperties;
|
||||
if (coreProperties != 0) fields |= UcdFields.CoreProperties;
|
||||
if (crossRerefences.Count > 0) fields |= UcdFields.CrossRerefences;
|
||||
|
||||
writer.Write((ushort)fields);
|
||||
|
||||
writer.WriteCodePoint(codePointRange.FirstCodePoint);
|
||||
if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint);
|
||||
|
||||
if ((fields & UcdFields.Name) != 0) writer.Write(name);
|
||||
if ((fields & UcdFields.Name) != 0)
|
||||
{
|
||||
// We write the names by optimizing for the common case.
|
||||
// i.e. Most characters have only one name.
|
||||
// The first 8 bit sequence will encore either the length of the name property alone,
|
||||
// or the number of aliases and a bit indicating the presence of the name property.
|
||||
|
||||
if (nameAliases.Count > 0)
|
||||
{
|
||||
writer.WritePackedLength((byte)(name != null ? 3 : 2), nameAliases.Count);
|
||||
|
||||
if (name != null)
|
||||
writer.WriteNamePropertyToFile(name);
|
||||
|
||||
foreach (var nameAlias in nameAliases)
|
||||
writer.WriteNameAliasToFile(nameAlias);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteNamePropertyToFile(name);
|
||||
}
|
||||
}
|
||||
if ((fields & UcdFields.Category) != 0) writer.Write((byte)category);
|
||||
if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)canonicalCombiningClass);
|
||||
if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)bidirectionalClass);
|
||||
@@ -203,6 +232,12 @@ namespace System.Unicode.Builder
|
||||
if ((fields & UcdFields.SimpleTitleCaseMapping) != 0) writer.Write(simpleTitleCaseMapping);
|
||||
if ((fields & UcdFields.ContributoryProperties) != 0) writer.Write((int)contributoryProperties);
|
||||
if ((fields & UcdFields.CoreProperties) != 0) writer.WriteUInt24((int)coreProperties);
|
||||
if ((fields & UcdFields.CrossRerefences) != 0)
|
||||
{
|
||||
writer.Write(checked((byte)(crossRerefences.Count - 1)));
|
||||
foreach (int crossReference in crossRerefences)
|
||||
writer.WriteCodePoint(crossReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace System.Unicode.Builder
|
||||
hasField = true;
|
||||
goto Completed;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
@@ -82,9 +82,9 @@ namespace System.Unicode.Builder
|
||||
} while (RefillBuffer());
|
||||
|
||||
hasField = false;
|
||||
Completed: ;
|
||||
Completed:;
|
||||
return hasField;
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadFieldInternal(bool trim)
|
||||
{
|
||||
@@ -121,7 +121,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
byte b = byteBuffer[index];
|
||||
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
{
|
||||
endOffset = index;
|
||||
hasField = false;
|
||||
@@ -192,7 +192,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
byte b = byteBuffer[index];
|
||||
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
{
|
||||
hasField = false;
|
||||
return true;
|
||||
|
||||
@@ -13,10 +13,14 @@ namespace System.Unicode.Builder
|
||||
public const string UnicodeDataFileName = "UnicodeData.txt";
|
||||
public const string PropListFileName = "PropList.txt";
|
||||
public const string DerivedCorePropertiesFileName = "DerivedCoreProperties.txt";
|
||||
public const string CjkRadicalsFileName = "CJKRadicals.txt";
|
||||
public const string NameAliasesFileName = "NameAliases.txt";
|
||||
public const string NamesListFileName = "NamesList.txt";
|
||||
public const string BlocksFileName = "Blocks.txt";
|
||||
public const string UnihanReadingsFileName = "Unihan_Readings.txt";
|
||||
public const string UnihanVariantsFileName = "Unihan_Variants.txt";
|
||||
public const string UnihanNumericValuesFileName = "Unihan_NumericValues.txt";
|
||||
public const string UnihanIrgSourcesFileName = "Unihan_IRGSources.txt";
|
||||
|
||||
private static string ParseSimpleCaseMapping(string mapping)
|
||||
{
|
||||
@@ -37,10 +41,14 @@ namespace System.Unicode.Builder
|
||||
await ProcessUnicodeDataFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessPropListFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessDerivedCorePropertiesFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessCjkRadicalsFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessNameAliasesFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessNamesListFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessBlocksFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanReadings(unihanSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanVariants(unihanSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanNumericValues(unihanSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanIrgSources(unihanSource, builder).ConfigureAwait(false);
|
||||
|
||||
return builder;
|
||||
}
|
||||
@@ -53,7 +61,7 @@ namespace System.Unicode.Builder
|
||||
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
var codePoint = new UnicodeCharacterRange(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
|
||||
var codePoint = new UnicodeCodePointRange(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
|
||||
|
||||
string name = reader.ReadField();
|
||||
|
||||
@@ -71,9 +79,9 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
if (rangeStartCodePoint < 0) throw new InvalidDataException("Invalid range data in UnicodeData.txt.");
|
||||
|
||||
codePoint = new UnicodeCharacterRange(rangeStartCodePoint, codePoint.LastCodePoint);
|
||||
codePoint = new UnicodeCodePointRange(rangeStartCodePoint, codePoint.LastCodePoint);
|
||||
|
||||
name = name.Substring(1, name.Length - 8).ToUpperInvariant(); // Upper-case the name in order to respect unicode naming scheme. (Spec says all names are uppercase ASCII)
|
||||
name = name.Substring(1, name.Length - 8).ToUpperInvariant(); // Upper-case the name in order to respect unicode naming scheme. (Spec says all names are uppercase ASCII)
|
||||
|
||||
rangeStartCodePoint = -1;
|
||||
}
|
||||
@@ -170,7 +178,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
ContributoryProperties property;
|
||||
|
||||
var range = UnicodeCharacterRange.Parse(reader.ReadTrimmedField());
|
||||
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
|
||||
if (EnumHelper<ContributoryProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
|
||||
{
|
||||
builder.SetProperties(property, range);
|
||||
@@ -187,7 +195,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
CoreProperties property;
|
||||
|
||||
var range = UnicodeCharacterRange.Parse(reader.ReadTrimmedField());
|
||||
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
|
||||
if (EnumHelper<CoreProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
|
||||
{
|
||||
builder.SetProperties(property, range);
|
||||
@@ -196,13 +204,167 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessCjkRadicalsFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(CjkRadicalsFileName).ConfigureAwait(false), ';'))
|
||||
{
|
||||
int lastReadRadical = 0;
|
||||
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
string radicalIndexText = reader.ReadField();
|
||||
bool isSimplified = radicalIndexText[radicalIndexText.Length - 1] == '\'';
|
||||
int radicalIndex = int.Parse(isSimplified ? radicalIndexText.Substring(0, radicalIndexText.Length - 1) : radicalIndexText);
|
||||
|
||||
if (isSimplified ? radicalIndex != lastReadRadical : lastReadRadical + 1 != (lastReadRadical = radicalIndex))
|
||||
throw new InvalidDataException("Did not expect radical number " + radicalIndexText + ".");
|
||||
|
||||
char radicalCodePoint = checked((char)int.Parse(reader.ReadTrimmedField(), NumberStyles.HexNumber));
|
||||
char characterCodePoint = checked((char)int.Parse(reader.ReadTrimmedField(), NumberStyles.HexNumber));
|
||||
|
||||
if (!isSimplified && (radicalCodePoint & 0x8000) != 0)
|
||||
throw new InvalidOperationException("Did not expect the radical code point to be higher than U+8000 for radical " + radicalIndex.ToString() + ".");
|
||||
|
||||
if (isSimplified)
|
||||
{
|
||||
builder.SetRadicalInfo(radicalIndex, UpdateRadicalData(builder.GetRadicalInfo(radicalIndex), radicalCodePoint, characterCodePoint));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.SetRadicalInfo(radicalIndex, new CjkRadicalData(radicalCodePoint, characterCodePoint));
|
||||
}
|
||||
}
|
||||
|
||||
if (lastReadRadical != UnicodeInfoBuilder.CjkRadicalCount)
|
||||
throw new InvalidOperationException("There was not enough data for the 214 CJK radicals.");
|
||||
}
|
||||
}
|
||||
|
||||
private static CjkRadicalData UpdateRadicalData(CjkRadicalData traditionalData, char simplifiedRadicalCodePoint, char simplifiedCharacterCodePoint)
|
||||
{
|
||||
return new CjkRadicalData
|
||||
(
|
||||
traditionalData.TraditionalRadicalCodePoint,
|
||||
traditionalData.TraditionalCharacterCodePoint,
|
||||
simplifiedRadicalCodePoint,
|
||||
simplifiedCharacterCodePoint
|
||||
);
|
||||
}
|
||||
|
||||
private static async Task ProcessNameAliasesFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(NameAliasesFileName).ConfigureAwait(false), ';'))
|
||||
{
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
var ucd = builder.GetUcd(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
|
||||
|
||||
string name = reader.ReadField();
|
||||
string kindName = reader.ReadField();
|
||||
UnicodeNameAliasKind kind;
|
||||
|
||||
if (!EnumHelper<UnicodeNameAliasKind>.TryGetNamedValue(kindName, out kind))
|
||||
throw new InvalidDataException("Unrecognized name alias: " + kindName + ".3");
|
||||
|
||||
ucd.NameAliases.Add(new UnicodeNameAlias(name, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessNamesListFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new StreamReader(await ucdSource.OpenDataFileAsync(NamesListFileName).ConfigureAwait(false), Encoding.UTF8, false))
|
||||
{
|
||||
string line;
|
||||
var characterData = null as UnicodeCharacterDataBuilder;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.Length == 0)
|
||||
{
|
||||
characterData = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (characterData != null && line.Length > 3 && line[0] == '\t')
|
||||
{
|
||||
if (line[1] == 'x')
|
||||
{
|
||||
// We should get at least 7 characters for a valid line: <tab> "x" <space> [0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]
|
||||
if (line.Length < 7)
|
||||
{
|
||||
characterData = null;
|
||||
continue;
|
||||
}
|
||||
if (line[2] != ' ') throw new InvalidDataException();
|
||||
|
||||
int length;
|
||||
|
||||
if (line[3].IsHexDigit())
|
||||
{
|
||||
length = line.IndexOf(' ', 3);
|
||||
if (length < 0) length = line.Length;
|
||||
length -= 3;
|
||||
|
||||
characterData.CrossRerefences.Add(int.Parse(line.Substring(3, length), NumberStyles.HexNumber));
|
||||
}
|
||||
else if (line[3] == '(')
|
||||
{
|
||||
bool hasBrackets = line[4] == '<';
|
||||
int codePointOffset = line.IndexOf(hasBrackets ? "> - " : "- ", 4);
|
||||
|
||||
if (codePointOffset < 0) throw new InvalidDataException();
|
||||
codePointOffset += hasBrackets ? 4 : 2;
|
||||
|
||||
length = line.IndexOf(')', codePointOffset);
|
||||
if (length < 0) throw new InvalidDataException();
|
||||
length -= codePointOffset;
|
||||
|
||||
characterData.CrossRerefences.Add(int.Parse(line.Substring(codePointOffset, length), NumberStyles.HexNumber));
|
||||
}
|
||||
else throw new InvalidDataException();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0].IsHexDigit())
|
||||
{
|
||||
int codePoint = int.Parse(line.Substring(0, line.IndexOf('\t')), NumberStyles.HexNumber);
|
||||
// This may return null, but for now, we will ignore code points that are not defined in UnicodeData.txt.
|
||||
characterData = builder.GetUcd(codePoint);
|
||||
// There should be no NamesList.txt entries for code points defined in a range.
|
||||
if (characterData != null && !characterData.CodePointRange.IsSingleCodePoint)
|
||||
{
|
||||
// The only exception to this rule will be when we added the "Noncharacter_Code_Point" property to a few ranges, and we will ignore those.
|
||||
if ((characterData.ContributoryProperties & ContributoryProperties.NonCharacterCodePoint) != 0)
|
||||
characterData = null;
|
||||
else
|
||||
throw new InvalidDataException("Did not expect an NamesList.txt entry for U+" + codePoint.ToString("X4") + ".");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (line[0])
|
||||
{
|
||||
case '@':
|
||||
case ';':
|
||||
case '\t':
|
||||
characterData = null;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDataException("Unrecognized data in NamesList.txt.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessBlocksFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(BlocksFileName).ConfigureAwait(false), ';'))
|
||||
{
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
builder.AddBlockEntry(new UnicodeBlock(UnicodeCharacterRange.Parse(reader.ReadField()), reader.ReadTrimmedField()));
|
||||
builder.AddBlockEntry(new UnicodeBlock(UnicodeCodePointRange.Parse(reader.ReadField()), reader.ReadTrimmedField()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,5 +489,48 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessUnihanIrgSources(IDataSource unihanDataSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnihanDataFileReader(await unihanDataSource.OpenDataFileAsync(UnihanIrgSourcesFileName).ConfigureAwait(false)))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.PropertyName)
|
||||
{
|
||||
case UnihanProperty.kRSUnicode:
|
||||
var entry = builder.GetUnihan(reader.CodePoint);
|
||||
var values = reader.PropertyValue.Split(' ');
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
bool isSimplified = false;
|
||||
int index;
|
||||
|
||||
for (int i = 0; i < value.Length; ++i)
|
||||
{
|
||||
switch (value[i])
|
||||
{
|
||||
case '\'':
|
||||
isSimplified = true;
|
||||
goto case '.';
|
||||
case '.':
|
||||
index = i;
|
||||
goto SeparatorFound;
|
||||
}
|
||||
}
|
||||
throw new InvalidDataException("Failed to decode value for kRSUnicode / Unicode_Radical_Stroke.");
|
||||
|
||||
SeparatorFound: ;
|
||||
entry.UnicodeRadicalStrokeCounts.Add(new UnicodeRadicalStrokeCount(byte.Parse(value.Substring(0, index), NumberStyles.None), byte.Parse(value.Substring(index + (isSimplified ? 2 : 1)), NumberStyles.None), isSimplified));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ignore unhandled properties for now.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,15 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
internal class UnicodeInfoBuilder
|
||||
{
|
||||
public const int CjkRadicalCount = 214; // The number of radicals (214) shouldn't change in the near future…
|
||||
|
||||
private readonly Version unicodeVersion;
|
||||
private UnicodeCharacterDataBuilder[] ucdEntries = new UnicodeCharacterDataBuilder[10000];
|
||||
private int ucdEntryCount;
|
||||
private UnihanCharacterDataBuilder[] unihanEntries = new UnihanCharacterDataBuilder[10000];
|
||||
private int unihanEntryCount;
|
||||
private List<UnicodeBlock> blockEntries = new List<UnicodeBlock>(100);
|
||||
private readonly List<UnicodeBlock> blockEntries = new List<UnicodeBlock>(100);
|
||||
private readonly CjkRadicalData[] cjkRadicals = new CjkRadicalData[CjkRadicalCount];
|
||||
|
||||
public UnicodeInfoBuilder(Version unicodeVersion)
|
||||
{
|
||||
@@ -37,7 +40,7 @@ namespace System.Unicode.Builder
|
||||
if (Δ == 0) return index;
|
||||
else if (Δ < 0) maxIndex = index - 1;
|
||||
else minIndex = index + 1;
|
||||
} while (minIndex <= maxIndex);
|
||||
} while (minIndex <= maxIndex);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -176,7 +179,7 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
public void SetProperties(ContributoryProperties property, UnicodeCharacterRange codePointRange)
|
||||
public void SetProperties(ContributoryProperties property, UnicodeCodePointRange codePointRange)
|
||||
{
|
||||
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
|
||||
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
|
||||
@@ -207,7 +210,7 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
public void SetProperties(CoreProperties property, UnicodeCharacterRange codePointRange)
|
||||
public void SetProperties(CoreProperties property, UnicodeCodePointRange codePointRange)
|
||||
{
|
||||
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
|
||||
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
|
||||
@@ -238,10 +241,24 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRadicalInfo(int radicalIndex, CjkRadicalData data)
|
||||
{
|
||||
if (radicalIndex < 1 || radicalIndex > CjkRadicalCount) throw new ArgumentOutOfRangeException(nameof(radicalIndex));
|
||||
|
||||
cjkRadicals[radicalIndex - 1] = data;
|
||||
}
|
||||
|
||||
public CjkRadicalData GetRadicalInfo(int radicalIndex)
|
||||
{
|
||||
if (radicalIndex < 1 || radicalIndex > CjkRadicalCount) throw new ArgumentOutOfRangeException(nameof(radicalIndex));
|
||||
|
||||
return cjkRadicals[radicalIndex - 1];
|
||||
}
|
||||
|
||||
public void AddBlockEntry(UnicodeBlock block)
|
||||
{
|
||||
blockEntries.Add(block);
|
||||
}
|
||||
}
|
||||
|
||||
//public UnicodeInfo ToUnicodeData()
|
||||
//{
|
||||
@@ -283,6 +300,20 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
WriteUnicodeBlockToFile(writer, blockEntries[i]);
|
||||
}
|
||||
writer.Write((byte)CjkRadicalCount);
|
||||
for (int i = 0; i < cjkRadicals.Length; ++i)
|
||||
{
|
||||
var radical = cjkRadicals[i];
|
||||
|
||||
writer.Write((ushort)(radical.HasSimplifiedForm ? 0x8000 | radical.TraditionalRadicalCodePoint : radical.TraditionalRadicalCodePoint));
|
||||
writer.Write((ushort)radical.TraditionalCharacterCodePoint);
|
||||
|
||||
if (radical.HasSimplifiedForm)
|
||||
{
|
||||
writer.Write((ushort)radical.SimplifiedRadicalCodePoint);
|
||||
writer.Write((ushort)radical.SimplifiedCharacterCodePoint);
|
||||
}
|
||||
}
|
||||
writer.WriteCodePoint(unihanEntryCount);
|
||||
for (int i = 0; i < unihanEntryCount; ++i)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{8DFDEE6C-4F0D-4DE1-B346-574CB56D2B8B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
@@ -52,7 +52,11 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\AssemblyInfo.Common.cs">
|
||||
<Link>Properties\AssemblyInfo.Common.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="BinaryWriterExtensions.cs" />
|
||||
<Compile Include="CharExtensions.cs" />
|
||||
<Compile Include="UnihanProperty.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace System.Unicode.Builder
|
||||
private string simplifiedVariant;
|
||||
private string traditionalVariant;
|
||||
|
||||
private readonly List<UnicodeRadicalStrokeCount> unicodeRadicalStrokeCounts = new List<UnicodeRadicalStrokeCount>();
|
||||
|
||||
public int CodePoint { get { return codePoint; } }
|
||||
public UnihanNumericType NumericType { get { return numericType; } set { numericType = value; } }
|
||||
public long NumericValue { get { return numericValue; } set { numericValue = value; } }
|
||||
@@ -36,6 +38,7 @@ namespace System.Unicode.Builder
|
||||
public string VietnameseReading { get { return vietnameseReading; } set { vietnameseReading = value; } }
|
||||
public string SimplifiedVariant { get { return simplifiedVariant; } set { simplifiedVariant = value; } }
|
||||
public string TraditionalVariant { get { return traditionalVariant; } set { traditionalVariant = value; } }
|
||||
public IList<UnicodeRadicalStrokeCount> UnicodeRadicalStrokeCounts { get { return unicodeRadicalStrokeCounts; } }
|
||||
|
||||
internal UnihanCharacterDataBuilder(int codePoint)
|
||||
{
|
||||
@@ -49,6 +52,7 @@ namespace System.Unicode.Builder
|
||||
codePoint,
|
||||
numericType,
|
||||
numericValue,
|
||||
unicodeRadicalStrokeCounts.ToArray(),
|
||||
definition,
|
||||
mandarinReading,
|
||||
cantoneseReading,
|
||||
@@ -67,6 +71,14 @@ namespace System.Unicode.Builder
|
||||
UnihanFields fields = default(UnihanFields);
|
||||
|
||||
fields |= (UnihanFields)NumericType;
|
||||
// For now, we have enough bits to encode the length of the array in the field specifier, so we'll do that.
|
||||
// (NB: A quick analysis of the files revealed thare there are almost always exactly one Radical/Stroke count, and occasionally two, yet never more.)
|
||||
if (unicodeRadicalStrokeCounts.Count > 0)
|
||||
{
|
||||
if (unicodeRadicalStrokeCounts.Count == 1) fields |= UnihanFields.UnicodeRadicalStrokeCount;
|
||||
else if (unicodeRadicalStrokeCounts.Count == 2) fields |= UnihanFields.UnicodeRadicalStrokeCountTwice;
|
||||
else fields |= UnihanFields.UnicodeRadicalStrokeCountMore;
|
||||
}
|
||||
if (Definition != null) fields |= UnihanFields.Definition;
|
||||
if (MandarinReading != null) fields |= UnihanFields.MandarinReading;
|
||||
if (CantoneseReading != null) fields |= UnihanFields.CantoneseReading;
|
||||
@@ -82,6 +94,19 @@ namespace System.Unicode.Builder
|
||||
|
||||
writer.WriteCodePoint(UnihanCharacterData.PackCodePoint(codePoint));
|
||||
if ((fields & UnihanFields.OtherNumeric) != 0) writer.Write(numericValue);
|
||||
|
||||
if ((fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0)
|
||||
{
|
||||
if ((fields & (UnihanFields.UnicodeRadicalStrokeCountMore)) == UnihanFields.UnicodeRadicalStrokeCountMore)
|
||||
writer.Write(checked((byte)(unicodeRadicalStrokeCounts.Count - 3)));
|
||||
|
||||
foreach (var radicalStrokeCount in unicodeRadicalStrokeCounts)
|
||||
{
|
||||
writer.Write(radicalStrokeCount.Radical);
|
||||
writer.Write((byte)(radicalStrokeCount.StrokeCount | (radicalStrokeCount.IsSimplified ? 0x80 : 0)));
|
||||
}
|
||||
}
|
||||
|
||||
if ((fields & UnihanFields.Definition) != 0) writer.Write(Definition);
|
||||
if ((fields & UnihanFields.MandarinReading) != 0) writer.Write(MandarinReading);
|
||||
if ((fields & UnihanFields.CantoneseReading) != 0) writer.Write(CantoneseReading);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace System.Unicode.Builder
|
||||
public UnihanDataFileReader(Stream stream, bool leaveOpen)
|
||||
{
|
||||
reader = new UnicodeDataFileReader(stream, '\t', leaveOpen);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace System.Unicode.Builder
|
||||
byte[] buffer;
|
||||
|
||||
return new Utf8Buffer(bufferStack.TryPop(out buffer) ? buffer : new byte[100]);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] buffer;
|
||||
private int length;
|
||||
@@ -40,16 +40,16 @@ namespace System.Unicode.Builder
|
||||
|
||||
private void EnsureExtraCapacity(int count)
|
||||
{
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("requiredExtraCapacity");
|
||||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
if (buffer.Length < checked(length + count))
|
||||
Array.Resize(ref buffer, Math.Max(length + count, buffer.Length << 1));
|
||||
}
|
||||
|
||||
public void Append(byte[] value, int startIndex, int count)
|
||||
{
|
||||
if (value == null) throw new ArgumentNullException("value");
|
||||
if (startIndex >= value.Length) throw new ArgumentOutOfRangeException("startIndex");
|
||||
if (checked(count += startIndex) > value.Length) throw new ArgumentOutOfRangeException("count");
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
if (startIndex >= value.Length) throw new ArgumentOutOfRangeException(nameof(startIndex));
|
||||
if (checked(count += startIndex) > value.Length) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
|
||||
EnsureExtraCapacity(value.Length);
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UnicodeInformation.Tests
|
||||
{
|
||||
public static class AssertEx
|
||||
{
|
||||
public static void ThrowsExactly<TException>(Action action, string methodName = null, string message = null)
|
||||
where TException : Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (TException ex)
|
||||
{
|
||||
if (ex.GetType() != typeof(TException))
|
||||
Assert.Fail(message ?? (methodName != null ? "The " + methodName + " method should throw an exception of type " : "Expected an exception of type ") + typeof(TException).Name + " but got " + ex.GetType().Name + ".");
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Fail(message ?? (methodName != null ? "The " + methodName + " method should throw an exception of type " : "Expected an exception of type ") + typeof(TException).Name + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,8 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeInformation.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeInformation.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: Guid("50337426-e884-4394-9e1a-f6f7a555f5d9")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Unicode.Builder;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Unicode.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class UnicodeDataManagerTests
|
||||
{
|
||||
private const string UcdDirectoryName = "UCD";
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
var directoryName = Path.GetFullPath(UcdDirectoryName);
|
||||
|
||||
if (!Directory.Exists(directoryName))
|
||||
{
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
string ucdFileName = Path.Combine(directoryName, "UCD.zip");
|
||||
string unihanFileName = Path.Combine(directoryName, "Unihan.zip");
|
||||
|
||||
if (!File.Exists(ucdFileName))
|
||||
{
|
||||
new WebClient().DownloadFile("http://www.unicode.org/Public/UCD/latest/ucd/UCD.zip", ucdFileName);
|
||||
ZipFile.ExtractToDirectory(ucdFileName, directoryName);
|
||||
}
|
||||
|
||||
if (!File.Exists(unihanFileName))
|
||||
{
|
||||
new WebClient().DownloadFile("http://www.unicode.org/Public/UCD/latest/ucd/Unihan.zip", unihanFileName);
|
||||
ZipFile.ExtractToDirectory(unihanFileName, directoryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BuildDataAsync()
|
||||
{
|
||||
var source = new FileDataSource(UcdDirectoryName);
|
||||
|
||||
var data = (await UnicodeDataProcessor.BuildDataAsync(source, source));
|
||||
|
||||
Assert.AreEqual((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BuildAndWriteDataAsync()
|
||||
{
|
||||
var source = new FileDataSource(UcdDirectoryName);
|
||||
|
||||
var data = await UnicodeDataProcessor.BuildDataAsync(source, source);
|
||||
|
||||
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
|
||||
{
|
||||
data.WriteToStream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[TestMethod]
|
||||
public void TestCodePointEncoding()
|
||||
{
|
||||
using (var stream = new MemoryStream(4))
|
||||
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
|
||||
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; ++i)
|
||||
{
|
||||
writer.WriteCodePoint(i);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
Assert.AreEqual(i, UnicodeInfo.ReadCodePoint(reader));
|
||||
stream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Unicode.Builder;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Unicode.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class UnicodeInfoBuilderTests
|
||||
{
|
||||
private sealed class FileHttpResponseHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly Dictionary<Uri, string> registeredFiles = new Dictionary<Uri, string>();
|
||||
|
||||
public void RegisterFile(Uri uri, string fileName)
|
||||
{
|
||||
registeredFiles.Add(uri, fileName);
|
||||
}
|
||||
|
||||
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
string fileName;
|
||||
|
||||
if (registeredFiles.TryGetValue(request.RequestUri, out fileName))
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(await Task.Run(() => File.ReadAllBytes(fileName)).ConfigureAwait(false)) };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const string HttpCacheDirectory = "_HttpCache";
|
||||
|
||||
private static async Task RegisterAndDownloadFile(FileHttpResponseHandler handler, string httpCacheDirectory, Uri baseUri, string fileName)
|
||||
{
|
||||
var uri = new Uri(baseUri, fileName);
|
||||
string path = Path.Combine(httpCacheDirectory, fileName);
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
var data = await httpClient.GetByteArrayAsync(uri).ConfigureAwait(false);
|
||||
|
||||
File.WriteAllBytes(path, data);
|
||||
}
|
||||
}
|
||||
|
||||
handler.RegisterFile(uri, path);
|
||||
}
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
var httpCacheDirectory = Path.GetFullPath(HttpCacheDirectory);
|
||||
|
||||
if (!Directory.Exists(httpCacheDirectory)) Directory.CreateDirectory(httpCacheDirectory);
|
||||
|
||||
var handler = new FileHttpResponseHandler();
|
||||
|
||||
var ucdTask = RegisterAndDownloadFile(handler, httpCacheDirectory, HttpDataSource.UnicodeCharacterDataUri, Program.UcdArchiveName);
|
||||
var unihanTask = RegisterAndDownloadFile(handler, httpCacheDirectory, HttpDataSource.UnicodeCharacterDataUri, Program.UnihanArchiveName);
|
||||
|
||||
Program.HttpMessageHandler = handler;
|
||||
|
||||
if (Directory.Exists(Program.UcdDirectoryName)) Directory.Delete(Program.UcdDirectoryName, true);
|
||||
if (File.Exists(Program.UcdArchiveName)) File.Delete(Program.UcdArchiveName);
|
||||
if (Directory.Exists(Program.UnihanDirectoryName)) Directory.Delete(Program.UnihanDirectoryName, true);
|
||||
if (File.Exists(Program.UnihanArchiveName)) File.Delete(Program.UnihanArchiveName);
|
||||
|
||||
Task.WaitAll(ucdTask, unihanTask);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DownloadUcdArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, false, false))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DownloadAndSaveUcdArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, false))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ExtractUcdArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, true))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DownloadUnihanArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, false, false))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DownloadAndSaveUnihanArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, false))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ExtractUnihanArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, true))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BuildDataAsync()
|
||||
{
|
||||
using (var ucdSource = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, null, null, null))
|
||||
using (var unihanSource = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, null, null, null))
|
||||
{
|
||||
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource));
|
||||
|
||||
Assert.AreEqual((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BuildAndWriteDataAsync()
|
||||
{
|
||||
using (var ucdSource = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, null, null, null))
|
||||
using (var unihanSource = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, null, null, null))
|
||||
{
|
||||
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource));
|
||||
|
||||
//using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
|
||||
using (var stream = File.Create("ucd.dat"))
|
||||
{
|
||||
data.WriteToStream(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[TestMethod]
|
||||
public void CodePointEncodingTest()
|
||||
{
|
||||
using (var stream = new MemoryStream(4))
|
||||
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
|
||||
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; ++i)
|
||||
{
|
||||
writer.WriteCodePoint(i);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
Assert.AreEqual(i, UnicodeInfo.ReadCodePoint(reader));
|
||||
stream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Unicode;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnicodeInformation.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class UnicodeInfoTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void CodePointEnumeratorTest()
|
||||
{
|
||||
string text = "\u0041\U0001F600\u00E9";
|
||||
|
||||
var enumerable = text.AsCodePointEnumerable();
|
||||
|
||||
Assert.AreEqual(text, enumerable.Text);
|
||||
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
|
||||
Assert.AreEqual(true, enumerator.MoveNext());
|
||||
Assert.AreEqual(0x0041, enumerator.Current);
|
||||
Assert.AreEqual(true, enumerator.MoveNext());
|
||||
Assert.AreEqual(0x1F600, enumerator.Current);
|
||||
Assert.AreEqual(true, enumerator.MoveNext());
|
||||
Assert.AreEqual(0x00E9, enumerator.Current);
|
||||
Assert.AreEqual(false, enumerator.MoveNext());
|
||||
|
||||
var genericEnumerator = ((IEnumerable<int>)enumerable).GetEnumerator();
|
||||
|
||||
Assert.AreEqual(true, genericEnumerator.MoveNext());
|
||||
Assert.AreEqual(0x0041, genericEnumerator.Current);
|
||||
Assert.AreEqual(true, genericEnumerator.MoveNext());
|
||||
Assert.AreEqual(0x1F600, genericEnumerator.Current);
|
||||
Assert.AreEqual(true, genericEnumerator.MoveNext());
|
||||
Assert.AreEqual(0x00E9, genericEnumerator.Current);
|
||||
Assert.AreEqual(false, genericEnumerator.MoveNext());
|
||||
|
||||
var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator();
|
||||
|
||||
Assert.AreEqual(true, legacyEnumerator.MoveNext());
|
||||
Assert.AreEqual(0x0041, legacyEnumerator.Current);
|
||||
Assert.AreEqual(true, legacyEnumerator.MoveNext());
|
||||
Assert.AreEqual(0x1F600, legacyEnumerator.Current);
|
||||
Assert.AreEqual(true, legacyEnumerator.MoveNext());
|
||||
Assert.AreEqual(0x00E9, legacyEnumerator.Current);
|
||||
Assert.AreEqual(false, legacyEnumerator.MoveNext());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DisplayTextTest()
|
||||
{
|
||||
for (int i = 0; i <= 0x20; ++i)
|
||||
{
|
||||
Assert.AreEqual(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(i));
|
||||
Assert.AreEqual(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(UnicodeInfo.GetCharInfo(i)));
|
||||
}
|
||||
|
||||
Assert.AreEqual("\u0041", UnicodeInfo.GetDisplayText(0x0041));
|
||||
Assert.AreEqual("\U0001F600", UnicodeInfo.GetDisplayText(0x1F600));
|
||||
Assert.AreEqual("\u00E9", UnicodeInfo.GetDisplayText(0x00E9));
|
||||
}
|
||||
|
||||
private static void AssertChar(int codePoint, UnicodeCategory category, string name, string block)
|
||||
{
|
||||
AssertChar(codePoint, category, UnicodeNumericType.None, null, name, block);
|
||||
}
|
||||
|
||||
private static void AssertChar(int codePoint, UnicodeCategory category, UnicodeNumericType numericType, UnicodeRationalNumber? numericValue, string name, string block)
|
||||
{
|
||||
var info = UnicodeInfo.GetCharInfo(codePoint);
|
||||
Assert.AreEqual(codePoint, info.CodePoint);
|
||||
Assert.AreEqual(category, info.Category);
|
||||
Assert.AreEqual(numericType, info.NumericType);
|
||||
Assert.AreEqual(numericValue, info.NumericValue);
|
||||
Assert.AreEqual(name, info.Name);
|
||||
Assert.AreEqual(block, UnicodeInfo.GetBlockName(codePoint));
|
||||
Assert.AreEqual(block, info.Block);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CharacterInfoTest()
|
||||
{
|
||||
AssertChar(0x0030, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(0), "DIGIT ZERO", "Basic Latin");
|
||||
AssertChar(0x0031, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(1), "DIGIT ONE", "Basic Latin");
|
||||
AssertChar(0x0032, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(2), "DIGIT TWO", "Basic Latin");
|
||||
AssertChar(0x0035, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(5), "DIGIT FIVE", "Basic Latin");
|
||||
AssertChar(0x0039, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(9), "DIGIT NINE", "Basic Latin");
|
||||
AssertChar(0x0041, UnicodeCategory.UppercaseLetter, "LATIN CAPITAL LETTER A", "Basic Latin");
|
||||
AssertChar(0x1F600, UnicodeCategory.OtherSymbol, "GRINNING FACE", "Emoticons");
|
||||
AssertChar(0x00E9, UnicodeCategory.LowercaseLetter, "LATIN SMALL LETTER E WITH ACUTE", "Latin-1 Supplement");
|
||||
AssertChar(0xD4DB, UnicodeCategory.OtherLetter, "HANGUL SYLLABLE PWILH", "Hangul Syllables");
|
||||
AssertChar(0x1F574, UnicodeCategory.OtherSymbol, "MAN IN BUSINESS SUIT LEVITATING", "Miscellaneous Symbols and Pictographs");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RationalNumberTest()
|
||||
{
|
||||
Assert.AreEqual(true, default(UnicodeRationalNumber).IsDefaultValue);
|
||||
Assert.AreEqual("1", new UnicodeRationalNumber(1).ToString());
|
||||
Assert.AreEqual("1", new UnicodeRationalNumber(1, 1).ToString());
|
||||
Assert.AreEqual(new UnicodeRationalNumber(1), new UnicodeRationalNumber(1, 1));
|
||||
Assert.AreEqual("1/100", new UnicodeRationalNumber(1, 100).ToString());
|
||||
Assert.AreEqual("-20/7", new UnicodeRationalNumber(-20, 7).ToString());
|
||||
Assert.AreEqual("-5", new UnicodeRationalNumber(-5).ToString());
|
||||
Assert.AreEqual(long.MaxValue.ToString(), new UnicodeRationalNumber(long.MaxValue).ToString());
|
||||
Assert.AreEqual(long.MaxValue.ToString() + "/" + byte.MaxValue.ToString(), new UnicodeRationalNumber(long.MaxValue, byte.MaxValue).ToString());
|
||||
Assert.AreEqual(string.Empty, default(UnicodeRationalNumber).ToString());
|
||||
|
||||
Assert.AreEqual(new UnicodeRationalNumber(0), UnicodeRationalNumber.Parse("0"));
|
||||
Assert.AreEqual(new UnicodeRationalNumber(1), UnicodeRationalNumber.Parse("1"));
|
||||
Assert.AreEqual(new UnicodeRationalNumber(1), UnicodeRationalNumber.Parse("1/1"));
|
||||
Assert.AreEqual(new UnicodeRationalNumber(1, 10), UnicodeRationalNumber.Parse("1/10"));
|
||||
Assert.AreNotEqual(new UnicodeRationalNumber(2, 10), UnicodeRationalNumber.Parse("1/10"));
|
||||
Assert.AreNotEqual(new UnicodeRationalNumber(1, 20), UnicodeRationalNumber.Parse("1/10"));
|
||||
Assert.AreNotEqual(new UnicodeRationalNumber(2, 2), new UnicodeRationalNumber(1, 1));
|
||||
|
||||
AssertEx.ThrowsExactly<ArgumentNullException>(() => UnicodeRationalNumber.Parse(null), "UnicodeRationalNumber.Parse");
|
||||
AssertEx.ThrowsExactly<ArgumentException>(() => UnicodeRationalNumber.Parse(string.Empty), "UnicodeRationalNumber.Parse");
|
||||
|
||||
var numbers = new[]
|
||||
{
|
||||
default(UnicodeRationalNumber),
|
||||
new UnicodeRationalNumber(0),
|
||||
new UnicodeRationalNumber(1),
|
||||
new UnicodeRationalNumber(1, 10),
|
||||
new UnicodeRationalNumber(1, 100),
|
||||
new UnicodeRationalNumber(10),
|
||||
new UnicodeRationalNumber(100),
|
||||
new UnicodeRationalNumber(1000),
|
||||
new UnicodeRationalNumber(1000000),
|
||||
new UnicodeRationalNumber(1000000000),
|
||||
new UnicodeRationalNumber(1000000000000),
|
||||
};
|
||||
|
||||
var hashSet = new HashSet<UnicodeRationalNumber>();
|
||||
|
||||
// Verify that all numbers are unique
|
||||
foreach (var number in numbers)
|
||||
Assert.AreEqual(true, hashSet.Add(number));
|
||||
|
||||
// Verify that all numbers are already in the list
|
||||
foreach (var number in numbers)
|
||||
Assert.AreEqual(false, hashSet.Add(number));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void HangulNameTest()
|
||||
{
|
||||
#if DEBUG
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName('\0'));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName('\uABFF'));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName('\uD7A5'));
|
||||
#endif
|
||||
Assert.AreEqual("HANGUL SYLLABLE PWILH", UnicodeInfo.GetName(0xD4DB));
|
||||
Assert.AreEqual("HANGUL SYLLABLE PWAENG", UnicodeInfo.GetName(0xD439));
|
||||
Assert.AreEqual("HANGUL SYLLABLE PANJ", UnicodeInfo.GetName(0xD311));
|
||||
Assert.AreEqual("HANGUL SYLLABLE TOLM", UnicodeInfo.GetName(0xD1AA));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void BlockNameTest()
|
||||
{
|
||||
Assert.AreEqual("Basic Latin", UnicodeInfo.GetBlockName(0x0041));
|
||||
Assert.AreEqual("Miscellaneous Technical", UnicodeInfo.GetBlockName(0x2307));
|
||||
Assert.AreEqual("Hangul Syllables", UnicodeInfo.GetBlockName(0xD311));
|
||||
Assert.AreEqual("Miscellaneous Symbols and Pictographs", UnicodeInfo.GetBlockName(0x1F574));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RadicalStrokeCountTest()
|
||||
{
|
||||
var char5E7A = UnicodeInfo.GetCharInfo(0x5E7A);
|
||||
|
||||
Assert.AreNotEqual(0, char5E7A.UnicodeRadicalStrokeCounts);
|
||||
Assert.AreEqual(false, char5E7A.UnicodeRadicalStrokeCounts[0].IsSimplified);
|
||||
Assert.AreEqual(char5E7A.UnicodeRadicalStrokeCounts[0].Radical, 52);
|
||||
Assert.AreEqual(char5E7A.UnicodeRadicalStrokeCounts[0].StrokeCount, 0);
|
||||
|
||||
var char2A6D6 = UnicodeInfo.GetCharInfo(0x2A6D6);
|
||||
|
||||
Assert.AreNotEqual(0, char2A6D6.UnicodeRadicalStrokeCounts);
|
||||
Assert.AreEqual(false, char2A6D6.UnicodeRadicalStrokeCounts[0].IsSimplified);
|
||||
Assert.AreEqual(char2A6D6.UnicodeRadicalStrokeCounts[0].Radical, 214);
|
||||
Assert.AreEqual(char2A6D6.UnicodeRadicalStrokeCounts[0].StrokeCount, 20);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RadicalInfoTest()
|
||||
{
|
||||
var radical1 = UnicodeInfo.GetCjkRadicalInfo(1);
|
||||
|
||||
Assert.AreEqual(false, radical1.HasSimplifiedForm);
|
||||
Assert.AreEqual(1, radical1.RadicalIndex);
|
||||
Assert.AreEqual('\u2F00', radical1.TraditionalRadicalCodePoint);
|
||||
Assert.AreEqual('\u4E00', radical1.TraditionalCharacterCodePoint);
|
||||
Assert.AreEqual('\u2F00', radical1.SimplifiedRadicalCodePoint);
|
||||
Assert.AreEqual('\u4E00', radical1.SimplifiedCharacterCodePoint);
|
||||
|
||||
var radical214 = UnicodeInfo.GetCjkRadicalInfo(214);
|
||||
|
||||
Assert.AreEqual(false, radical214.HasSimplifiedForm);
|
||||
Assert.AreEqual(214, radical214.RadicalIndex);
|
||||
Assert.AreEqual('\u2FD5', radical214.TraditionalRadicalCodePoint);
|
||||
Assert.AreEqual('\u9FA0', radical214.TraditionalCharacterCodePoint);
|
||||
Assert.AreEqual('\u2FD5', radical214.SimplifiedRadicalCodePoint);
|
||||
Assert.AreEqual('\u9FA0', radical214.SimplifiedCharacterCodePoint);
|
||||
|
||||
AssertEx.ThrowsExactly<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(0), nameof(UnicodeInfo.GetCjkRadicalInfo));
|
||||
AssertEx.ThrowsExactly<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(215), nameof(UnicodeInfo.GetCjkRadicalInfo));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CodePointRangeTest()
|
||||
{
|
||||
var fullRange = new UnicodeCodePointRange(0, 0x10FFFF);
|
||||
|
||||
Assert.AreEqual(0, fullRange.FirstCodePoint);
|
||||
Assert.AreEqual(0x10FFFF, fullRange.LastCodePoint);
|
||||
Assert.AreEqual(false, fullRange.IsSingleCodePoint);
|
||||
|
||||
var letterA = new UnicodeCodePointRange('A');
|
||||
|
||||
Assert.AreEqual('A', letterA.FirstCodePoint);
|
||||
Assert.AreEqual('A', letterA.LastCodePoint);
|
||||
Assert.AreEqual(true, letterA.IsSingleCodePoint);
|
||||
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(-1));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(0x110000));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(int.MaxValue));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(-1, 10));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(10, 0x110000));
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(-1, 0x110000));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CodePointRangeEnumerationTest()
|
||||
{
|
||||
const int start = 0xA3F;
|
||||
const int end = 0x105F;
|
||||
|
||||
// Generic test
|
||||
{
|
||||
int i = start;
|
||||
|
||||
foreach (int n in new UnicodeCodePointRange(start, end))
|
||||
{
|
||||
Assert.AreEqual(i++, n);
|
||||
}
|
||||
}
|
||||
|
||||
// Nongeneric test
|
||||
{
|
||||
int i = start;
|
||||
|
||||
var enumerator = (IEnumerator)new UnicodeCodePointRange(start, end).GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
Assert.AreEqual(i++, enumerator.Current);
|
||||
}
|
||||
|
||||
enumerator.Reset();
|
||||
|
||||
Assert.AreEqual(true, enumerator.MoveNext());
|
||||
Assert.AreEqual(start, enumerator.Current);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[TestMethod]
|
||||
public void UnihanCodePointPackingTest()
|
||||
{
|
||||
for (int i = 0x3400; i < 0x4E00; ++i)
|
||||
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0x4E00; i < 0xA000; ++i)
|
||||
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0xF900; i < 0xFB00; ++i)
|
||||
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0x20000; i < 0x2F800; ++i)
|
||||
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0x2F800; i < 0x30000; ++i)
|
||||
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
|
||||
const string packCodePointErrorMessage = "The PackCodePoint method should fail for code points outside of the valid range.";
|
||||
const string unpackCodePointErrorMessage = "The PackCodePoint method should fail for values outside of the valid range.";
|
||||
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0xA000), nameof(UnihanCharacterData.PackCodePoint), packCodePointErrorMessage);
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0xFB00), nameof(UnihanCharacterData.PackCodePoint), packCodePointErrorMessage);
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0x30000), nameof(UnihanCharacterData.PackCodePoint), packCodePointErrorMessage);
|
||||
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.UnpackCodePoint(-1), nameof(UnihanCharacterData.UnpackCodePoint), unpackCodePointErrorMessage);
|
||||
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.UnpackCodePoint(0x20000), nameof(UnihanCharacterData.UnpackCodePoint), unpackCodePointErrorMessage);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{50337426-E884-4394-9E1A-F6F7A555F5D9}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
@@ -60,8 +60,13 @@
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="UnicodeDataManagerTests.cs" />
|
||||
<Compile Include="..\AssemblyInfo.Common.cs">
|
||||
<Link>Properties\AssemblyInfo.Common.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="AssertEx.cs" />
|
||||
<Compile Include="UnicodeInfoBuilderTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UnicodeInfoTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UnicodeInformation.Builder\UnicodeInformation.Builder.csproj">
|
||||
|
||||
@@ -13,12 +13,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeInformation.Builder"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{73097DF3-04B7-4C5F-B4EA-0EB800E40702}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
AssemblyInfo.Common.cs = AssemblyInfo.Common.cs
|
||||
Example.cs = Example.cs
|
||||
LICENSE.txt = LICENSE.txt
|
||||
README.md = README.md
|
||||
System.Unicode.snk = System.Unicode.snk
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{311FC325-8547-4806-8617-956F1356A92C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
docs\uci-00.png = docs\uci-00.png
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace System.Unicode
|
||||
[ValueName("CS"), ValueName("Common_Separator"), Display(Name = "Common_Separator", Description = "commas, colons, and slashes")]
|
||||
CommonSeparator,
|
||||
[ValueName("NSM"), ValueName("Nonspacing_Mark"), Display(Name = "Nonspacing_Mark", Description = "any nonspacing mark")]
|
||||
NonspacingMark,
|
||||
NonSpacingMark,
|
||||
[ValueName("BN"), ValueName("Boundary_Neutral"), Display(Name = "Boundary_Neutral", Description = "most format characters, control codes, or noncharacters")]
|
||||
BoundaryNeutral,
|
||||
[ValueName("B"), ValueName("Paragraph_Separator"), Display(Name = "Paragraph_Separator", Description = "various newline characters")]
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace System.Unicode
|
||||
{
|
||||
internal struct CjkRadicalData
|
||||
{
|
||||
public readonly char TraditionalRadicalCodePoint;
|
||||
public readonly char TraditionalCharacterCodePoint;
|
||||
public readonly char SimplifiedRadicalCodePoint;
|
||||
public readonly char SimplifiedCharacterCodePoint;
|
||||
|
||||
internal CjkRadicalData(char radicalCodePoint, char characterCodePoint)
|
||||
{
|
||||
TraditionalRadicalCodePoint = radicalCodePoint;
|
||||
TraditionalCharacterCodePoint = characterCodePoint;
|
||||
SimplifiedRadicalCodePoint = radicalCodePoint;
|
||||
SimplifiedCharacterCodePoint = characterCodePoint;
|
||||
}
|
||||
|
||||
internal CjkRadicalData(char traditionalRadicalCodePoint, char traditionalCharacterCodePoint, char simplifiedRadicalCodePoint, char simplifiedCharacterCodePoint)
|
||||
{
|
||||
TraditionalRadicalCodePoint = traditionalRadicalCodePoint;
|
||||
TraditionalCharacterCodePoint = traditionalCharacterCodePoint;
|
||||
SimplifiedRadicalCodePoint = simplifiedCharacterCodePoint;
|
||||
SimplifiedCharacterCodePoint = simplifiedCharacterCodePoint;
|
||||
}
|
||||
|
||||
public bool HasSimplifiedForm { get { return SimplifiedRadicalCodePoint != TraditionalRadicalCodePoint || SimplifiedCharacterCodePoint != TraditionalCharacterCodePoint; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct CjkRadicalInfo
|
||||
{
|
||||
private readonly byte radicalIndex;
|
||||
private readonly CjkRadicalData radicalData;
|
||||
|
||||
public byte RadicalIndex { get { return radicalIndex; } }
|
||||
|
||||
public char TraditionalRadicalCodePoint { get { return radicalData.TraditionalRadicalCodePoint; } }
|
||||
public char TraditionalCharacterCodePoint { get { return radicalData.TraditionalCharacterCodePoint; } }
|
||||
public char SimplifiedRadicalCodePoint { get { return radicalData.SimplifiedRadicalCodePoint; } }
|
||||
public char SimplifiedCharacterCodePoint { get { return radicalData.SimplifiedCharacterCodePoint; } }
|
||||
|
||||
public bool HasSimplifiedForm { get { return radicalData.HasSimplifiedForm; } }
|
||||
|
||||
internal CjkRadicalInfo(byte radicalIndex, CjkRadicalData radicalData)
|
||||
{
|
||||
this.radicalIndex = radicalIndex;
|
||||
this.radicalData = radicalData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace System.Unicode
|
||||
|
||||
public CodePointEnumerator(string text)
|
||||
{
|
||||
if (text == null) throw new ArgumentNullException("text");
|
||||
if (text == null) throw new ArgumentNullException(nameof(text));
|
||||
|
||||
this.text = text;
|
||||
this.current = 0;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace System.Unicode
|
||||
public enum CompatibilityFormattingTag : byte
|
||||
{
|
||||
Canonical = 0,
|
||||
[ValueName("font"), Display(Name = "font", Description = "Font variant (for example, a blackletter form)")]
|
||||
[ValueName("font"), Display(Name = "font", Description = "Font variant (for example, a blackletter form)")]
|
||||
Font,
|
||||
[ValueName("noBreak"), Display(Name = "noBreak", Description = "No-break version of a space or hyphen")]
|
||||
NoBreak,
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace System.Unicode
|
||||
where attr.Name != null
|
||||
select new KeyValuePair<string, T>(attr.Name, (T)field.GetValue(null))
|
||||
).ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetNamedValue(string name, out T value)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
internal static class HangulInfo
|
||||
{
|
||||
// Constants defined on page 144 of the Unicode 7.0 Standard (3.12)
|
||||
private const ushort SBase = 0xAC00;
|
||||
private const ushort LBase = 0x1100;
|
||||
private const ushort VBase = 0x1161;
|
||||
private const ushort TBase = 0x11A7;
|
||||
private const int LCount = 19;
|
||||
private const int VCount = 21;
|
||||
private const int TCount = 28;
|
||||
private const int NCount = VCount * TCount;
|
||||
private const int SCount = LCount * NCount;
|
||||
|
||||
private static readonly string[] JamoLTable =
|
||||
{
|
||||
"G", "GG", "N", "D", "DD", "R", "M", "B", "BB",
|
||||
"S", "SS", "", "J", "JJ", "C", "K", "T", "P", "H"
|
||||
};
|
||||
|
||||
private static readonly string[] JamoVTable =
|
||||
{
|
||||
"A", "AE", "YA", "YAE", "EO", "E", "YEO", "YE", "O",
|
||||
"WA", "WAE", "OE", "YO", "U", "WEO", "WE", "WI",
|
||||
"YU", "EU", "YI", "I"
|
||||
};
|
||||
|
||||
private static readonly string[] JamoTTable =
|
||||
{
|
||||
"", "G", "GG", "GS", "N", "NJ", "NH", "D", "L", "LG", "LM",
|
||||
"LB", "LS", "LT", "LP", "LH", "M", "B", "BS",
|
||||
"S", "SS", "NG", "J", "C", "K", "T", "P", "H"
|
||||
};
|
||||
|
||||
// Algorithm defined on page 150 of the Unicode 7.0 Standard (3.12)
|
||||
internal static string GetHangulName(char codePoint)
|
||||
{
|
||||
int sIndex = codePoint - SBase;
|
||||
|
||||
if (sIndex < 0 || sIndex >= SCount) throw new ArgumentOutOfRangeException(nameof(codePoint));
|
||||
|
||||
int lIndex = sIndex / NCount;
|
||||
int vIndex = (sIndex % NCount) / TCount;
|
||||
int tIndex = sIndex % TCount;
|
||||
|
||||
return "HANGUL SYLLABLE " + JamoLTable[lIndex] + JamoVTable[vIndex] + JamoTTable[tIndex];
|
||||
}
|
||||
|
||||
internal static bool IsHangul(int codePoint)
|
||||
{
|
||||
return codePoint >= SBase && codePoint <= SBase + SCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,11 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeInformation")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeInformation")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: AssemblyTitle(".NET Unicode Information Library")]
|
||||
[assembly: AssemblyDescription("Library providing access to Unicode data to .NET clients.")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Builder, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
#if DEBUG
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
#endif
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace System.Unicode
|
||||
internal enum UcdFields : ushort
|
||||
{
|
||||
// Not really a field, just here to indicate that the entry is a range
|
||||
CodePointRange = 1,
|
||||
|
||||
Name = 2,
|
||||
CodePointRange = 1,
|
||||
|
||||
Name = 2, // Will stand in for official name as well as related names.
|
||||
Category = 4,
|
||||
CanonicalCombiningClass = 8,
|
||||
BidirectionalClass = 16,
|
||||
@@ -23,7 +23,7 @@ namespace System.Unicode
|
||||
// NumericType / NumericValue : Not exactly a bit mask here… More like [0…3] << 6
|
||||
NumericDecimal = 64,
|
||||
NumericDigit = 128,
|
||||
NumericNumeric = 192,
|
||||
NumericNumeric = 192,
|
||||
|
||||
// This is a yes/no field, so obviously, no extra storage is required for this one…
|
||||
BidirectionalMirrored = 256,
|
||||
@@ -35,5 +35,7 @@ namespace System.Unicode
|
||||
|
||||
ContributoryProperties = 8192,
|
||||
CoreProperties = 16384,
|
||||
|
||||
CrossRerefences = 32768,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeBlock
|
||||
{
|
||||
public readonly UnicodeCharacterRange CodePointRange;
|
||||
public readonly UnicodeCodePointRange CodePointRange;
|
||||
public readonly string Name;
|
||||
|
||||
internal UnicodeBlock(UnicodeCharacterRange codePointRange, string name)
|
||||
internal UnicodeBlock(UnicodeCodePointRange codePointRange, string name)
|
||||
{
|
||||
this.CodePointRange = codePointRange;
|
||||
this.Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +50,10 @@ namespace System.Unicode
|
||||
{
|
||||
var dictionary = new Dictionary<string, UnicodeCategory>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var info in categories)
|
||||
foreach (var info in categories)
|
||||
{
|
||||
dictionary.Add(info.ShortName, info.Category);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ namespace System.Unicode
|
||||
public static UnicodeCategoryInfo Get(UnicodeCategory category)
|
||||
{
|
||||
return categories[(int)category];
|
||||
}
|
||||
}
|
||||
|
||||
public static UnicodeCategoryInfo FromShortName(string name)
|
||||
{
|
||||
|
||||
@@ -10,54 +10,77 @@ namespace System.Unicode
|
||||
public struct UnicodeCharInfo
|
||||
{
|
||||
private readonly int codePoint;
|
||||
private readonly string name;
|
||||
private readonly UnicodeCharacterData unicodeCharacterData;
|
||||
private readonly UnihanCharacterData unihanCharacterData;
|
||||
private readonly string block;
|
||||
|
||||
public int CodePoint { get { return codePoint; } }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return unicodeCharacterData.Name == null || unicodeCharacterData.CodePointRange.IsSingleCodePoint ?
|
||||
unicodeCharacterData.Name :
|
||||
unicodeCharacterData.Name + "-" + codePoint.ToString("X4");
|
||||
}
|
||||
}
|
||||
[ValueName("Name"), ValueName("na")]
|
||||
public string Name { get { return name; } }
|
||||
[ValueName("Name_Alias")]
|
||||
public UnicodeNameAliasCollection NameAliases { get { return new UnicodeNameAliasCollection(unicodeCharacterData?.NameAliases); } }
|
||||
|
||||
public UnicodeCategory Category { get { return unicodeCharacterData != null ? unicodeCharacterData.Category : UnicodeCategory.OtherNotAssigned; } }
|
||||
public string Block { get { return block ?? "No_Block"; } }
|
||||
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData.CanonicalCombiningClass; } }
|
||||
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData.BidirectionalClass; } }
|
||||
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData.DecompositionType; } }
|
||||
public string DecompositionMapping { get { return unicodeCharacterData.DecompositionMapping; } }
|
||||
public UnicodeNumericType NumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : unicodeCharacterData.NumericType; } }
|
||||
[ValueName("General_Category"), ValueName("gc")]
|
||||
public UnicodeCategory Category { get { return unicodeCharacterData?.Category ?? UnicodeCategory.OtherNotAssigned; } }
|
||||
[ValueName("Block"), ValueName("blk")]
|
||||
public string Block { get { return block ?? UnicodeInfo.DefaultBlock; } }
|
||||
[ValueName("Canonical_Combining_Class"), ValueName("ccc")]
|
||||
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData?.CanonicalCombiningClass ?? CanonicalCombiningClass.NotReordered; } }
|
||||
[ValueName("Bidi_Class"), ValueName("bc")]
|
||||
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData?.BidirectionalClass ?? BidirectionalClass.LeftToRight; } }
|
||||
[ValueName("Decomposition_Type"), ValueName("dt")]
|
||||
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData?.DecompositionType ?? CompatibilityFormattingTag.Canonical; } }
|
||||
[ValueName("Decomposition_Mapping"), ValueName("dm")]
|
||||
public string DecompositionMapping { get { return unicodeCharacterData?.DecompositionMapping; } }
|
||||
[ValueName("Numeric_Type"), ValueName("nt")]
|
||||
public UnicodeNumericType NumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : unicodeCharacterData?.NumericType ?? UnicodeNumericType.None; } }
|
||||
public UnihanNumericType UnihanNumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType : UnihanNumericType.None; } }
|
||||
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData.NumericValue; } }
|
||||
public bool BidirectionalMirrored { get { return unicodeCharacterData.BidirectionalMirrored; } }
|
||||
public string OldName { get { return unicodeCharacterData.OldName; } }
|
||||
public string SimpleUpperCaseMapping { get { return unicodeCharacterData.SimpleUpperCaseMapping; } }
|
||||
public string SimpleLowerCaseMapping { get { return unicodeCharacterData.SimpleLowerCaseMapping; } }
|
||||
public string SimpleTitleCaseMapping { get { return unicodeCharacterData.SimpleTitleCaseMapping; } }
|
||||
public ContributoryProperties ContributoryProperties { get { return unicodeCharacterData.ContributoryProperties; } }
|
||||
public CoreProperties CoreProperties { get { return unicodeCharacterData.CoreProperties; } }
|
||||
[ValueName("Numeric_Value"), ValueName("nv")]
|
||||
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData?.NumericValue; } }
|
||||
[ValueName("Bidi_Mirrored")]
|
||||
public bool BidirectionalMirrored { get { return unicodeCharacterData?.BidirectionalMirrored ?? false; } }
|
||||
[ValueName("Unicode_1_Name"), ValueName("na1")]
|
||||
public string OldName { get { return unicodeCharacterData?.OldName; } }
|
||||
[ValueName("Simple_Uppercase_Mapping"), ValueName("suc")]
|
||||
public string SimpleUpperCaseMapping { get { return unicodeCharacterData?.SimpleUpperCaseMapping; } }
|
||||
[ValueName("Simple_Lowercase_Mapping"), ValueName("slc")]
|
||||
public string SimpleLowerCaseMapping { get { return unicodeCharacterData?.SimpleLowerCaseMapping; } }
|
||||
[ValueName("Simple_Titlecase_Mapping"), ValueName("stc")]
|
||||
public string SimpleTitleCaseMapping { get { return unicodeCharacterData?.SimpleTitleCaseMapping; } }
|
||||
public ContributoryProperties ContributoryProperties { get { return unicodeCharacterData?.ContributoryProperties ?? 0; } }
|
||||
public CoreProperties CoreProperties { get { return unicodeCharacterData?.CoreProperties ?? 0; } }
|
||||
public UnicodeCrossReferenceCollection CrossRerefences { get { return new UnicodeCrossReferenceCollection(unicodeCharacterData?.CrossRerefences); } }
|
||||
[ValueName("kRSUnicode"), ValueName("cjkRSUnicode"), ValueName("Unicode_Radical_Stroke"), ValueName("URS")]
|
||||
public UnicodeRadicalStrokeCountCollection UnicodeRadicalStrokeCounts { get { return new UnicodeRadicalStrokeCountCollection(unihanCharacterData?.UnicodeRadicalStrokeCounts); } }
|
||||
|
||||
[ValueName("kDefinition")]
|
||||
public string Definition { get { return unihanCharacterData?.Definition; } }
|
||||
[ValueName("kMandarin")]
|
||||
public string MandarinReading { get { return unihanCharacterData?.MandarinReading; } }
|
||||
[ValueName("kCantonese")]
|
||||
public string CantoneseReading { get { return unihanCharacterData?.CantoneseReading; } }
|
||||
[ValueName("kJapaneseKun")]
|
||||
public string JapaneseKunReading { get { return unihanCharacterData?.JapaneseKunReading; } }
|
||||
[ValueName("kJapaneseOn")]
|
||||
public string JapaneseOnReading { get { return unihanCharacterData?.JapaneseOnReading; } }
|
||||
[ValueName("kKorean")]
|
||||
public string KoreanReading { get { return unihanCharacterData?.KoreanReading; } }
|
||||
[ValueName("kHangul")]
|
||||
public string HangulReading { get { return unihanCharacterData?.HangulReading; } }
|
||||
[ValueName("kVietnamese")]
|
||||
public string VietnameseReading { get { return unihanCharacterData?.VietnameseReading; } }
|
||||
|
||||
[ValueName("kSimplifiedVariant")]
|
||||
public string SimplifiedVariant { get { return unihanCharacterData?.SimplifiedVariant; } }
|
||||
[ValueName("kTraditionalVariant")]
|
||||
public string TraditionalVariant { get { return unihanCharacterData?.TraditionalVariant; } }
|
||||
|
||||
internal UnicodeCharInfo(int codePoint, UnicodeCharacterData unicodeCharacterData, UnihanCharacterData unihanCharacterData, string block)
|
||||
{
|
||||
this.codePoint = codePoint;
|
||||
this.name = UnicodeInfo.GetName(codePoint, unicodeCharacterData);
|
||||
this.unicodeCharacterData = unicodeCharacterData;
|
||||
this.unihanCharacterData = unihanCharacterData;
|
||||
this.block = block;
|
||||
|
||||
@@ -9,8 +9,9 @@ namespace System.Unicode
|
||||
{
|
||||
internal sealed class UnicodeCharacterData
|
||||
{
|
||||
public readonly UnicodeCharacterRange CodePointRange;
|
||||
public readonly UnicodeCodePointRange CodePointRange;
|
||||
public readonly string Name;
|
||||
public readonly UnicodeNameAlias[] NameAliases;
|
||||
public readonly UnicodeCategory Category;
|
||||
public readonly CanonicalCombiningClass CanonicalCombiningClass;
|
||||
public readonly BidirectionalClass BidirectionalClass;
|
||||
@@ -26,31 +27,33 @@ namespace System.Unicode
|
||||
public readonly ContributoryProperties ContributoryProperties;
|
||||
public readonly CoreProperties CoreProperties;
|
||||
|
||||
public readonly int[] RelatedCodePoints; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
|
||||
public readonly int[] CrossRerefences; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
|
||||
|
||||
internal UnicodeCharacterData
|
||||
(
|
||||
UnicodeCharacterRange codePointRange,
|
||||
UnicodeCodePointRange codePointRange,
|
||||
string name,
|
||||
UnicodeNameAlias[] nameAliases,
|
||||
UnicodeCategory category,
|
||||
CanonicalCombiningClass canonicalCombiningClass,
|
||||
BidirectionalClass bidirectionalClass,
|
||||
CompatibilityFormattingTag decompositionType,
|
||||
string decompositionMapping,
|
||||
string decompositionMapping,
|
||||
UnicodeNumericType numericType,
|
||||
UnicodeRationalNumber numericValue,
|
||||
bool bidirectionalMirrored,
|
||||
string oldName,
|
||||
string simpleUpperCaseMapping,
|
||||
string simpleUpperCaseMapping,
|
||||
string simpleLowerCaseMapping,
|
||||
string simpleTitleCaseMapping,
|
||||
ContributoryProperties contributoryProperties,
|
||||
CoreProperties coreProperties,
|
||||
int[] relatedCodePoints
|
||||
int[] crossRerefences
|
||||
)
|
||||
{
|
||||
this.CodePointRange = codePointRange;
|
||||
this.Name = name;
|
||||
this.NameAliases = nameAliases;
|
||||
this.Category = category;
|
||||
this.CanonicalCombiningClass = canonicalCombiningClass;
|
||||
this.BidirectionalClass = bidirectionalClass;
|
||||
@@ -65,8 +68,8 @@ namespace System.Unicode
|
||||
this.SimpleTitleCaseMapping = simpleTitleCaseMapping;
|
||||
this.ContributoryProperties = contributoryProperties;
|
||||
this.CoreProperties = coreProperties;
|
||||
this.RelatedCodePoints = relatedCodePoints;
|
||||
}
|
||||
this.CrossRerefences = crossRerefences;
|
||||
}
|
||||
|
||||
public UnicodeRationalNumber? NumericValue { get { return NumericType != UnicodeNumericType.None ? numericValue : null as UnicodeRationalNumber?; } }
|
||||
}
|
||||
|
||||
+10
-10
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeCharacterRange : IEnumerable<int>
|
||||
public struct UnicodeCodePointRange : IEnumerable<int>
|
||||
{
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
@@ -39,20 +39,20 @@ namespace System.Unicode
|
||||
|
||||
public bool IsSingleCodePoint { get { return FirstCodePoint == LastCodePoint; } }
|
||||
|
||||
public UnicodeCharacterRange(int codePoint)
|
||||
public UnicodeCodePointRange(int codePoint)
|
||||
{
|
||||
if (codePoint < 0 || codePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("codePoint");
|
||||
if (codePoint < 0 || codePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(codePoint));
|
||||
|
||||
FirstCodePoint = codePoint;
|
||||
LastCodePoint = codePoint;
|
||||
}
|
||||
|
||||
public UnicodeCharacterRange(int firstCodePoint, int lastCodePoint)
|
||||
public UnicodeCodePointRange(int firstCodePoint, int lastCodePoint)
|
||||
{
|
||||
if (firstCodePoint < 0 || firstCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("firstCodePoint");
|
||||
if (lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("lastCodePoint");
|
||||
if (firstCodePoint < 0 || firstCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(firstCodePoint));
|
||||
if (lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(lastCodePoint));
|
||||
|
||||
FirstCodePoint = firstCodePoint;
|
||||
FirstCodePoint = firstCodePoint;
|
||||
LastCodePoint = lastCodePoint;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace System.Unicode
|
||||
return FirstCodePoint == LastCodePoint ? FirstCodePoint.ToString("X4") : FirstCodePoint.ToString("X4") + ".." + LastCodePoint.ToString("X4");
|
||||
}
|
||||
|
||||
public static UnicodeCharacterRange Parse(string s)
|
||||
public static UnicodeCodePointRange Parse(string s)
|
||||
{
|
||||
int start, end;
|
||||
|
||||
@@ -86,9 +86,9 @@ namespace System.Unicode
|
||||
{
|
||||
start = int.Parse(s.Substring(0, rangeSeparatorOffset), NumberStyles.HexNumber);
|
||||
end = int.Parse(s.Substring(rangeSeparatorOffset + 2), NumberStyles.HexNumber);
|
||||
}
|
||||
}
|
||||
|
||||
return new UnicodeCharacterRange(start, end);
|
||||
return new UnicodeCodePointRange(start, end);
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() { return new Enumerator(FirstCodePoint, LastCodePoint); }
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeCrossReferenceCollection : IList<int>
|
||||
{
|
||||
private static int[] EmptyArray = new int[0];
|
||||
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private readonly int[] items;
|
||||
private int index;
|
||||
|
||||
internal Enumerator(int[] items)
|
||||
{
|
||||
this.items = items;
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public int Current { get { return items[index]; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
|
||||
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
|
||||
|
||||
void IEnumerator.Reset() { this.index = -1; }
|
||||
}
|
||||
|
||||
private readonly int[] items;
|
||||
|
||||
public UnicodeCrossReferenceCollection() { items = EmptyArray; }
|
||||
internal UnicodeCrossReferenceCollection(int[] items) { this.items = items ?? EmptyArray; }
|
||||
|
||||
public int this[int index] { get { return items[index]; } }
|
||||
|
||||
int IList<int>.this[int index]
|
||||
{
|
||||
get { return items[index]; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public int Count { get { return items.Length; } }
|
||||
|
||||
bool ICollection<int>.IsReadOnly { get { return true; } }
|
||||
|
||||
public void Add(int item) { throw new NotSupportedException(); }
|
||||
public void Insert(int index, int item) { throw new NotSupportedException(); }
|
||||
|
||||
public bool Remove(int item) { throw new NotSupportedException(); }
|
||||
public void RemoveAt(int index) { throw new NotSupportedException(); }
|
||||
|
||||
public void Clear() { throw new NotSupportedException(); }
|
||||
|
||||
public int IndexOf(int item) { return Array.IndexOf(items, item); }
|
||||
public bool Contains(int item) { return IndexOf(item) >= 0; }
|
||||
|
||||
public void CopyTo(int[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
|
||||
|
||||
public Enumerator GetEnumerator() { return new Enumerator(items); }
|
||||
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -12,23 +12,29 @@ namespace System.Unicode
|
||||
{
|
||||
public static class UnicodeInfo
|
||||
{
|
||||
public const string DefaultBlock = "No_Block";
|
||||
|
||||
private static readonly Version unicodeVersion;
|
||||
private static readonly UnicodeCharacterData[] unicodeCharacterData;
|
||||
private static readonly UnihanCharacterData[] unihanCharacterData;
|
||||
private static readonly UnicodeBlock[] blocks;
|
||||
private static readonly CjkRadicalData[] radicals;
|
||||
private static readonly int maxContiguousIndex;
|
||||
|
||||
static UnicodeInfo()
|
||||
{
|
||||
using (var stream = new DeflateStream(typeof(UnicodeInfo).GetTypeInfo().Assembly.GetManifestResourceStream("ucd.dat"), CompressionMode.Decompress, false))
|
||||
{
|
||||
ReadFromStream(stream, out unicodeVersion, out unicodeCharacterData, out unihanCharacterData, out blocks);
|
||||
ReadFromStream(stream, out unicodeVersion, out unicodeCharacterData, out unihanCharacterData, out radicals, out blocks, out maxContiguousIndex);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ReadFromStream(Stream stream, out Version unicodeVersion, out UnicodeCharacterData[] unicodeCharacterData, out UnihanCharacterData[] unihanCharacterData, out UnicodeBlock[] blocks)
|
||||
internal static void ReadFromStream(Stream stream, out Version unicodeVersion, out UnicodeCharacterData[] unicodeCharacterData, out UnihanCharacterData[] unihanCharacterData, out CjkRadicalData[] radicals, out UnicodeBlock[] blocks, out int maxContiguousIndex)
|
||||
{
|
||||
using (var reader = new BinaryReader(stream, Encoding.UTF8))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (reader.ReadByte() != 'U'
|
||||
| reader.ReadByte() != 'C'
|
||||
| reader.ReadByte() != 'D')
|
||||
@@ -41,22 +47,43 @@ namespace System.Unicode
|
||||
var fileUnicodeVersion = new Version(reader.ReadUInt16(), reader.ReadByte());
|
||||
|
||||
var unicodeCharacterDataEntries = new UnicodeCharacterData[ReadCodePoint(reader)];
|
||||
byte[] nameBuffer = new byte[128];
|
||||
int mci = 0;
|
||||
|
||||
for (int i = 0; i < unicodeCharacterDataEntries.Length; ++i)
|
||||
for (i = 0; i < unicodeCharacterDataEntries.Length; ++i)
|
||||
{
|
||||
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader);
|
||||
if ((unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer)).CodePointRange.Contains(i)) mci = i;
|
||||
else
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
maxContiguousIndex = mci;
|
||||
|
||||
for (; i < unicodeCharacterDataEntries.Length; ++i)
|
||||
{
|
||||
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer);
|
||||
}
|
||||
|
||||
var blockEntries = new UnicodeBlock[reader.ReadByte()];
|
||||
|
||||
for (int i = 0; i < blockEntries.Length; ++i)
|
||||
for (i = 0; i < blockEntries.Length; ++i)
|
||||
{
|
||||
blockEntries[i] = ReadBlockEntry(reader);
|
||||
}
|
||||
|
||||
var cjkRadicalEntries = new CjkRadicalData[reader.ReadByte()];
|
||||
|
||||
for (i = 0; i < cjkRadicalEntries.Length; ++i)
|
||||
{
|
||||
cjkRadicalEntries[i] = ReadCjkRadicalInfo(reader);
|
||||
}
|
||||
|
||||
var unihanCharacterDataEntries = new UnihanCharacterData[ReadCodePoint(reader)];
|
||||
|
||||
for (int i = 0; i < unihanCharacterDataEntries.Length; ++i)
|
||||
for (i = 0; i < unihanCharacterDataEntries.Length; ++i)
|
||||
{
|
||||
unihanCharacterDataEntries[i] = ReadUnihanCharacterDataEntry(reader);
|
||||
}
|
||||
@@ -64,17 +91,52 @@ namespace System.Unicode
|
||||
unicodeVersion = fileUnicodeVersion;
|
||||
unicodeCharacterData = unicodeCharacterDataEntries;
|
||||
unihanCharacterData = unihanCharacterDataEntries;
|
||||
radicals = cjkRadicalEntries;
|
||||
blocks = blockEntries;
|
||||
}
|
||||
}
|
||||
|
||||
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader)
|
||||
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer)
|
||||
{
|
||||
var fields = (UcdFields)reader.ReadUInt16();
|
||||
|
||||
var codePointRange = (fields & UcdFields.CodePointRange) != 0 ? new UnicodeCharacterRange(ReadCodePoint(reader), ReadCodePoint(reader)) : new UnicodeCharacterRange(ReadCodePoint(reader));
|
||||
var codePointRange = (fields & UcdFields.CodePointRange) != 0 ? new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)) : new UnicodeCodePointRange(ReadCodePoint(reader));
|
||||
|
||||
string name = null;
|
||||
UnicodeNameAlias[] nameAliases = UnicodeNameAlias.EmptyArray;
|
||||
|
||||
// Read all the official names of the character.
|
||||
if ((fields & UcdFields.Name) != 0)
|
||||
{
|
||||
int length = reader.ReadByte();
|
||||
byte @case = (byte)(length & 0xC0);
|
||||
|
||||
if (@case < 0x80) // Handles the case where only the name is present.
|
||||
{
|
||||
length = (length & 0x7F) + 1;
|
||||
if (reader.Read(nameBuffer, 0, length) != length) throw new EndOfStreamException();
|
||||
|
||||
name = Encoding.UTF8.GetString(nameBuffer, 0, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
nameAliases = new UnicodeNameAlias[(length & 0x3F) + 1];
|
||||
|
||||
if ((@case & 0x40) != 0)
|
||||
{
|
||||
length = reader.ReadByte() + 1;
|
||||
if (length > 128) throw new InvalidDataException("Did not expect names longer than 128 bytes.");
|
||||
if (reader.Read(nameBuffer, 0, length) != length) throw new EndOfStreamException();
|
||||
name = Encoding.UTF8.GetString(nameBuffer, 0, length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nameAliases.Length; ++i)
|
||||
{
|
||||
nameAliases[i] = new UnicodeNameAlias(reader.ReadString(), (UnicodeNameAliasKind)(reader.ReadByte()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string name = (fields & UcdFields.Name) != 0 ? reader.ReadString() : null;
|
||||
var category = (fields & UcdFields.Category) != 0 ? (UnicodeCategory)reader.ReadByte() : UnicodeCategory.OtherNotAssigned;
|
||||
var canonicalCombiningClass = (fields & UcdFields.CanonicalCombiningClass) != 0 ? (CanonicalCombiningClass)reader.ReadByte() : CanonicalCombiningClass.NotReordered;
|
||||
var bidirectionalClass = (fields & UcdFields.BidirectionalClass) != 0 ? (BidirectionalClass)reader.ReadByte() : 0;
|
||||
@@ -90,11 +152,19 @@ namespace System.Unicode
|
||||
string simpleTitleCaseMapping = (fields & UcdFields.SimpleTitleCaseMapping) != 0 ? reader.ReadString() : null;
|
||||
ContributoryProperties contributoryProperties = (fields & UcdFields.ContributoryProperties) != 0 ? (ContributoryProperties)reader.ReadInt32() : 0;
|
||||
CoreProperties coreProperties = (fields & UcdFields.CoreProperties) != 0 ? (CoreProperties)ReadInt24(reader) : 0;
|
||||
int[] crossReferences = (fields & UcdFields.CrossRerefences) != 0 ? new int[reader.ReadByte() + 1] : null;
|
||||
|
||||
if (crossReferences != null)
|
||||
{
|
||||
for (int i = 0; i < crossReferences.Length; ++i)
|
||||
crossReferences[i] = ReadCodePoint(reader);
|
||||
}
|
||||
|
||||
return new UnicodeCharacterData
|
||||
(
|
||||
codePointRange,
|
||||
name,
|
||||
nameAliases,
|
||||
category,
|
||||
canonicalCombiningClass,
|
||||
bidirectionalClass,
|
||||
@@ -109,9 +179,9 @@ namespace System.Unicode
|
||||
simpleTitleCaseMapping,
|
||||
contributoryProperties,
|
||||
coreProperties,
|
||||
null
|
||||
crossReferences
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static UnihanCharacterData ReadUnihanCharacterDataEntry(BinaryReader reader)
|
||||
{
|
||||
@@ -124,6 +194,18 @@ namespace System.Unicode
|
||||
reader.ReadInt64() :
|
||||
0;
|
||||
|
||||
UnicodeRadicalStrokeCount[] unicodeRadicalStrokeCounts = (fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0 ?
|
||||
new UnicodeRadicalStrokeCount
|
||||
[
|
||||
(fields & UnihanFields.UnicodeRadicalStrokeCountMore) == UnihanFields.UnicodeRadicalStrokeCountMore ?
|
||||
reader.ReadByte() + 3 :
|
||||
((byte)(fields & UnihanFields.UnicodeRadicalStrokeCountMore) >> 2)
|
||||
] :
|
||||
UnicodeRadicalStrokeCount.EmptyArray;
|
||||
|
||||
for (int i = 0; i < unicodeRadicalStrokeCounts.Length; ++i)
|
||||
unicodeRadicalStrokeCounts[i] = new UnicodeRadicalStrokeCount(reader.ReadByte(), reader.ReadByte());
|
||||
|
||||
string definition = (fields & UnihanFields.Definition) != 0 ? reader.ReadString() : null;
|
||||
string mandarinReading = (fields & UnihanFields.MandarinReading) != 0 ? reader.ReadString() : null;
|
||||
string cantoneseReading = (fields & UnihanFields.CantoneseReading) != 0 ? reader.ReadString() : null;
|
||||
@@ -140,6 +222,7 @@ namespace System.Unicode
|
||||
codePoint,
|
||||
numericType,
|
||||
numericValue,
|
||||
unicodeRadicalStrokeCounts,
|
||||
definition,
|
||||
mandarinReading,
|
||||
cantoneseReading,
|
||||
@@ -153,9 +236,20 @@ namespace System.Unicode
|
||||
);
|
||||
}
|
||||
|
||||
private static CjkRadicalData ReadCjkRadicalInfo(BinaryReader reader)
|
||||
{
|
||||
char tr;
|
||||
char tc;
|
||||
|
||||
tr = (char)reader.ReadUInt16();
|
||||
tc = (char)reader.ReadUInt16();
|
||||
|
||||
return (tr & 0x8000) == 0 ? new CjkRadicalData(tr, tc) : new CjkRadicalData((char)(tr & 0x7FFF), tc, (char)reader.ReadUInt16(), (char)reader.ReadUInt16());
|
||||
}
|
||||
|
||||
private static UnicodeBlock ReadBlockEntry(BinaryReader reader)
|
||||
{
|
||||
return new UnicodeBlock(new UnicodeCharacterRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
|
||||
return new UnicodeBlock(new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
|
||||
}
|
||||
|
||||
private static int ReadInt24(BinaryReader reader)
|
||||
@@ -183,15 +277,31 @@ namespace System.Unicode
|
||||
else
|
||||
{
|
||||
return 0x40A0 + (((((b & 0x1F) << 8) | reader.ReadByte()) << 8) | reader.ReadByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Version UnicodeVersion { get { return unicodeVersion; } }
|
||||
|
||||
private static UnicodeCharacterData FindUnicodeCodePoint(int codePoint)
|
||||
{
|
||||
int minIndex = 0;
|
||||
int maxIndex = unicodeCharacterData.Length - 1;
|
||||
// For the first code points (this includes all of ASCII, and quite a bit more), the index in the table will be the code point itself.
|
||||
if (codePoint <= maxContiguousIndex)
|
||||
{
|
||||
return unicodeCharacterData[codePoint];
|
||||
}
|
||||
else
|
||||
{
|
||||
// For other code points, we will use a classic binary search with adjusted search indexes.
|
||||
return BinarySearchUnicodeCodePoint(codePoint);
|
||||
}
|
||||
}
|
||||
|
||||
private static UnicodeCharacterData BinarySearchUnicodeCodePoint(int codePoint)
|
||||
{
|
||||
// NB: Due to the strictly ordered nature of the table, we know that a code point can never happen after the index which is the code point itself.
|
||||
// This will greatly reduce the range to scan for characters close to maxContiguousIndex, and will have a lesser impact on other characters.
|
||||
int minIndex = maxContiguousIndex + 1;
|
||||
int maxIndex = codePoint < unicodeCharacterData.Length ? codePoint - 1 : unicodeCharacterData.Length - 1;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -212,7 +322,7 @@ namespace System.Unicode
|
||||
int minIndex;
|
||||
int maxIndex;
|
||||
|
||||
if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unicodeCharacterData.Length - 1].CodePoint)
|
||||
if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unihanCharacterData.Length - 1].CodePoint)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -250,42 +360,121 @@ namespace System.Unicode
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static string GetBlockName(int codePoint)
|
||||
/// <summary>Gets the name of the Unicode block containing the character.</summary>
|
||||
/// <remarks>If the character has not been assigned to a block, the value of <see cref="DefaultBlock"/> will be returned.</remarks>
|
||||
/// <param name="codePoint">The Unicode code point whose block should be retrieved.</param>
|
||||
/// <returns>The name of the block the code point was assigned to.</returns>
|
||||
public static string GetBlockName(int codePoint)
|
||||
{
|
||||
int i = FindBlockIndex(codePoint);
|
||||
|
||||
return i >= 0 ? blocks[i].Name : null;
|
||||
}
|
||||
return i >= 0 ? blocks[i].Name : DefaultBlock;
|
||||
}
|
||||
|
||||
/// <summary>Gets Unicode information on the specified code point.</summary>
|
||||
/// <remarks>
|
||||
/// This method will consolidate the data from a few different sources.
|
||||
/// There are more efficient way of retrieving the data for some properties if only one of those is needed at a time:
|
||||
/// <list type="bullet">
|
||||
/// <listheader>
|
||||
/// <term>Property</term>
|
||||
/// <description>Method</description>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>Name</term>
|
||||
/// <description><see cref="GetName(int)"/></description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Category</term>
|
||||
/// <description><see cref="GetCategory(int)"/></description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Block</term>
|
||||
/// <description><see cref="GetBlockName(int)"/></description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <param name="codePoint">The Unicode code point for which the data must be retrieved.</param>
|
||||
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
|
||||
public static UnicodeCharInfo GetCharInfo(int codePoint)
|
||||
{
|
||||
return new UnicodeCharInfo(codePoint, FindUnicodeCodePoint(codePoint), FindUnihanCodePoint(codePoint), GetBlockName(codePoint));
|
||||
}
|
||||
|
||||
/// <summary>Gets the category of the specified code point.</summary>
|
||||
/// <remarks>
|
||||
/// The name referred to is the unicode General_Category property.
|
||||
/// If you only need the category of a character, calling this method is faster than calling <see cref="GetCharInfo(int)"/> and retrieving <see cref="UnicodeCharInfo.Category"/>, because there is less information to lookup.
|
||||
/// </remarks>
|
||||
/// <param name="codePoint">The Unicode code point for which the category must be retrieved.</param>
|
||||
/// <returns>The category of the code point.</returns>
|
||||
public static UnicodeCategory GetCategory(int codePoint)
|
||||
{
|
||||
var charInfo = FindUnicodeCodePoint(codePoint);
|
||||
var charData = FindUnicodeCodePoint(codePoint);
|
||||
|
||||
return charInfo != null ? charInfo.Category : UnicodeCategory.OtherNotAssigned;
|
||||
}
|
||||
return charData != null ? charData.Category : UnicodeCategory.OtherNotAssigned;
|
||||
}
|
||||
|
||||
/// <summary>Gets a display text for the specified code point.</summary>
|
||||
/// <param name="charInfo">The information for the code point.</param>
|
||||
/// <returns>A display text for the code point, which may be the representation of the code point itself.</returns>
|
||||
public static string GetDisplayText(UnicodeCharInfo charInfo)
|
||||
{
|
||||
if (charInfo.CodePoint <= 0x0020) return ((char)(0x2400 + charInfo.CodePoint)).ToString();
|
||||
else if (charInfo.Category == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(charInfo.CodePoint);
|
||||
else return char.ConvertFromUtf32(charInfo.CodePoint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets a display text for the specified code point.</summary>
|
||||
/// <param name="codePoint">The Unicode code point, for which a display text should be returned.</param>
|
||||
/// <returns>A display text for the code point, which may be the representation of the code point itself.</returns>
|
||||
public static string GetDisplayText(int codePoint)
|
||||
{
|
||||
if (codePoint <= 0x0020) return ((char)(0x2400 + codePoint)).ToString();
|
||||
else if (GetCategory(codePoint) == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(codePoint);
|
||||
else return char.ConvertFromUtf32(codePoint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets the name of the specified code point.</summary>
|
||||
/// <remarks>
|
||||
/// The name referred to is the unicode Name property.
|
||||
/// If you only need the name of a character, calling this method is faster than calling <see cref="GetCharInfo(int)"/> and retrieving <see cref="UnicodeCharInfo.Name"/>, because there is less information to lookup.
|
||||
/// </remarks>
|
||||
/// <param name="codePoint">The Unicode code point for which the name must be retrieved.</param>
|
||||
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
|
||||
public static string GetName(int codePoint)
|
||||
{
|
||||
if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint);
|
||||
else return GetName(codePoint, FindUnicodeCodePoint(codePoint));
|
||||
}
|
||||
|
||||
internal static string GetName(int codePoint, UnicodeCharacterData characterData)
|
||||
{
|
||||
if (characterData.CodePointRange.IsSingleCodePoint) return characterData.Name;
|
||||
else if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint);
|
||||
else if (characterData.Name != null) return characterData.Name + "-" + codePoint.ToString("X4");
|
||||
else return null;
|
||||
}
|
||||
|
||||
/// <summary>Returns information for a CJK radical.</summary>
|
||||
/// <param name="radicalIndex">The index of the radical. Must be between 1 and <see cref="CjkRadicalCount"/>.</param>
|
||||
/// <returns>Information on the specified radical.</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">The <paramref name="radicalIndex"/> parameter is out of range.</exception>
|
||||
public static CjkRadicalInfo GetCjkRadicalInfo(int radicalIndex)
|
||||
{
|
||||
return new CjkRadicalInfo(checked((byte)radicalIndex), radicals[radicalIndex - 1]);
|
||||
}
|
||||
|
||||
/// <summary>Returns the number of CJK radicals in the Unicode data.</summary>
|
||||
/// <remarks>This value will be 214 for the foreseeable future.</remarks>
|
||||
public static int CjkRadicalCount { get { return radicals.Length; } }
|
||||
|
||||
/// <summary>Gets all the blocks defined in the Unicode data.</summary>
|
||||
/// <remarks><see cref="DefaultBlock"/> is not the name of a block, but only a value indicating the abscence of block information for a given code point.</remarks>
|
||||
/// <returns>An array containing an entry for every block defined in the Unicode data.</returns>
|
||||
public static UnicodeBlock[] GetBlocks()
|
||||
{
|
||||
return (UnicodeBlock[])blocks.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{CB722958-A1C4-4121-804B-7D5A671491B1}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
@@ -32,6 +32,8 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@@ -40,6 +42,8 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
@@ -58,13 +62,22 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\AssemblyInfo.Common.cs">
|
||||
<Link>Properties\AssemblyInfo.Common.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="BidirectionalClass.cs" />
|
||||
<Compile Include="CjkRadicalData.cs" />
|
||||
<Compile Include="CjkRadicalInfo.cs" />
|
||||
<Compile Include="CompatibilityFormattingTag.cs" />
|
||||
<Compile Include="ContributoryProperties.cs" />
|
||||
<Compile Include="CanonicalCombiningClass.cs" />
|
||||
<Compile Include="CodePointEnumerable.cs" />
|
||||
<Compile Include="CodePointEnumerator.cs" />
|
||||
<Compile Include="CoreProperties.cs" />
|
||||
<Compile Include="HangulInfo.cs" />
|
||||
<Compile Include="UnicodeCrossReferenceCollection.cs" />
|
||||
<Compile Include="UnicodeRadicalStrokeCountCollection.cs" />
|
||||
<Compile Include="UnicodeNameAliasCollection.cs" />
|
||||
<Compile Include="UcdFields.cs" />
|
||||
<Compile Include="EnumHelper.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
@@ -73,9 +86,12 @@
|
||||
<Compile Include="UnicodeCategoryExtensions.cs" />
|
||||
<Compile Include="UnicodeCategoryInfo.cs" />
|
||||
<Compile Include="UnicodeCharacterData.cs" />
|
||||
<Compile Include="UnicodeCharacterRange.cs" />
|
||||
<Compile Include="UnicodeCodePointRange.cs" />
|
||||
<Compile Include="UnicodeCharInfo.cs" />
|
||||
<Compile Include="UnicodeInfo.cs" />
|
||||
<Compile Include="UnicodeNameAlias.cs" />
|
||||
<Compile Include="UnicodeNameAliasKind.cs" />
|
||||
<Compile Include="UnicodeRadicalStrokeCount.cs" />
|
||||
<Compile Include="UnihanNumericType.cs" />
|
||||
<Compile Include="UnicodeNumericType.cs" />
|
||||
<Compile Include="UnihanCharacterData.cs" />
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>$version$</version>
|
||||
<title>$title$</title>
|
||||
<authors>$author$</authors>
|
||||
<owners>$author$</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>https://github.com/GoldenCrystal/NetUnicodeInfo</projectUrl>
|
||||
<iconUrl>https://raw.githubusercontent.com/GoldenCrystal/NetUnicodeInfo/master/UnicodeCharacterInspector/UnicodeCharacterInspector.ico</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>$description$</description>
|
||||
<releaseNotes></releaseNotes>
|
||||
<copyright>Copyright 2014</copyright>
|
||||
<tags>Unicode Unihan .NET C# String Text Char Character CodePoint Code Point</tags>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeNameAlias
|
||||
{
|
||||
internal static readonly UnicodeNameAlias[] EmptyArray = new UnicodeNameAlias[0];
|
||||
|
||||
public string Name { get; }
|
||||
public UnicodeNameAliasKind Kind { get; }
|
||||
|
||||
internal UnicodeNameAlias(string name, UnicodeNameAliasKind kind)
|
||||
{
|
||||
Name = name;
|
||||
Kind = kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeNameAliasCollection : IList<UnicodeNameAlias>
|
||||
{
|
||||
public struct Enumerator : IEnumerator<UnicodeNameAlias>
|
||||
{
|
||||
private readonly UnicodeNameAlias[] items;
|
||||
private int index;
|
||||
|
||||
internal Enumerator(UnicodeNameAlias[] items)
|
||||
{
|
||||
this.items = items;
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public UnicodeNameAlias Current { get { return items[index]; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
|
||||
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
|
||||
|
||||
void IEnumerator.Reset() { this.index = -1; }
|
||||
}
|
||||
|
||||
private readonly UnicodeNameAlias[] items;
|
||||
|
||||
public UnicodeNameAliasCollection() { items = UnicodeNameAlias.EmptyArray; }
|
||||
internal UnicodeNameAliasCollection(UnicodeNameAlias[] items) { this.items = items ?? UnicodeNameAlias.EmptyArray; }
|
||||
|
||||
public UnicodeNameAlias this[int index] { get { return items[index]; } }
|
||||
|
||||
UnicodeNameAlias IList<UnicodeNameAlias>.this[int index]
|
||||
{
|
||||
get { return items[index]; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public int Count { get { return items.Length; } }
|
||||
|
||||
bool ICollection<UnicodeNameAlias>.IsReadOnly { get { return true; } }
|
||||
|
||||
public void Add(UnicodeNameAlias item) { throw new NotSupportedException(); }
|
||||
public void Insert(int index, UnicodeNameAlias item) { throw new NotSupportedException(); }
|
||||
|
||||
public bool Remove(UnicodeNameAlias item) { throw new NotSupportedException(); }
|
||||
public void RemoveAt(int index) { throw new NotSupportedException(); }
|
||||
|
||||
public void Clear() { throw new NotSupportedException(); }
|
||||
|
||||
public int IndexOf(UnicodeNameAlias item) { return Array.IndexOf(items, item); }
|
||||
public bool Contains(UnicodeNameAlias item) { return IndexOf(item) >= 0; }
|
||||
|
||||
public void CopyTo(UnicodeNameAlias[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
|
||||
|
||||
public Enumerator GetEnumerator() { return new Enumerator(items); }
|
||||
|
||||
IEnumerator<UnicodeNameAlias> IEnumerable<UnicodeNameAlias>.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace System.Unicode
|
||||
{
|
||||
public enum UnicodeNameAliasKind : byte
|
||||
{
|
||||
[ValueName("correction")]
|
||||
Correction = 1,
|
||||
[ValueName("control")]
|
||||
Control = 2,
|
||||
[ValueName("alternate")]
|
||||
Alternate = 3,
|
||||
[ValueName("figment")]
|
||||
Figment = 4,
|
||||
[ValueName("abbreviation")]
|
||||
Abbreviation = 5
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeRadicalStrokeCount
|
||||
{
|
||||
internal static readonly UnicodeRadicalStrokeCount[] EmptyArray = new UnicodeRadicalStrokeCount[0];
|
||||
|
||||
private readonly byte radical;
|
||||
private readonly byte strokeCount;
|
||||
|
||||
internal UnicodeRadicalStrokeCount(byte rawRadical, byte rawStrokeCount)
|
||||
{
|
||||
radical = rawRadical;
|
||||
strokeCount = rawStrokeCount;
|
||||
}
|
||||
|
||||
internal UnicodeRadicalStrokeCount(byte radical, byte strokeCount, bool isSimplified)
|
||||
{
|
||||
this.radical = radical;
|
||||
if (isSimplified) strokeCount |= 0x80;
|
||||
this.strokeCount = strokeCount;
|
||||
}
|
||||
|
||||
public byte Radical { get { return radical; } }
|
||||
public byte StrokeCount { get { return (byte)(strokeCount & 0x7F); } }
|
||||
public bool IsSimplified { get { return (strokeCount & 0x80) != 0; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeRadicalStrokeCountCollection : IList<UnicodeRadicalStrokeCount>
|
||||
{
|
||||
public struct Enumerator : IEnumerator<UnicodeRadicalStrokeCount>
|
||||
{
|
||||
private readonly UnicodeRadicalStrokeCount[] items;
|
||||
private int index;
|
||||
|
||||
internal Enumerator(UnicodeRadicalStrokeCount[] items)
|
||||
{
|
||||
this.items = items;
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public UnicodeRadicalStrokeCount Current { get { return items[index]; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
|
||||
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
|
||||
|
||||
void IEnumerator.Reset() { this.index = -1; }
|
||||
}
|
||||
|
||||
private readonly UnicodeRadicalStrokeCount[] items;
|
||||
|
||||
public UnicodeRadicalStrokeCountCollection() { items = UnicodeRadicalStrokeCount.EmptyArray; }
|
||||
internal UnicodeRadicalStrokeCountCollection(UnicodeRadicalStrokeCount[] items) { this.items = items ?? UnicodeRadicalStrokeCount.EmptyArray; }
|
||||
|
||||
public UnicodeRadicalStrokeCount this[int index] { get { return items[index]; } }
|
||||
|
||||
UnicodeRadicalStrokeCount IList<UnicodeRadicalStrokeCount>.this[int index]
|
||||
{
|
||||
get { return items[index]; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public int Count { get { return items.Length; } }
|
||||
|
||||
bool ICollection<UnicodeRadicalStrokeCount>.IsReadOnly { get { return true; } }
|
||||
|
||||
public void Add(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
|
||||
public void Insert(int index, UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
|
||||
|
||||
public bool Remove(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
|
||||
public void RemoveAt(int index) { throw new NotSupportedException(); }
|
||||
|
||||
public void Clear() { throw new NotSupportedException(); }
|
||||
|
||||
public int IndexOf(UnicodeRadicalStrokeCount item) { return Array.IndexOf(items, item); }
|
||||
public bool Contains(UnicodeRadicalStrokeCount item) { return IndexOf(item) >= 0; }
|
||||
|
||||
public void CopyTo(UnicodeRadicalStrokeCount[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
|
||||
|
||||
public Enumerator GetEnumerator() { return new Enumerator(items); }
|
||||
|
||||
IEnumerator<UnicodeRadicalStrokeCount> IEnumerable<UnicodeRadicalStrokeCount>.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace System.Unicode
|
||||
{
|
||||
public static UnicodeRationalNumber Parse(string s)
|
||||
{
|
||||
if (s == null) throw new ArgumentNullException("s");
|
||||
if (s == null) throw new ArgumentNullException(nameof(s));
|
||||
if (s.Length == 0) throw new ArgumentException();
|
||||
|
||||
int fractionBarIndex = s.IndexOf('/');
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace System.Unicode
|
||||
public readonly int CodePoint;
|
||||
public readonly UnihanNumericType NumericType;
|
||||
public readonly long NumericValue;
|
||||
public readonly UnicodeRadicalStrokeCount[] UnicodeRadicalStrokeCounts;
|
||||
public readonly string Definition;
|
||||
public readonly string MandarinReading;
|
||||
public readonly string CantoneseReading;
|
||||
@@ -27,6 +28,7 @@ namespace System.Unicode
|
||||
int codePoint,
|
||||
UnihanNumericType numericType,
|
||||
long numericValue,
|
||||
UnicodeRadicalStrokeCount[] unicodeRadicalStrokeCounts,
|
||||
string definition,
|
||||
string mandarinReading,
|
||||
string cantoneseReading,
|
||||
@@ -42,6 +44,7 @@ namespace System.Unicode
|
||||
CodePoint = codePoint;
|
||||
NumericType = numericType;
|
||||
NumericValue = numericValue;
|
||||
UnicodeRadicalStrokeCounts = unicodeRadicalStrokeCounts;
|
||||
Definition = definition;
|
||||
MandarinReading = mandarinReading;
|
||||
CantoneseReading = cantoneseReading;
|
||||
@@ -66,10 +69,10 @@ namespace System.Unicode
|
||||
if (codePoint < 0x2F800) return codePoint - 0x19400;
|
||||
else if (codePoint < 0x30000) return codePoint - 0x10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException("codePoint");
|
||||
}
|
||||
throw new ArgumentOutOfRangeException(nameof(codePoint));
|
||||
}
|
||||
|
||||
internal static int UnpackCodePoint(int packedCodePoint)
|
||||
{
|
||||
@@ -81,7 +84,7 @@ namespace System.Unicode
|
||||
else if (packedCodePoint < 0x1F800) return packedCodePoint - 0xFD00;
|
||||
else if (packedCodePoint < 0x20000) return packedCodePoint + 0x10000;
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("packedCodePoint");
|
||||
throw new ArgumentOutOfRangeException(nameof(packedCodePoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,21 @@ namespace System.Unicode
|
||||
AccountingNumeric = 2,
|
||||
OtherNumeric = 3,
|
||||
|
||||
Definition = 4,
|
||||
MandarinReading = 8,
|
||||
CantoneseReading = 16,
|
||||
JapaneseKunReading = 32,
|
||||
JapaneseOnReading = 64,
|
||||
KoreanReading = 128,
|
||||
HangulReading = 256,
|
||||
VietnameseReading = 512,
|
||||
// UnicodeRadicalStroke : Not exactly a bit mask…
|
||||
UnicodeRadicalStrokeCount = 4, // Will indicate exactly one value for Unicode_Radical_Stroke.
|
||||
UnicodeRadicalStrokeCountTwice = 8, // Will indicate exactly two values for Unicode_Radical_Stroke.
|
||||
UnicodeRadicalStrokeCountMore = 12, // Will indicate three or more values for Unicode_Radical_Stroke. This combination should never happen in the current files.
|
||||
|
||||
SimplifiedVariant = 1024,
|
||||
TraditionalVariant = 2048,
|
||||
Definition = 16,
|
||||
MandarinReading = 32,
|
||||
CantoneseReading = 64,
|
||||
JapaneseKunReading = 128,
|
||||
JapaneseOnReading = 256,
|
||||
KoreanReading = 512,
|
||||
HangulReading = 1024,
|
||||
VietnameseReading = 2048,
|
||||
|
||||
SimplifiedVariant = 4096,
|
||||
TraditionalVariant = 8192,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
|
||||
public sealed class ValueNameAttribute : Attribute
|
||||
{
|
||||
private readonly string name;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Reference in New Issue
Block a user